1

所以我有一些代码 - 我想编译字符串'temp'然后执行它,然后更改字符串,重新编译并执行。问题是目前它只是首先执行第一个代码。在代码中编译,没有得到我想要的行为。

我想到:

​​

我也得到:

This is in another java file 
This is in another java file 

的完整代码如下,感谢任何帮助。

import java.io.IOException; 
import java.util.Arrays; 
import javax.tools.DiagnosticCollector; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaCompiler.CompilationTask; 
import javax.tools.JavaFileObject; 
import javax.tools.ToolProvider; 

public class Another2 { 

    public static void main(String args[]) throws IOException { 
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); 

     //First run 
     String temp = "public class HelloWorld {\n" + " public static void main(String args[]) {\n" 
       + " System.out.println(\"First Compiled Class\");\n" + " }\n" + "}"; 

     JavaFileObject file = new JavaSourceFromString("HelloWorld", temp); 
     Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file); 
     CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits); 
     task.call(); 
     try { 
      Class.forName("HelloWorld").getDeclaredMethod("main", new Class[] { String[].class }) 
        .invoke(null, new Object[] { null }); 
     } catch (Exception e) { 
      // handled it 
     } 

     //second run 
     temp = "public class HelloWorld {\n" + " public static void main(String args[]) {\n" 
       + " System.out.println(\"How About Now?\");\n" + " }\n" + "}"; 
     file = new JavaSourceFromString("HelloWorld", temp); 
     Iterable<? extends JavaFileObject> compilationUnits2 = Arrays.asList(file); 
     task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits2); 
     task.call(); 
     try { 
      Class.forName("HelloWorld").getDeclaredMethod("main", new Class[] { String[].class }) 
        .invoke(null, new Object[] { null }); 
     } catch (Exception e) { 
      // handled it 
     } 
    } 

} 

回答

0

原来,我一直在寻找的代码是:

import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.net.MalformedURLException; 
import java.net.URI; 
import java.net.URL; 
import java.net.URLConnection; 
import java.util.Arrays; 

import javax.tools.DiagnosticCollector; 
import javax.tools.JavaCompiler; 
import javax.tools.JavaFileObject; 
import javax.tools.SimpleJavaFileObject; 
import javax.tools.ToolProvider; 
import javax.tools.JavaCompiler.CompilationTask; 

public class AnotherClassLoaderRunner { 

    private static final String nameOfDemoClass = "ByeWorld"; 

    public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, 
      IllegalArgumentException, IllegalAccessException, InvocationTargetException { 
     // Start compilation and loading of first class. 
     String sourceCode = "public class " + nameOfDemoClass + " {\n" + " public static void main(String args[]) {\n" 
       + " System.out.println(\"First of our Compiled Class\");\n" + " }\n" + "}"; 
     AnotherClassLoader classLoader = new AnotherClassLoader(AnotherClassLoaderRunner.class.getClassLoader(), nameOfDemoClass); 
     Class<?> myclass = classLoader.loadClass(nameOfDemoClass,sourceCode); 
     Method mymethod = myclass.getDeclaredMethod("main", new Class[] { String[].class }); 
     mymethod.invoke(null, new Object[] { null }); 

     // Start compilation and loading of second class. 
     sourceCode = sourceCode.replace("First of our Compiled Cla", "Second of our Compiled Cla"); 
     classLoader = new AnotherClassLoader(AnotherClassLoaderRunner.class.getClassLoader(), nameOfDemoClass); 
     myclass = classLoader.loadClass(nameOfDemoClass,sourceCode); 
     mymethod = myclass.getDeclaredMethod("main", new Class[] { String[].class }); 
     mymethod.invoke(null, new Object[] { null }); 
    } 
} 

class AnotherClassLoader extends ClassLoader { 

    private static final String pathToClassDirectory = "file:/Users/*********/Documents/workspace/Dynamic/src/"; 
    private String targetName; 

    public AnotherClassLoader(ClassLoader parent, String target) { 
     super(parent); 
     targetName = target; 
    } 

    public Class<?> loadClass(String name, String compileme) throws ClassNotFoundException { 
     if (!targetName.equals(name)) { 
      return super.loadClass(name); 
     } 
     JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
     JavaFileObject file = new JavaSourceFromString(name, compileme); 
     Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file); 
     CompilationTask task = compiler.getTask(null, null, new DiagnosticCollector<JavaFileObject>(), null, null, 
       compilationUnits); 
     task.call(); 
     // THE CLASSFILE FOR THE SYSTEM EXSITS AT THIS POINT, thought how it 
     // chooses the directory escapes me. 
     try { 
      String url = pathToClassDirectory + targetName + ".class"; 
      URL myUrl = new URL(url); 
      URLConnection connection = myUrl.openConnection(); 
      InputStream input = connection.getInputStream(); 
      ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
      int data = input.read(); 
      while (data != -1) { 
       buffer.write(data); 
       data = input.read(); 
      } 
      input.close(); 
      byte[] classData = buffer.toByteArray(); 

      return defineClass(targetName, classData, 0, classData.length); 

     } catch (MalformedURLException e) { 
      e.printStackTrace(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 
} 

class JavaSourceFromString extends SimpleJavaFileObject { 
    final String code; 

    JavaSourceFromString(String name, String code) { 
     super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); 
     this.code = code; 
    } 

    @Override 
    public CharSequence getCharContent(boolean ignoreEncodingErrors) { 
     return code; 
    } 
} 
2

我怀疑是默认的类加载器缓存中的类文件和你的第二个的Class.forName()实际上没有做任何事情。您需要创建自己的类加载器并使用它。