Динамически создавать класс java, компилировать и создавать его экземпляры во время выполнения - PullRequest
1 голос
/ 13 марта 2020

У меня есть String, который мне нужно преобразовать в java класс, скомпилировать и создать экземпляр во время выполнения: предположим, что мой String:

String s = " public class Test {
  public Double add(Double x, Double y){
    return (x+y);
  }
}"

Как я могу преобразовать его классу Test .class, создайте его экземпляр и вызовите метод add(Double x, Double y) во время выполнения?

Я читал о Byte Приятель, но в примерах, которые я вижу, класс уже определен. В ситуации, подобной приведенной выше, кто-нибудь может привести пример, как я могу использовать ByteBuddy или любые другие библиотеки, с помощью которых я могу достичь этого?

Любые входные данные или предложения о том, как преобразовать этот String в скомпилируемый и инстанцируемый java класс, будут полезны.

Ответы [ 2 ]

3 голосов
/ 13 марта 2020

Можем ли мы использовать что-то вроде этого:

package com.demo;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.StandardLocation;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;

public class StringToClass
{
    public static void main(String[] args)
    {
        String s = "import com.demo.FormulaAPI; public class FormulaExecutor" +
                " { public Double formula1(FormulaAPI apiReference)" +
                " { System.out.println(apiReference.evaluate(\"10.10\"));  return apiReference.evaluate(\"10.10\"); } }";
        try
        {
            dynamicClass(s, "FormulaExecutor");
        } catch (IOException | NoSuchMethodException | ClassNotFoundException | IllegalAccessException | InstantiationException | InvocationTargetException e)
        {
            e.printStackTrace();
        }

    }

    static void dynamicClass(String sourceCode, String className) throws IOException, NoSuchMethodException, ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException
    {
        File parent = new File(System.getProperty("user.dir"));
        File sourceFile = new File(parent, className + ".java");
        sourceFile.deleteOnExit();

        FileWriter writer = new FileWriter(sourceFile);
        writer.write(sourceCode);
        writer.close();

        JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager standardJavaFileManager = javaCompiler.getStandardFileManager(null, null, null);
        File parentDir = sourceFile.getParentFile();
        standardJavaFileManager.setLocation(StandardLocation.CLASS_OUTPUT, Arrays.asList(parentDir));
        Iterable<? extends JavaFileObject> compilationUnits = standardJavaFileManager.getJavaFileObjectsFromFiles(Arrays.asList(sourceFile));
        javaCompiler.getTask(null, standardJavaFileManager, null, null, null, compilationUnits).call();
        standardJavaFileManager.close();

        URLClassLoader urlClassLoader = URLClassLoader.newInstance(new URL[] {parentDir.toURI().toURL()});
        Class<?> dynamicClass = urlClassLoader.loadClass(className);


        Method formula1 = dynamicClass.getDeclaredMethod("formula1", FormulaAPI.class);
        formula1.invoke(dynamicClass.newInstance(), new Object[] {new FormulaAPI()});
    }


}

package com.demo;

public class FormulaAPI
{
    public Double evaluate(String str)
    {
        return Double.valueOf(str);
    }
}

На данный момент имя метода жестко задано

        Method addMethod = dynamicClass.getDeclaredMethod("add", Double.class, Double.class);

Мы даже можем сгенерировать его в runTime с помощью отражения

Мы можем импортировать класс в исходном коде.

1 голос
/ 13 марта 2020

Byte Buddy работает на уровне байтового кода и не обрабатывает исходный код. Вы можете использовать Javassist для этой цели, который предлагает ограниченную обработку исходного кода, поскольку он поставляет свой собственный компилятор.

В качестве альтернативы используйте Java API компилятора, как предложено.

...