Java SE6调用动态编译

来源:互联网 发布:美食杰seo分析 编辑:程序博客网 时间:2024/04/30 13:26

一、使用JavaCompiler接口编译java源程序

  我们可以通过ToolProvider类的静态方法getSystemJavaCompiler来得到一个JavaCompiler接口的实例。需要用到 jre6\lib\tools.jar 这个包。

 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

  JavaCompiler中最核心的方法是run。通过这个方法可以编译java源程序。这个方法有3个固定参数和1个可变参数(可变参数是从Jave SE5开始提供的一个新的参数类型,用type… argu表示)。前3个参数分别用来为java编译器提供参数、得到Java编译器的输出信息以及接收编译器的错误信息,后面的可变参数可以传入一个或多 个Java源程序文件。如果run编译成功,返回0。

 int run(InputStream in, OutputStream out, OutputStream err, String... arguments) 

  如果前3个参数传入的是null,那么run方法将以标准的输入、输出代替,即System.in、System.out和System.err。

  下面是利用java动态编译实现eval功能:

package com.flyoung;import java.io.File;import java.io.FileWriter;import java.io.PrintWriter;import java.lang.reflect.Method;import javax.tools.JavaCompiler;import javax.tools.ToolProvider;public class JavacTest {    public JavacTest(){            }        public static void eval(String str){        System.out.println(System.getProperty("user.dir"));//当前工作目录        String s = "public class Temp{" ;        s+="\r\n"+"      public static String call(String ss){      ";                s+="\r\n"+"            System.out.println(\""+str+"\");  ";        s+="\r\n"+"            return \"return_str\"; ";        s+="\r\n"+"      }";        s+="\r\n"+"}";        try{            File file = new File("Temp.java");            PrintWriter pw = new PrintWriter(new FileWriter(file));            //pw.println(s);            //pw.write(s);            pw.close();                        //动态编译            JavaCompiler javac = ToolProvider.getSystemJavaCompiler();            int status = javac.run(null, null, null, "-d",System.getProperty("user.dir")+"/bin","Temp.java");            if(status!=0){                System.out.println("没有编译成功!");            }                        //动态执行        Class cls = Class.forName("Temp");//返回与带有给定字符串名的类 或接口相关联的 Class 对象。        Method method = cls.getDeclaredMethod("call", String.class);//返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法        String result= (String)method.invoke(null, str);//静态方法第一个参数可为null,第二个参数为实际传参        System.out.println(result);        }catch(Exception e){            e.printStackTrace();        }        }    /**     * @param args     */    public static void main(String[] args) {        // TODO Auto-generated method stub        JavacTest javacTest = new JavacTest();        javacTest.eval("input_str");    }}

二、使用StandardJavaFileManager编译java源程序

  在Java SE6中最好的方法是使用StandardJavaFileManager类。这个类可以很好地控制输入、输出,并且可以通过DiagnosticListener得到诊断信息,而DiagnosticCollector类就是listener的实现。
  使用StandardJavaFileManager需要两步。首先建立一个DiagnosticCollector实例以及通过 JavaCompiler的getStandardFileManager()方法得到一个StandardFileManager对象。最后通过 CompilationTask中的call方法编译源程序。

详细请看:http://doc.java.sun.com/DocWeb/api/javax.tools.JavaCompiler

示例:

package com.flyoung;import java.io.File; import java.io.FileWriter; import java.util.Arrays; import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; public class DynamicCompileTest {   public static void main(String[] args) throws Exception {       //1.创建需要动态编译的代码字符串       String nr="\r\n";//回车换行       String source="package com.flyoung.hello;"+nr+       "    public class Hello{"+nr+       "     public static void main(String[] args){"+nr+       "     System.out.println(\"helloworld!\");"+nr+       "}"+nr+       "}"  ;      //2.将预动态编译的代码写入文件中1:创建临时目录 2:写入临时文件       File dir=new File(System.getProperty("user.dir")+"/temp");//临时目录      //如果/temp目录不存在创建temp目录      if(!dir.exists()){        dir.mkdir(); }      FileWriter writer=new FileWriter(new File(dir,"Hello.java"));      writer.write(source);//将字符串写入文件中      writer.flush();      writer.close();      //3:取得当前系统java编译器      JavaCompiler javaCompiler=ToolProvider.getSystemJavaCompiler();    //4:获取一个文件管理器StandardJavaFileManage      StandardJavaFileManager javaFileManager=javaCompiler.getStandardFileManager(null, null, null);    //5.文件管理器根与文件连接起来      Iterable it=javaFileManager.getJavaFileObjects(new File(dir,"Hello.java"));    //6.创建编译的任务     CompilationTask task=javaCompiler.getTask(null,     javaFileManager,null,Arrays.asList("-d","./temp"), null, it);    //执行编译     task.call();     javaFileManager.close();   } }

三、从内存中动态编译源程序

      JavaCompiler 不仅能编译硬盘上的 Java 文件,而且还能编译内存中的 Java 代码,然后使用reflection来运行他们。

package com.flyoung;import java.io.IOException; import java.net.URI; import javax.tools.SimpleJavaFileObject; public class JavaStringObject extends SimpleJavaFileObject {   private String code;   public JavaStringObject(String name, String code) {    //super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);    super(URI.create(name+".java"), Kind.SOURCE);    this.code = code;   }   @Override   public  CharSequence  getCharContent(boolean  ignoreEncodingErrors)  throws  IOException   {    return code;   } } 

 

package com.flyoung;import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask; public class DynamicCompileTest {   public static void main(String[] args) throws Exception {    /*      * 编译内存中的java代码      */    // 将代码写入内存中     StringWriter writer = new StringWriter();// 内存字符串输出流     PrintWriter out = new PrintWriter(writer);     out.println("package com.flyoung.hello;");     out.println("public class Hello{");     out.println("public static void main(String[] args){");     out.println("System.out.println(\"helloworld!\");");     out.println("}");     out.println("}");     out.flush();     out.close();    // 开始编译     JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();     JavaFileObject fileObject = new JavaStringObject("Hello", writer.toString());    CompilationTask  task=javaCompiler.getTask(null, null, null,     Arrays.asList("-d","./bin"), null, Arrays.asList(fileObject));     boolean success=task.call();        if(!success){          System.out.println("编译失败!");        }        else{          System.out.println("编译成功!");         //利用反射调用其中的main()方法         // Class class1=Class.forName("com.flyoung.hello.Hello");         //ClassLoader是自动去从当前工作目录下的classpath路径下去找 也就是bin目录下  //Class class1=ClassLoader.getSystemClassLoader().loadClass("com.flyoung.hello.Hello");                 //利用URLClassLoader去实例化一个Class类  类文件可以放在任意位置,这样就很方便了          URL[] urls=new URL[]{new URL("file:/"+"./bin/")};          URLClassLoader classLoader=new URLClassLoader(urls);          Class class1=classLoader.loadClass("com.flyoung.hello.Hello");          Method method=class1.getDeclaredMethod("main",String[].class);          String[] args1={null};          method.invoke(class1.newInstance(),args1);         }   } } 



原创粉丝点击