在字符串中编译Java代码

时间:2017-02-22 20:54:19

标签: java reflection compilation

我在String中编写一个简单的java代码,并希望在程序运行时动态执行,下面是我的代码:

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

public class CompliedClass {
    public static void main(String[] args) {
        String source = ""
                +"class Solution{"
                +"public int add(){"
                +"return 1+1;"
                +"}"
                +"}";

        //File root = new File("");
        File sourceFile = new File("./src/Solution.java");
        try {
            Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(sourceFile.getPath());
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        if (compiler == null) {
            System.out.println("JDK required (running inside of JRE)");
        }else{
            System.out.println("you got it!");
        }

        int compilationResult = compiler.run(null, null, null,sourceFile.getPath());
        if(compilationResult == 0){
            System.out.println("Compilation is successful");
        }else{
            System.out.println("Compilation Failed");
        }

        try{
            URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { sourceFile.toURI().toURL() });
            Class<?> cls = Class.forName("Solution" , true, classLoader);
            Object instance = cls.newInstance();
            Method method = cls.getDeclaredMethod("add", null);
            System.out.println(method.invoke(instance, null));
        }catch(Exception e){
            System.out.println("something wrong");
        }

    }
}

上面代码的问题是当我第一次执行时,我无法得到结果,看来下面的代码有异常:

Object instance = cls.newInstance();

然后我执行第二次,它的功能很好,所以结论是当我第一次运行时,找不到Solution类,导致下面的异常

java.lang.ClassNotFoundException: Solution

有人可以帮我解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

1)您的班级应该有公共修饰符,否则 CompliedClass 如果未在同一个包中声明,则无法访问它。在这里它可以工作,因为两者都在默认包中,但不建议。

2)你的错误在这里:

URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { sourceFile.toURI().toURL() });

此处sourceFile引用Solution java类文件 它应该根据Solution的javadoc,URLClassLoader java.net.URLClassLoader.newInstance(URL[] urls)参数来引用包含url java类文件的文件夹的url 指的是搜索类和资源的URL。

您可以尝试使用以下两个修改的代码:

public class CompliedClass {
    public static void main(String[] args) {

        String source = "public class Solution{" + "public int add(){" + "return 1+1;" + "}" + "}";

        File folder = new File("./src");
        File sourceFile = new File(folder, "Solution.java");

        try {
            Files.write(sourceFile.toPath(), source.getBytes(StandardCharsets.UTF_8));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(sourceFile.getPath());
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        if (compiler == null) {
            System.out.println("JDK required (running inside of JRE)");
        } else {
            System.out.println("you got it!");
        }

        int compilationResult = compiler.run(null, null, null, sourceFile.getPath());
        if (compilationResult == 0) {
            System.out.println("Compilation is successful");
        } else {
            System.out.println("Compilation Failed");
        }

        try {
            URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] {folder.toURI().toURL() });
            Class<?> cls = Class.forName("Solution", true, classLoader);
            Object instance = cls.newInstance();
            Method method = cls.getDeclaredMethod("add", null);
            System.out.println(method.invoke(instance, null));
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("something wrong");
        }

    }
}

输出:

  

。\ src \ Solution.java

     你知道了!

     

编译成功

     

2

答案 1 :(得分:1)

您的问题可能是解决方案.class的类文件,该类文件是在当前类的.class文件的位置之外的其他位置创建的.class。确保创建.class文件的位置包含在当前程序的类路径中,您将很高兴。

答案 2 :(得分:1)

您提供的代码存在一些问题。

  1. 您定义为字符串的类应该可由主类访问。目前它不是。解决问题的最简单方法是将其设为公开
  2. 您的类加载器正在尝试从源代码本身加载类(“Solution.java”的URL作为类路径URL提供)。 URLClassLoader实际上要求jar到jar或带有类的文件夹。
  3. 请在下面找到更正后的版本:

    public class CompliedClass {
    
      public static void main(String[] args) throws Exception {
        String classDef = ""
            + "public class Solution{"
            + "  public int add(){return 1+1;}"
            + "}";
    
        Path sourceFile = Paths.get("Solution.java");
        Files.write(sourceFile, classDef.getBytes());
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        if (compiler == null) {
          System.out.println("JDK required (running inside of JRE)");
          System.exit(1);
        } else {
          System.out.println("you got it!");
        }
    
        int compilationResult = compiler.run(null, null, null, sourceFile.toString());
        if (compilationResult == 0) {
          System.out.println("Compilation is successful");
        } else {
          System.out.println("Compilation Failed");
          System.exit(1);
        }
    
        URL classPath = sourceFile.toAbsolutePath().getParent().toUri().toURL();
        URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{classPath});
        Class<?> cls = Class.forName("Solution", true, classLoader);
        Object instance = cls.newInstance();
        Method method = cls.getDeclaredMethod("add", null);
        System.out.println(method.invoke(instance, null));
      }
    }