开发者

Java Compiler API with classes that depend on each other

I'm using Java Compiler API to compile in-memory classes. That is, classes are compiled to bytecode (no .classes files stored in disk) and then loaded by reconstructing the bytecode.

Sometimes, I need to compile a class that depends on another, also 开发者_StackOverflow中文版in-memory compiled, class. For instance: Compile Class A, then compile Class B which depends on Class A.

To solve this, I pass both Class A and Class B as the compilation units needed by the getTask method of the compiler API.

However, I really don't like this solution, as it makes me recompile Class A which was already compiled.

Is there a way to get around this?

EDIT: I found a solution through this link: http://www.ibm.com/developerworks/java/library/j-jcomp/index.html


Yes, this is totally possible as long as you properly implement the ForwardingJavaFileManager. The two most important methods are inferBinaryName() and list(). If you set these two up properly, the compiler will be able to resolve classes that you've previously compiled.

inferBinaryName() must return the class' simple name (e.g. the inferred binary name for com.test.Test would be just Test). Here is my implementation (my subclass of JavaFileObject is called InAppJavaFileObject):

@Override
public String inferBinaryName(Location location, JavaFileObject javaFileObject) {

    if(location == StandardLocation.CLASS_PATH && javaFileObject instanceof InAppJavaFileObject) {
        return StringUtils.substringBeforeLast(javaFileObject.getName(), ".java");
    }

    return super.inferBinaryName(location, javaFileObject);
}

Note that I'm stripping off ".java" from the end. When constructing a JavaFileObject, the file name must end in ".java", but if you don't strip the suffix later, the compiler won't find your class.

list() is a little bit more complicated because you have to be careful to play along nicely with your delegate file manager. In my implementation, I keep a map of fully-qualified class name to my subclass of JavaFileObject that I can iterate over:

@Override
public Iterable<JavaFileObject> list(Location action, String pkg, Set<JavaFileObject.Kind> kind, boolean recurse) throws IOException {

    Iterable<JavaFileObject> superFiles = super.list(action, pkg, kind, recurse);

    // see if there's anything in our cache that matches the criteria.
    if(action == StandardLocation.CLASS_PATH && (kind.contains(JavaFileObject.Kind.CLASS) || kind.contains(JavaFileObject.Kind.SOURCE))) {

        List<JavaFileObject> ourFiles = new ArrayList<JavaFileObject>();
        for(Map.Entry<String,InAppJavaFileObject> entry : files.entrySet()) {
            String className = entry.getKey();
            if(className.startsWith(pkg) && ("".equals(pkg) || pkg.equals(className.substring(0, className.lastIndexOf('.'))))) {
                ourFiles.add(entry.getValue());
            }
        }

        if(ourFiles.size() > 0) {
            for(JavaFileObject javaFileObject : superFiles) {
                ourFiles.add(javaFileObject);
            }

            return ourFiles;
        }
    }

    // nothing found in our hash map that matches the criteria...  return
    // whatever super came up with.
    return superFiles;
}

Once you have those methods properly implemented, the rest just works. Enjoy!


That leads to the obvious question of why you want to compile class A separately first. Why not just compile everything in one go?


How if you maintain the modified time of the files and the (in-memory) compiled byte code?


I don't think you can avoid compiling both classes. In fact, if you don't compile both of them, there is a chance that you will end up with binary compatibility problems, or problems with incorrect inlined constants.

This is essentially the same problem as you'd get if you compiled one class and not the other from the command line.

But to be honest, I wouldn't worry about trying to optimize the compilation like that. (And if your application needs to be able to dynamically compile one class and not the other, it has probably has significant design issues.)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜