[generator] Created easier mechanism for importing types in Java files

Signed-off-by: Miro Spönemann <miro.spoenemann@itemis.de>
This commit is contained in:
Miro Spönemann 2015-07-03 15:53:01 +02:00
parent ba1ee21786
commit 36e2a8fd4c
9 changed files with 201 additions and 139 deletions

View file

@ -10,6 +10,7 @@ package org.eclipse.xtext.xtext.generator
import com.google.inject.Singleton
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtext.Grammar
import org.eclipse.xtext.xtext.generator.model.TypeReference
import static org.eclipse.xtext.GrammarUtil.*
@ -19,36 +20,28 @@ class XtextGeneratorNaming {
@Accessors(PUBLIC_SETTER)
String eclipsePluginActivator
def getPackage(String qualifiedName) {
qualifiedName.substring(0, qualifiedName.lastIndexOf('.'))
}
def getSimple(String qualifiedName) {
qualifiedName.substring(qualifiedName.lastIndexOf('.'))
}
def getRuntimeBasePackage(Grammar grammar) {
getNamespace(grammar)
}
def getRuntimeModule(Grammar grammar) {
grammar.runtimeBasePackage + '.' + getName(grammar) + 'RuntimeModule'
new TypeReference(grammar.runtimeBasePackage, getName(grammar) + 'RuntimeModule')
}
def getRuntimeGenModule(Grammar grammar) {
grammar.runtimeBasePackage + '.Abstract' + getName(grammar) + 'RuntimeModule'
new TypeReference(grammar.runtimeBasePackage, 'Abstract' + getName(grammar) + 'RuntimeModule')
}
def getRuntimeDefaultModule(Grammar grammar) {
'org.eclipse.xtext.service.DefaultRuntimeModule'
new TypeReference('org.eclipse.xtext.service.DefaultRuntimeModule')
}
def getRuntimeSetup(Grammar grammar) {
grammar.runtimeBasePackage + '.' + getName(grammar) + 'StandaloneSetup'
new TypeReference(grammar.runtimeBasePackage, getName(grammar) + 'StandaloneSetup')
}
def getRuntimeGenSetup(Grammar grammar) {
grammar.runtimeBasePackage + '.' + getName(grammar) + 'StandaloneSetupGenerated'
new TypeReference(grammar.runtimeBasePackage, getName(grammar) + 'StandaloneSetupGenerated')
}
def getEclipsePluginBasePackage(Grammar grammar) {
@ -56,26 +49,26 @@ class XtextGeneratorNaming {
}
def getEclipsePluginModule(Grammar grammar) {
grammar.eclipsePluginBasePackage + '.' + getName(grammar) + 'UiModule'
new TypeReference(grammar.eclipsePluginBasePackage, getName(grammar) + 'UiModule')
}
def getEclipsePluginGenModule(Grammar grammar) {
grammar.eclipsePluginBasePackage + '.' + 'Abstract' + getName(grammar) + 'UiModule'
new TypeReference(grammar.eclipsePluginBasePackage, 'Abstract' + getName(grammar) + 'UiModule')
}
def getEclipsePluginDefaultModule(Grammar grammar) {
'org.eclipse.xtext.ui.DefaultUiModule'
new TypeReference('org.eclipse.xtext.ui.DefaultUiModule')
}
def getEclipsePluginExecutableExtensionFactory(Grammar grammar) {
grammar.eclipsePluginBasePackage + '.' + getName(grammar) + 'ExecutableExtensionFactory'
new TypeReference(grammar.eclipsePluginBasePackage, getName(grammar) + 'ExecutableExtensionFactory')
}
def getEclipsePluginActivator(Grammar grammar) {
if (eclipsePluginActivator === null) {
eclipsePluginActivator = grammar.eclipsePluginBasePackage + '.internal.' + getName(grammar) + 'Activator'
}
return eclipsePluginActivator
return new TypeReference(eclipsePluginActivator)
}
}

View file

@ -7,8 +7,19 @@
*******************************************************************************/
package org.eclipse.xtext.xtext.generator
import com.google.inject.Binder
import com.google.inject.Guice
import com.google.inject.Inject
import com.google.inject.Injector
import com.google.inject.Provider
import com.google.inject.Singleton
import com.google.inject.name.Names
import org.eclipse.xtext.Constants
import org.eclipse.xtext.ISetup
import org.eclipse.xtext.ISetupExtension
import org.eclipse.xtext.XtextPackage
import org.eclipse.xtext.resource.impl.BinaryGrammarResourceFactoryImpl
import org.eclipse.xtext.service.SingletonBinding
import org.eclipse.xtext.xtext.generator.model.CodeConfig
import org.eclipse.xtext.xtext.generator.model.GuiceModuleAccess
import org.eclipse.xtext.xtext.generator.model.JavaFileAccess
@ -23,7 +34,7 @@ class XtextGeneratorTemplates {
def TextFileAccess startPluginXml(TextFileAccess file) {
file.path = 'plugin.xml'
file.codeFragments += '''
file.content = '''
<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.0"?>
@ -33,7 +44,7 @@ class XtextGeneratorTemplates {
}
def TextFileAccess finishPluginXml(TextFileAccess file) {
file.codeFragments += '''
file.content = '''
</plugin>
'''
return file
@ -42,18 +53,17 @@ class XtextGeneratorTemplates {
def JavaFileAccess getRuntimeSetup(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val javaFile = new JavaFileAccess(g.runtimeSetup, codeConfig)
val runtimeSetupImpl = javaFile.imported(g.runtimeGenSetup)
javaFile.typeComment = '''
/**
* Initialization support for running Xtext languages without Equinox extension registry.
*/
'''
javaFile.codeFragments += '''
public class «g.runtimeSetup.simple» extends «runtimeSetupImpl»{
javaFile.javaContent = '''
public class «g.runtimeSetup.simpleName» extends «g.runtimeGenSetup»{
public static void doSetup() {
new «g.runtimeSetup.simple»().createInjectorAndDoEMFRegistration();
new «g.runtimeSetup.simpleName»().createInjectorAndDoEMFRegistration();
}
}
@ -64,62 +74,52 @@ class XtextGeneratorTemplates {
def JavaFileAccess startRuntimeGenSetup(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val javaFile = new JavaFileAccess(g.runtimeGenSetup, codeConfig)
javaFile.imported('org.eclipse.emf.ecore.EPackage')
javaFile.imported('org.eclipse.emf.ecore.resource.Resource')
javaFile.imported('org.eclipse.xtext.ISetup')
javaFile.imported('org.eclipse.xtext.ISetupExtension')
javaFile.imported('com.google.inject.Guice')
javaFile.imported('com.google.inject.Injector')
javaFile.imported('java.util.List')
javaFile.imported('java.util.Arrays')
val runtimeGuiceModule = javaFile.imported(g.runtimeModule)
val usedRuntimeSetups = g.usedGrammars.map[javaFile.imported(it.runtimeSetup)]
javaFile.codeFragments += '''
public class «g.runtimeGenSetup.simple» implements ISetup, ISetupExtension {
javaFile.javaContent = '''
public class «g.runtimeGenSetup.simpleName» implements «ISetup», «ISetupExtension» {
@Override
public List<String> getFileExtensions() {
return Arrays.asList(«FOR fileExtension : langConfig.fileExtensions SEPARATOR ','»"«fileExtension»"«ENDFOR»);
public «'java.util.List'»<String> getFileExtensions() {
return «'java.util.Arrays'».asList(«FOR fileExtension : langConfig.fileExtensions SEPARATOR ','»"«fileExtension»"«ENDFOR»);
}
@Override
public Injector createInjectorAndDoEMFRegistration() {
«FOR usedSetup : usedRuntimeSetup
«usedSetup».doSetup();
public «Injector» createInjectorAndDoEMFRegistration() {
«FOR usedGrammar : g.usedGrammar
«usedGrammar.runtimeSetup».doSetup();
«ENDFOR»
«IF g.usedGrammars.isEmpty»
// register default ePackages
if (!Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("ecore"))
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"ecore", new org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl());
if (!Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xmi"))
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"xmi", new org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl());
if (!Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xtextbin"))
Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"xtextbin", new org.eclipse.xtext.resource.impl.BinaryGrammarResourceFactoryImpl());
if (!EPackage.Registry.INSTANCE.containsKey(org.eclipse.xtext.XtextPackage.eNS_URI))
EPackage.Registry.INSTANCE.put(org.eclipse.xtext.XtextPackage.eNS_URI, org.eclipse.xtext.XtextPackage.eINSTANCE);
if (!«'org.eclipse.emf.ecore.resource.Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("ecore"))
«'org.eclipse.emf.ecore.resource.Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"ecore", new «'org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl());
if (!«'org.eclipse.emf.ecore.resource.Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xmi"))
«'org.eclipse.emf.ecore.resource.Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"xmi", new «'org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl());
if (!«'org.eclipse.emf.ecore.resource.Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().containsKey("xtextbin"))
«'org.eclipse.emf.ecore.resource.Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
"xtextbin", new «BinaryGrammarResourceFactoryImpl»());
if (!«'org.eclipse.emf.ecore.EPackage'».Registry.INSTANCE.containsKey(«XtextPackage».eNS_URI))
«'org.eclipse.emf.ecore.EPackage'».Registry.INSTANCE.put(«XtextPackage».eNS_URI, «XtextPackage».eINSTANCE);
«ENDIF»
Injector injector = createInjector();
«Injector» injector = createInjector();
register(injector);
return injector;
}
public Injector createInjector() {
return Guice.createInjector(new «runtimeGuiceModule»());
public «Injector» createInjector() {
return «Guice».createInjector(new «g.runtimeModule»());
}
public void register(Injector injector) {
public void register(«Injector» injector) {
'''
javaFile.markedAsGenerated = true
return javaFile
}
def JavaFileAccess finishRuntimeGenSetup(JavaFileAccess javaFile) {
javaFile.codeFragments += '''
javaFile.javaContent = '''
}
}
'''
@ -147,14 +147,13 @@ class XtextGeneratorTemplates {
def JavaFileAccess getRuntimeModule(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val javaFile = new JavaFileAccess(g.runtimeModule, codeConfig)
val runtimeGeneratedModule = javaFile.imported(g.runtimeGenModule)
javaFile.typeComment = '''
/**
* Use this class to register components to be used at runtime / without the Equinox extension registry.
*/
'''
javaFile.codeFragments += '''
public class «g.runtimeModule.simple» extends «runtimeGeneratedModule» {
javaFile.javaContent = '''
public class «g.runtimeModule.simpleName» extends «g.runtimeGenModule» {
}
'''
@ -164,35 +163,30 @@ class XtextGeneratorTemplates {
def GuiceModuleAccess startRuntimeGenModule(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val module = new GuiceModuleAccess(g.runtimeGenModule, codeConfig)
module.imported('java.util.Properties')
module.imported('org.eclipse.xtext.Constants')
module.imported('com.google.inject.Binder')
module.imported('com.google.inject.name.Names')
val runtimeDefaultModule = module.imported(g.runtimeDefaultModule)
module.typeComment = '''
/**
* Manual modifications go to {@link «g.runtimeModule.simple»}.
* Manual modifications go to {@link «g.runtimeModule.simpleName»}.
*/
'''
module.codeFragments += '''
public abstract class «g.runtimeGenModule.simple» extends «runtimeDefaultModule» {
module.javaContent = '''
public abstract class «g.runtimeGenModule.simpleName» extends «g.runtimeDefaultModule» {
protected Properties properties = null;
protected «'java.util.Properties properties = null;
@Override
public void configure(Binder binder) {
public void configure(«Binder» binder) {
properties = tryBindProperties(binder, "«g.name.replaceAll("\\.","/")».properties");
super.configure(binder);
}
public void configureLanguageName(Binder binder) {
binder.bind(String.class).annotatedWith(Names.named(Constants.LANGUAGE_NAME)).toInstance("«g.name»");
public void configureLanguageName(«Binder» binder) {
binder.bind(String.class).annotatedWith(«Names».named(«Constants».LANGUAGE_NAME)).toInstance("«g.name»");
}
public void configureFileExtensions(Binder binder) {
public void configureFileExtensions(«Binder» binder) {
if (properties == null || properties.getProperty(Constants.FILE_EXTENSIONS) == null)
binder.bind(String.class).annotatedWith(Names.named(Constants.FILE_EXTENSIONS)).toInstance("«langConfig.fileExtensions.join(',')»");
binder.bind(String.class).annotatedWith(«Names».named(«Constants».FILE_EXTENSIONS)).toInstance("«langConfig.fileExtensions.join(',')»");
}
'''
module.markedAsGenerated = true
@ -202,16 +196,14 @@ class XtextGeneratorTemplates {
def JavaFileAccess getEclipsePluginModule(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val javaFile = new JavaFileAccess(g.eclipsePluginModule, codeConfig)
val eclipsePluginGenGuiceModule = javaFile.imported(g.eclipsePluginGenModule)
javaFile.imported('org.eclipse.ui.plugin.AbstractUIPlugin')
javaFile.typeComment = '''
/**
* Use this class to register components to be used within the Eclipse IDE.
*/
'''
javaFile.codeFragments += '''
public class «g.eclipsePluginModule.simple» extends «eclipsePluginGenGuiceModule» {
public «g.eclipsePluginModule.simple»(AbstractUIPlugin plugin) {
javaFile.javaContent = '''
public class «g.eclipsePluginModule.simpleName» extends «g.eclipsePluginGenModule» {
public «g.eclipsePluginModule.simpleName»(«'org.eclipse.ui.plugin.AbstractUIPlugin'» plugin) {
super(plugin);
}
}
@ -222,18 +214,16 @@ class XtextGeneratorTemplates {
def GuiceModuleAccess startEclipsePluginGenModule(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val module = new GuiceModuleAccess(g.eclipsePluginGenModule, codeConfig)
module.imported('org.eclipse.ui.plugin.AbstractUIPlugin')
val eclipsePluginDefaultModule = module.imported(g.eclipsePluginDefaultModule)
module.typeComment = '''
/**
* Manual modifications go to {@link «g.eclipsePluginModule.simple»}.
* Manual modifications go to {@link «g.eclipsePluginModule.simpleName»}.
*/
'''
module.codeFragments += '''
public abstract class «g.eclipsePluginGenModule.simple» extends «eclipsePluginDefaultModule» {
module.javaContent = '''
public abstract class «g.eclipsePluginGenModule.simpleName» extends «g.eclipsePluginDefaultModule» {
public «g.eclipsePluginGenModule.simple»(AbstractUIPlugin plugin) {
public «g.eclipsePluginGenModule.simpleName»(«'org.eclipse.ui.plugin.AbstractUIPlugin'» plugin) {
super(plugin);
}
'''
@ -242,26 +232,23 @@ class XtextGeneratorTemplates {
}
def GuiceModuleAccess finishGenModule(GuiceModuleAccess module) {
val binder = module.imported('com.google.inject.Binder')
val provider = module.imported('com.google.inject.Provider')
val singletonBinding = module.imported('org.eclipse.xtext.service.SingletonBinding')
for (it : module.bindings) {
module.codeFragments += '''
module.javaContent = '''
«IF !value.provider && value.statements.isEmpty»
// contributed by «contributedBy»
«IF key.singleton»@«singletonBinding»«IF key.eagerSingleton»(eager=true)«ENDIF»«ENDIF»
public «IF value.expression === null»Class<? extends «module.imported(key.type)»>«ELSE»«module.imported(key.type)»«ENDIF» «bindMethodName»() {
«IF key.singleton»@«SingletonBinding»«IF key.eagerSingleton»(eager=true)«ENDIF»«ENDIF»
public «IF value.expression === null»Class<? extends «key.type»>«ELSE»«key.type»«ENDIF» «bindMethodName»() {
return «IF value.expression !== null»«value.expression»«ELSE»«value.typeName».class«ENDIF»;
}
«ELSEIF value.statements.isEmpty»
// contributed by «contributedBy»
«IF key.singleton»@«singletonBinding»«IF key.eagerSingleton»(eager=true)«ENDIF»«ENDIF»
public «IF value.expression==null»Class<? extends «provider»<«key.type»>>«ELSE»«provider»<«key.type»>«ENDIF» «bindMethodName»() {
«IF key.singleton»@«SingletonBinding»«IF key.eagerSingleton»(eager=true)«ENDIF»«ENDIF»
public «IF value.expression==null»Class<? extends «Provider»<«key.type»>>«ELSE»«Provider»<«key.type»>«ENDIF» «bindMethodName»() {
return «IF value.expression!=null»«value.expression»«ELSE»«value.typeName».class«ENDIF»;
}
«ELSE»
// contributed by «contributedBy»
public void «bindMethodName»(«binder» binder) {
public void «bindMethodName»(«Binder» binder) {
«FOR statement : value.statements»
«statement»«IF !statement.endsWith(';')»;«ENDIF»
«ENDFOR»
@ -269,7 +256,7 @@ class XtextGeneratorTemplates {
«ENDIF»
'''
}
module.codeFragments += '''
module.javaContent = '''
}
'''
return module
@ -278,10 +265,6 @@ class XtextGeneratorTemplates {
def JavaFileAccess getEclipsePluginExecutableExtensionFactory(LanguageConfig2 langConfig) {
val g = langConfig.grammar
val javaFile = new JavaFileAccess(g.eclipsePluginExecutableExtensionFactory, codeConfig)
javaFile.imported('org.osgi.framework.Bundle')
javaFile.imported('com.google.inject.Injector')
val superClass = javaFile.imported('org.eclipse.xtext.ui.guice.AbstractGuiceAwareExecutableExtensionFactory')
val activator = javaFile.imported(g.eclipsePluginActivator)
javaFile.typeComment = '''
/**
@ -289,17 +272,17 @@ class XtextGeneratorTemplates {
* introduced subclass.
*/
'''
javaFile.codeFragments += '''
public class «g.eclipsePluginExecutableExtensionFactory.simple» extends «superClass» {
javaFile.javaContent = '''
public class «g.eclipsePluginExecutableExtensionFactory.simpleName» extends «'org.eclipse.xtext.ui.guice.AbstractGuiceAwareExecutableExtensionFactory'» {
@Override
protected Bundle getBundle() {
return «activator».getInstance().getBundle();
protected «'org.osgi.framework.Bundle getBundle() {
return «g.eclipsePluginActivator».getInstance().getBundle();
}
@Override
protected Injector getInjector() {
return «activator».getInstance().getInjector(«activator».«g.name.toUpperCase.replaceAll('\\.', '_')»);
protected «Injector» getInjector() {
return «g.eclipsePluginActivator».getInstance().getInjector(«g.eclipsePluginActivator».«g.name.toUpperCase.replaceAll('\\.', '_')»);
}
}

View file

@ -65,6 +65,10 @@ class CodeConfig implements IGuiceAwareGeneratorComponent {
override initialize(Injector injector) {
injector.injectMembers(this)
if (lineDelimiter === null)
lineDelimiter = '\n'
var fileHeader = fileHeaderTemplate
if (fileHeader != null) {
if (fileHeader.contains(FILE_HEADER_VAR_TIME)) {
@ -148,7 +152,7 @@ class CodeConfig implements IGuiceAwareGeneratorComponent {
val stringBuilder = new StringBuilder
for (annotation : classAnnotations) {
val importString = annotation.annotationImport
if (!Strings.isEmpty(importString)) {
if (importString !== null) {
stringBuilder.append('import ').append(importString).append(';').append(Strings.newLine)
}
}

View file

@ -58,7 +58,7 @@ class GeneratedClassAnnotation implements IClassAnnotation {
}
override getAnnotationImport() {
return 'javax.annotation.Generated'
return new TypeReference('javax.annotation.Generated')
}
private def void +=(StringBuilder stringBuilder, String s) {

View file

@ -39,8 +39,8 @@ class GuiceModuleAccess extends JavaFileAccess {
@Accessors
val List<Binding> bindings = newArrayList
new(String qualifiedName, CodeConfig codeConfig) {
super(qualifiedName, codeConfig)
new(TypeReference typeRef, CodeConfig codeConfig) {
super(typeRef, codeConfig)
}
}

View file

@ -27,6 +27,6 @@ interface IClassAnnotation {
* Return the qualified name of the annotation interface for use in import declarations,
* or {@code null} if no import is required.
*/
def String getAnnotationImport()
def TypeReference getAnnotationImport()
}

View file

@ -10,12 +10,15 @@ package org.eclipse.xtext.xtext.generator.model
import com.google.common.collect.Lists
import java.util.Collections
import java.util.Map
import java.util.regex.Pattern
import org.eclipse.emf.codegen.util.CodeGenUtil
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend2.lib.StringConcatenation
import org.eclipse.xtend2.lib.StringConcatenationClient
class JavaFileAccess extends TextFileAccess {
val Map<String, String> imports = newHashMap
val Map<String, TypeReference> imports = newHashMap
val String packageName
@ -28,38 +31,42 @@ class JavaFileAccess extends TextFileAccess {
boolean markedAsGenerated
new(String qualifiedName, CodeConfig codeConfig) {
val simpleNameIndex = qualifiedName.lastIndexOf('.')
this.packageName = qualifiedName.substring(0, simpleNameIndex)
val simpleName = qualifiedName.substring(simpleNameIndex + 1)
this.path = packageName.replace('.', '/') + '/' + simpleName + '.java'
this.codeConfig = codeConfig
this(new TypeReference(qualifiedName), codeConfig)
}
def String imported(Class<?> clazz) {
return imported(clazz.name.replace('$', '.'))
new(TypeReference typeRef, CodeConfig codeConfig) {
this.packageName = typeRef.package
if (typeRef.name != packageName + '.' + typeRef.simpleName)
throw new IllegalArgumentException('Nested types cannot be serialized.')
this.path = packageName.replace('.', '/') + '/' + typeRef.simpleName + '.java'
this.codeConfig = codeConfig
}
def String imported(String clazz) {
val simpleNameIndex = clazz.lastIndexOf('.')
val simpleName = clazz.substring(simpleNameIndex + 1)
val packageName = clazz.substring(0, simpleNameIndex)
if (CodeGenUtil.isJavaDefaultType(simpleName) || this.packageName == packageName)
def String importType(TypeReference typeRef) {
val simpleName = typeRef.simpleName
if (CodeGenUtil.isJavaDefaultType(simpleName) || this.packageName == typeRef.package)
return simpleName
val imported = imports.get(simpleName)
if (imported != null) {
if (imported.equals(clazz))
if (imported == typeRef)
return simpleName
else
return clazz
return typeRef.name
}
imports.put(simpleName, clazz)
imports.put(simpleName, typeRef)
return simpleName
}
def void setJavaContent(StringConcatenationClient javaContent) {
val javaStringConcat = new JavaStringConcatenation(this)
javaStringConcat.append(javaContent)
content = javaStringConcat
}
override generate() {
val classAnnotations = codeConfig.classAnnotations.filter[appliesTo(this)]
classAnnotations.forEach[imported(annotationImport)]
val sortedImports = Lists.newArrayList(imports.values())
classAnnotations.forEach[importType(annotationImport)]
val sortedImports = Lists.newArrayList(imports.values.map[name])
Collections.sort(sortedImports)
return '''
«codeConfig.fileHeader»
@ -73,10 +80,32 @@ class JavaFileAccess extends TextFileAccess {
«FOR annot : classAnnotations»
«annot.generate()»
«ENDFOR»
«FOR fragment : codeFragments»
«fragment»
«ENDFOR»
«content»
'''
}
private static class JavaStringConcatenation extends StringConcatenation {
val JavaFileAccess access
val typeNamePattern = Pattern.compile('[a-z]+(\\.[a-z]+)*(\\.[A-Z][a-zA-Z]*)+')
new(JavaFileAccess access) {
super(access.codeConfig.lineDelimiter)
this.access = access
}
override getStringRepresentation(Object object) {
if (object instanceof TypeReference)
access.importType(object)
else if (object instanceof Class<?>)
access.importType(new TypeReference(object as Class<?>))
else if (object instanceof String && typeNamePattern.matcher(object as String).matches)
access.importType(new TypeReference(object as String))
else
object.toString
}
}
}

View file

@ -10,10 +10,8 @@ package org.eclipse.xtext.xtext.generator.model
import com.google.common.io.Files
import java.io.File
import java.nio.charset.Charset
import java.util.List
import org.eclipse.emf.common.util.URI
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtend2.lib.StringConcatenation
import org.eclipse.xtext.generator.IFileSystemAccess2
import org.eclipse.xtext.parser.IEncodingProvider
@ -23,17 +21,13 @@ class TextFileAccess {
String path
@Accessors
val List<CharSequence> codeFragments = newArrayList
CharSequence content
@Accessors
IEncodingProvider encodingProvider
def CharSequence generate() {
val result = new StringConcatenation
for (fragment : codeFragments) {
result.append(fragment)
}
return result
return content
}
def writeTo(IFileSystemAccess2 fileSystemAccess) {

View file

@ -0,0 +1,59 @@
/*******************************************************************************
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*******************************************************************************/
package org.eclipse.xtext.xtext.generator.model
import org.eclipse.xtend.lib.annotations.EqualsHashCode
@EqualsHashCode
class TypeReference {
val String name
new(String name) {
this.name = name
}
new(String packageName, String className) {
this.name = packageName + '.' + className
}
new(Class<?> clazz) {
this.name = clazz.name.replace('$', '.')
}
override toString() {
name
}
def getName() {
name
}
def getSimpleName() {
val simpleNameIndex = name.lastIndexOf('.')
return name.substring(simpleNameIndex + 1)
}
def getPackage() {
var packageEnd = name.length
for (var i = name.length - 1; i >= 0; i--) {
if (name.charAt(i).matches('.')) {
if (Character.isLowerCase(name.charAt(i + 1)))
return name.substring(0, packageEnd)
else
packageEnd = i
}
}
return ''
}
private def matches(char c1, char c2) {
c1 == c2
}
}