11

I wish to compile source without having the dependencies present on the machine.
Example: File A.java:

import some.pkg.B; 
public class A extends B {...}

I don't have B source present, I wish to hook either JavaFileManager or a custom ClassLoader in order to get the symbols in question (the package 'some.package' and class B) and then use a service I have that retrieves the source string.

The compiling code: (inputFiles has A.java)

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
CustomClassLoader classLoader = new CustomClassLoader();
StandardJavaFileManager standardfileManager = compiler.getStandardFileManager(this, null, null);
JavaFileManager fileManager = new CustomFileManager(standardfileManager, output, classLoader);
CompilationTask task = compiler.getTask(null, fileManager, this, null, null, inputFiles);
boolean result = task.call();

Hooks on JavaFileManager (getFileForInput..) and on my classloader (findClass, loadClass ..) didn't triggered when compiling and I got error messages:

A.java:#: package some.pkg does not exist
A.java:#: cannot find symbol
symbol: class B

EDIT

After playing around with the API, going over JavaCompiler (older version) source and reading Compilation Overview I still can't find an API hook I can use to provide me Symbols from the syntax trees. It seems that the API needs to get all resources based on package names as suggested by kschneid.
One workaround I thought about is running the JavaCompiler and analyze the error messages for missing symbols. That way I will know which symbols are needed, get them and recompile.
Any other workarounds / solutions?

Chen Harel
  • 9,684
  • 5
  • 44
  • 58
  • What JDK version/compiler and platform are you using? – matts May 29 '12 at 15:51
  • JavaCompiler (javac), JDK 1.6.30 x64 on Windows. – Chen Harel May 29 '12 at 16:49
  • I am not completely sure. But, I feel as if what you are trying to do is dynamic class-loading. Can't you user `Class.forname()` to load the class at runtime. Please correct me if I misunderstood. – Ankit Jun 03 '12 at 10:24
  • @Ankit I am trying to compile sources, not load classes – Chen Harel Jun 03 '12 at 10:40
  • 1
    Just wondering: what is the purpose of doing this? Also, I don't know about bytecode very well but I wonder if it would not prevent you from implementing/overriding methods from B (since the compiler won't have their definitions). In the end I am not sure it would be possible to get runnable bytecode like this, even after loading the real B class… – Didier L Jun 04 '12 at 16:00

2 Answers2

4

(I assume that you're not really using a package name of "package" since that would just be illegal...)

Your custom JavaFileManager should be getting its list method invoked. Hopefully this notation makes sense, but the combination of args to that method should look like this:

[PLATFORM_CLASS_PATH, some, [CLASS], false]
[CLASS_PATH, some, [SOURCE, CLASS], false]
[PLATFORM_CLASS_PATH, some.pkg, [CLASS], false]
[CLASS_PATH, some.pkg, [SOURCE, CLASS], false]

I'm not sure how difficult it will be for your specific environment to create the appropriate Iterable<JavaFileObject> instances, but I think that's what would be required...

kschneid
  • 5,626
  • 23
  • 31
  • Thanks for the package note, I've revised the question. – Chen Harel May 30 '12 at 07:35
  • I've missed this function, good call. It is a good path however I don't want to build JavaFileObject to all the classes in the package, just the ones being used in the actual compilation of the Java file I'm trying to compile. Is there a way to get the actual classes names and not just the packages? – Chen Harel May 30 '12 at 07:38
  • 1
    Here is a great implementation for this. http://atamur.blogspot.kr/2009/10/using-built-in-javacompiler-with-custom.html – zeodtr May 15 '15 at 10:26
1

I've found that a nice way to hook in classes at compile time is with Groovy AST Transformation. You can have a look at what can be done here

That's not plain old java though, but it can be an handy tool to know

Grooveek
  • 10,046
  • 1
  • 27
  • 37