Hi,
I have an xbase DSL and run into troubles when trying to use a custom class loader in combination with the CompilationTestHelper.
I managed to reproduce the issue on a minimalistic project:
grammar com.septentrio.infrastructure.juggle.Juggle with org.eclipse.xtext.xbase.annotations.XbaseWithAnnotations
generate juggle "http://www.septentrio.com/infrastructure/juggle/Juggle"
import "http://www.eclipse.org/xtext/common/JavaVMTypes" as types
import "http://www.eclipse.org/xtext/xbase/Xbase" as xbase
Model:
package=Package?
importSection=XImportSection?
variables+=Variable*;
Package:
'package' name=QualifiedName;
Variable:
'variable' type=JvmTypeReference name=ID;
The test uses Janino to compile the "Doer" class on-the-fly and inject the resulting classloader into the instance of CompilationTestHelper:
class JuggleGeneratorTest {
private Logger logger = LoggerFactory.getLogger(JuggleGeneratorTest)
private Server server
@Inject private Provider<CompilationTestHelper> compilationTestHelperProvider
@Test def void testGeneratedCode() {
val clazz = '''
package com.example;
public class Doer {
public void doSomething() {}
}
'''.load('com.example.Doer')
Thread.currentThread.contextClassLoader = clazz.classLoader
'''
package mypackage
import com.example.Doer
variable Doer doer
'''
.compile(clazz.classLoader)[
System.out.println(generatedCode)
]
}
private def compile(CharSequence string, ClassLoader cl, IAcceptor<Result> result) {
val cth = compilationTestHelperProvider.get
cth.javaCompilerClassPath = cl
cth.compile(string, result)
}
private def load(CharSequence string, String className) {
val compiler = new SimpleCompiler
compiler.cook(null, new ByteArrayInputStream(string.toString.getBytes))
compiler.classLoader.loadClass(className)
}
}
The inferrer is minimal:
class JuggleJvmModelInferrer extends AbstractModelInferrer {
@Inject extension JvmTypesBuilder
def dispatch void infer(Model model, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(model.toClass(model.getJavaClassName)) [
for(variable: model.variables) {
members += variable.toField(variable.name, variable.type)
}
]
}
def getJavaClassName(Model it) {
getPackageName+'.'+eResource.URI.trimFileExtension.lastSegment
}
def getPackageName(Model it) {
eResource.allContents.filter(Package).head.name
}
}
The resulting java code seems to not be able to resolve the "com.example.Doer" class:
public class MyFile {
private /* Doer */Object doer;
}
}
If the "Doer" class is defined as a regular java file, instead of being compiled on-the-fly, everything is OK.
Are there any restriction on the type of class loader I can use?
Is this the right way to use a custom class loader?