Reputation: 1
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
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