Страницы

Поиск по вопросам

четверг, 9 апреля 2020 г.

SimpleJavaFileObject импорт кастом пакета/классов

#java #classloader

                    
Приветствую!

Задача заключается в компиляции динамического класса(созданного из строкового представления)
и дальнейшем инстанцировании.

Проблема заключается в импортировании моего пакета/классов, хранящихся  в отличных
от стандартных java-директорий (lib), в динамический класс. К примеру: после выполнения
строки import controller.*; возникает ошибка:

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


но стандартные пакеты/классы импортируются без ошибок, и компиляция соответственно
выполняется тоже без ошибок. 

Пробовал решить через getTask метод JavaCompiler Api путем отправки optionList с
параметрами, но в итоге не успешно.

Как правильно импортировать в динамический класс свои пакет/классы?

Мой код:

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 optionList = new ArrayList();
    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 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 m = new HashMap();

    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;   
    }
}


}

Заранее спасибо!
    


Ответы

Ответ 1



Во время компиляции ты указал optionList.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path"))); Это значит, что компилятор во время компиляции видит только jar'ники из стандартной библиотеки. Твой jar'ник с пакетом controller наверняка лежит отдельно. Поэтому надо испльзовать optionList.addAll(Arrays.asList("-classpath", System.getProperty("java.class.path")+";путь/где/лежит/jar/с/пакетом/controller.jar"));

Комментариев нет:

Отправить комментарий