2017-02-22 5 views
3

написать простой код Java в строке и хочет выполнить динамически при запуске программы, ниже мой код:Compile 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(); 

Затем я выполняю во второй раз, он работает хорошо, поэтому вывод о том, когда я запускаю в первый раз, Невозможно найти класс решения, вызывающий исключение ниже

java.lang.ClassNotFoundException: Solution 

Может кто-нибудь помочь мне исправить эту проблему, пожалуйста?

+0

Просто удивительно, почему не загружается файл банку динамически? –

+0

ClassLoaders загружают файлы .class, а не файлы .java. Вы не можете передать 'sourceFile' в URLClassLoader. На самом деле, я уверен, что вы даже не можете передать файл .class; вам нужно передать URL-адрес каталога или файла .jar, который содержит один или несколько файлов .class. URL-адреса, которые вы передаете URLClassLoader, функционально идентичны пути к классам. – VGR

+0

Замечание: вам даже не нужно писать материал в * файл *. Это можно сделать исключительно в памяти. См. Http://stackoverflow.com/questions/935175/convert-string-to-code/30038318#30038318 для примера. – Marco13

ответ

1

1) У вашего класса должен быть общедоступный модификатор иначе Соответствующий класс не смог получить к нему доступ, если он не был объявлен в том же пакете. Здесь он может работать как в пакете по умолчанию, но не рекомендуется.

2) Ваша ошибка здесь:

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

Здесь sourceFile относится к файлу класса Solution Java.
Он должен скорее ссылаться на URL-адрес папки, содержащей файл класса Java Solution, поскольку согласно javadoc URLClassLoader java.net.URLClassLoader.newInstance(URL[] urls) параметр 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

вы его получили!

Компиляция успешна

+0

Твоя работа прекрасна, спасибо, эта проблема часто меня раздражала. – crlyw

0

Ваша проблема может быть файл класса для решения .class создается в другом месте, чем местоположение файла .class текущего класса. Убедитесь, что место, где создан файл .class, включено в путь к классам текущей программы, и вам будет хорошо идти.

1

Существует несколько проблем с кодом, который вы предоставили.

  1. Класс, который вы определяете как строку, должен быть доступен вашему основному классу. В настоящее время это не так. Самый простой способ исправить это - сделать это public
  2. Ваш загрузчик классов пытается загрузить класс из самого исходного кода (URL-адрес «Solution.java» предоставляется как URL-адрес пути). URLClassLoader фактически ожидает либо URL-адрес банку, либо папку с классами.

Вы можете найти исправленную версию ниже:

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)); 
    } 
} 
+0

Спасибо за исправление меня, ваш код работает нормально. – crlyw