Leonid Kositsyn
Leonid Kositsyn

Reputation: 1

SimpleJavaFileObject how to import custom(created by me) package?

I'm first time here so...

The task is in compilation dynamic class(created from string) and subsequent creating instantiation.

The problem is in importation my custom package/classes, placed in different folders, to dynamic class. For example: after import controller.*; an error occurs:

/CompiledClass.java:4: error: package controller does not exist

but standard packages(libraries) have been imported well without any issues and compilation ended the same way.

I've tried to solve via getTask method of JavaCompiler Api by sending optionList with path but without success.

So how to correct import custom package?

Here is my code:

package view;

import controller.*;

import java.io.*;

import java.lang.reflect.Constructor;

import java.lang.reflect.Method;

import java.net.URI;

import java.security.SecureClassLoader;

import java.util.*;

import javax.tools.*;
import javax.tools.JavaCompiler.*;
import javax.tools.JavaFileObject.Kind;

public class CompileJavaManager {

public static void compileJavaFileObject(StringBuilder inputString, Writer jspOut) throws Exception {
    String className = "CompiledClass";
    String classMethod = "methodOf" + className;
    Class compiledClass = null;
    //Class<?> c = Class.forName(className);

    StringBuilder javaFileContents =
        new StringBuilder("" +
            //"package compiled;" +
            '\n' +
            "import java.io.*;\n" +
            "import java.util.*;\n" +
            "import controller.*;\n" +
            '\n' +
            "public class " + className +"{\n" +
            "   private Writer out = null;\n" +
            '\n' +
            "   public " + className +"(Writer out){\n" +
            "       this.out = out;\n" +
            //"       this.container = container;" +
            "   }" +
            "   public void " + classMethod + "() throws java.io.IOException{\n" +
                    //inputString +
            "   }\n" +
            "}\n");

    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    DiagnosticCollector diagnosticsCollector = new DiagnosticCollector();
    StandardJavaFileManager standardJavaFileManager = compiler.getStandardFileManager(diagnosticsCollector, null, null);
    SpecialClassLoader classLoader = new SpecialClassLoader();
    SpecialJavaFileManager fileManager = new SpecialJavaFileManager(standardJavaFileManager, classLoader);           

    List<String> optionList = new ArrayList<String>();
    optionList.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path")));

    JavaObjectFromString javaObjectFromString = new JavaObjectFromString(className, javaFileContents.toString());

    Iterable fileObjects = Arrays.asList(javaObjectFromString);
    Iterable classes = null;           
    Writer out = new PrintWriter(jspOut);

    CompilationTask task = compiler.getTask(out, fileManager, diagnosticsCollector, optionList, classes, fileObjects);
    Boolean result = task.call();
    List<Diagnostic> diagnostics = diagnosticsCollector.getDiagnostics();

    if (result) {
        compiledClass = classLoader.findClass(className);
        Constructor<?> constructor = compiledClass.getConstructor(Writer.class);
        Object instance = constructor.newInstance(jspOut);
        //call the method, pass a null params 
        Method instanceMethod = compiledClass.getDeclaredMethod(classMethod, null);
        instanceMethod.invoke(instance, null);
        //System.out.println(instance);
    } else {
        // Compilation fails
        for (Diagnostic d : diagnostics) {
            System.out.println(d);
        }
    }
}

private static class JavaObjectFromString extends SimpleJavaFileObject {
    private String sourceCode = null;

    public JavaObjectFromString(String className, String sourceCode) throws Exception {
        super(URI.create("file:///" + className + Kind.SOURCE.extension), Kind.SOURCE);
        this.sourceCode = sourceCode;
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
        return sourceCode;
    }

    @Override
    public OutputStream openOutputStream() {       
        throw new IllegalStateException();   
    }

    @Override
    public InputStream openInputStream() {       
        return new ByteArrayInputStream(sourceCode.getBytes());   
    }
}

private static class JavaObjectFromByteCode extends SimpleJavaFileObject {   
    private ByteArrayOutputStream baos;  

    public JavaObjectFromByteCode(String name) {       
        super(URI.create("byte:///" + name + Kind.CLASS.extension), Kind.CLASS);   
    }

    @Override
    public CharSequence getCharContent(boolean ignoreEncodingErrors) {       
        throw new IllegalStateException();   
    }

    @Override
    public OutputStream openOutputStream() {       
        baos = new ByteArrayOutputStream();       
        return baos;   
    }

    @Override
    public InputStream openInputStream() {       
        throw new IllegalStateException();   
    }

    public byte[] getBytes() {       
        return baos.toByteArray();   
    }
}

private static class SpecialClassLoader extends ClassLoader {   
    private Map<String,JavaObjectFromByteCode> m = new HashMap<String, JavaObjectFromByteCode>();

    protected Class<?> findClass(String name) throws ClassNotFoundException {       
        JavaObjectFromByteCode jobc = m.get(name);       
        if (jobc==null){           
            jobc = m.get(name.replace(".","/"));           
            if (jobc==null){               
                return super.findClass(name);           
            }       
        }       
        return defineClass(name, jobc.getBytes(), 0, jobc.getBytes().length);   
    }

    public void addClass(String name, JavaObjectFromByteCode jobc) {       
        m.put(name, jobc);   
    }
}

private static class SpecialJavaFileManager extends ForwardingJavaFileManager {   
    private SpecialClassLoader scl;   

    public SpecialJavaFileManager(StandardJavaFileManager sjfm, SpecialClassLoader scl) {       
        super(sjfm);       
        this.scl = scl;   
    }   

    public JavaFileObject getJavaFileForOutput(Location location, String name, JavaFileObject.Kind kind, FileObject sibling) throws IOException {       
        JavaObjectFromByteCode jobc = new JavaObjectFromByteCode(name);       
        scl.addClass(name, jobc);       
        return jobc;   
    }

    public ClassLoader getClassLoader(Location location) {       
        return scl;   
    }
}

}

Thanks in advance!

Upvotes: 0

Views: 571

Answers (1)

Leonid Kositsyn
Leonid Kositsyn

Reputation: 1

The problem has been solved:

I have added path to my jar controller.jar in addition to System.getProperty("java.class.path").

Here is the code:

optionList.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path") + ";path/to/your/controller.jar"));

Upvotes: 0

Related Questions