getJavaFileForOutput(…) method of custom JavaFileM

2019-05-27 08:42发布

问题:

I have a custom JavaFileManager that looks something like this:

public class InMemoryForwardingFileManager extends ForwardingJavaFileManager<StandardJavaFileManager> {

    private final Map<String, ByteArrayJavaFileObject> javaFileObjects = new HashMap<>();

    @Override
    public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException{

        JavaFileObject fileObject = new ByteArrayJavaFileObject( ... );
        javaFileObjects.put(className, fileObject);

        return fileObject;
    }


    @Override
    public ClassLoader getClassLoader(Location location){

        return new SecureClassLoader(InMemoryForwardingFileManager.class.getClassLoader()){

            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {

                ByteArrayJavaFileObject fileObject = javaFileObjects.get(name);

                if(fileObject != null){
                    byte[] bytes = fileObject.getBytes();
                    return defineClass(name, bytes, 0, bytes.length);
                } else{
                    throw new ClassNotFoundException();
                }

            }

        }

    }
}

I have redacted a lot of code for readability purposes; the class also implements the list(...) method and the inferBinaryName(...) method.

In another area of my project I run something similar to the following:

InMemoryForwardingFileManager fileManager = // get singleton instance

... // declare compilation units, options, diagnostic listener, etc

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
CompilationTask compilerTask = compiler.getTask(null, fileManager, diagnostics, compilationOptions, null, compilationUnits);
compilerTask.call();

// load and instantiate the compiled class
ClassLoader classLoader = fileManager.getClassLoader(null);
MyGeneratedClass instance = (MyGeneratedClass) classLoader.loadClass(fullClassName).newInstance();

If I run some junit tests in eclipse on windows/mac/linux it works exactly as I would expect. If I run my project in glassfish on windows it also works exactly how I would expect. If I run the same project in glassfish on Mac OS X Mavericks or Centos 6.4 the getJavaFileForOutput(...) is simply never called! The getClassLoader(...) method of my file manager is eventually called but by then it is too late.

What is unique about the linux+glassfish environment that is preventing my getJavaFileForOuput method from being called?

I'm pretty sure I have all environments correctly set up to use the same jdk version: jdk1.7.0_45.

Any advice??

回答1:

I'll answer my own question here.

I can't believe this went over my head but it turns out the Windows environment was using glassfish3 whereas the other environments were using glassfish4. Once I discovered this, I tested the project on windows using glassfish4 and I was able to replicate the same issue I experience on mac/linux.

While that vaguely answers my question, if I find out exactly why the above code does not work as expected in glassfish4, I will add an explanation here.