Eclipse's JDT compiler provide an interface INameEnvironment
which defines method findType(...)
enable you to do cascade compilation. Curiously I would like to know if there are any means to do it using standard JDK compiler toolkit?
Note, the scenario is a template engine which do in memory compilation for template file generated classes which have inter-dependencies, and it cannot forecast the order you encountered a template file, thus Foo
might needs to be compiled first before it's parent Bar
compiled already, therefore you need a mechanism to do cascade compilation, meaning during compilation of Foo
you need to generate another source Bar
and compile it first in order to continue Foo
's compilation: some code like the follows:
private NameEnvironmentAnswer findType(final String name) {
try {
if (!name.contains(TemplateClass.CN_SUFFIX)) {
return findStandType(name);
}
char[] fileName = name.toCharArray();
TemplateClass templateClass = classCache.getByClassName(name);
// TemplateClass exists
if (templateClass != null) {
if (templateClass.javaByteCode != null) {
ClassFileReader classFileReader = new ClassFileReader(templateClass.javaByteCode, fileName, true);
return new NameEnvironmentAnswer(classFileReader, null);
}
// Cascade compilation
ICompilationUnit compilationUnit = new CompilationUnit(name);
return new NameEnvironmentAnswer(compilationUnit, null);
}
// So it's a standard class
return findStandType(name);
} catch (ClassFormatException e) {
// Something very very bad
throw new RuntimeException(e);
}
}
Based on our comment conversation, I think the answer is a clear: no, you can't do that with the JDK compiler. It does give you a hook when it requests the package, but not the specific class dependency.
About as close as you can get so far as I know is:
Here's a nice article with code though it needs to be adapted to handle in memory classes. Specifically the issue you're describing is handled by the JavaFileManager.list(...)
method. You have to return back JavaFileObjects here that you have cached in memory. You'll most likely need to create a subclass of ForwardingJavaFileManager
as described in the article--though modified to handle the cached classes you are working with.
You can use that to compile something. If it returns errors, use regex to find out what is missing. After generating/compiling the code for the missing thing, retry compiling the original code.
NOTE: It does ask for the FQN of the dependent class as the packageName argument in ForwardingFileManager.list(...) at some point. I haven't tried to return the class at that point. It might not work because the package would mismatch, but maybe it would.
Try reading through this HelloWorld example to see if it solves your problem. Without posting the code, it's hard to say what your specific issue is.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With