`
budairenqin
  • 浏览: 201230 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

java API的动态编译接口

阅读更多
     读javac源码时奇怪com.sun.tools.javac.main.Main中有这么个boolean apiMode实例变量,代码注释说“如果apiMode为true,那么某些错误可能导致异常”。奇怪的是从命令行启动javac并没有相关代码能设置apiMode的值,于是在源码中翻来翻去,发现原来是动态编译时会用到apiMode这个变量,于是豁然开朗,还是记录下吧,好记性不如烂笔头

特意写了个动态编译的测试代码如下:
    public static final String JAVA_FILE_NAME = "DynamicCompiler";
    
    /**
     * 动态编译javac入口:
     * com.sun.tools.javac.api.JavacTaskImpl.call()
     */
    @Test public void testDynamicCompiler() {
        try {
            // 动态编译
            // compiler实际类型:com.sun.tools.javac.api.JavacTool
            javax.tools.JavaCompiler compiler = javax.tools.ToolProvider.getSystemJavaCompiler();
            
            // standardJavaFileManager实际类型 :com.sun.tools.javac.file.JavacFileManager
            javax.tools.StandardJavaFileManager standardJavaFileManager = compiler.getStandardFileManager(null, null, null);
            
            Iterable<? extends javax.tools.JavaFileObject> iterable =
                    standardJavaFileManager.getJavaFileObjects(MainTest.JAVAFILES_PATH + "/" + JAVA_FILE_NAME + ".java");
    
            // 相当于命令行调用javac时的参数
            List<String> args = Arrays.asList("-d", MainTest.CLASSFILES_PATH);
            
            // compilationTask实际类型:com.sun.tools.javac.api.JavacTaskImpl
            javax.tools.JavaCompiler.CompilationTask compilationTask =
                    compiler.getTask(null, standardJavaFileManager, null, args, null, iterable);
            
            // 调用com.sun.tools.javac.api.JavacTaskImpl.call(); 函数中会把apiMode设置为true
            // 编译,调用com.sun.tools.javac.main.compile(String[], Context, List<JavaFileObject> ,Iterable<? extends Processor>)
            compilationTask.call();
            
            standardJavaFileManager.close();
            
            // 用URLClassLoader来装载这个编译好的类
            URL[] urls = new URL[] {new URL("file:/" + MainTest.CLASSFILES_PATH + "/")};
            URLClassLoader urlClassLoader = new URLClassLoader(urls);
            Class<?> clazz = urlClassLoader.loadClass(JAVA_FILE_NAME);
            
            // 方法调用
            Object obj = clazz.newInstance();
            Method method = clazz.getMethod("sayHello");
            method.invoke(obj);
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
                | NoSuchMethodException | SecurityException | IllegalArgumentException
                | InvocationTargetException | IOException e) {
            e.printStackTrace();
        }
    }

被编译的java文件
public class DynamicCompiler {
    public void sayHello() {
        System.out.println("Hello");
    }
}


以下javax.tools.ToolProvider.findSystemToolClass(String)方法中源码片段是关键,它会找到你机器%JAVA_HOME%/lib/tools.jar,然后装载
                File file = new File(System.getProperty("java.home"));
                if (file.getName().equalsIgnoreCase("jre"))
                    file = file.getParentFile();
                for (String name : defaultToolsLocation)
                    file = new File(file, name);

                // if tools not found, no point in trying a URLClassLoader
                // so rethrow the original exception.
                if (!file.exists())
                    throw e;

                URL[] urls = { file.toURI().toURL() };
                trace(FINE, urls[0].toString());

                cl = URLClassLoader.newInstance(urls);
                refToolClassLoader = new WeakReference<ClassLoader>(cl);


编译源码片段(来自com.sun.tools.javac.api.JavacTaskImpl):
public Boolean call() {
        if (!used.getAndSet(true)) {
            initContext();
            notYetEntered = new HashMap<JavaFileObject, JCCompilationUnit>();
            compilerMain.setAPIMode(true);
            // 编译器入口 com.sun.tools.javac.main.Main.compile(String[], Context, List<JavaFileObject>,Iterable<? extends Processor>)
            result = compilerMain.compile(args, context, fileObjects, processors);
            cleanup();
            return result == 0;
        } else {
            throw new IllegalStateException("multiple calls to method 'call'");
        }
    }


其实写了这么多,只有这一句才是我的最初目的
compilerMain.setAPIMode(true);

但是最后发现不经意间学到了更多更好的东西,还是记录下来吧
分享到:
评论

相关推荐

    JavaCompiler --JDK6 API的简介(java动态编译)

    JavaCompiler --JDK6 API 的简介(java动态编译) JavaCompiler 是 Java 中的一个编译器接口,提供了编译 Java 源代码的功能。在 Java SE6 中,JavaCompiler 接口是 javax.tools 包的一部分,提供了标准的方式来...

    java 动态编译.java文件,动态运行类

    本文将深入探讨如何利用Java的API来动态编译.java源文件,并执行编译后的类。 首先,Java的`javac`命令行工具是用于编译Java源代码的标准方式,但在程序中实现动态编译则需要使用`javax.tools`包中的接口和类。这个...

    Java 动态编译源码并调用

    Java 6及以后的版本引入了`javax.tools.JavaCompiler`接口,它提供了一套API用于在运行时编译Java源码。首先,我们需要获取`ToolProvider`的实例,然后使用`getSystemJavaCompiler()`方法来获取`JavaCompiler`实例...

    java动态编译java源文件

    Java的`javax.tools.JavaCompiler` API 提供了这样的能力,让我们能够在运行时动态编译Java源文件。 首先,我们需要引入`javax.tools`和`java.compiler`这两个Java标准库。它们包含了编译Java源文件所需的所有工具...

    java 动态编译.java文件,动态运行类 _1.2

    1. **Java编译API:Javacompiler接口** Java提供了一个内置的`javax.tools.JavaCompiler`接口,它是Java工具接口(Java Tool API)的一部分,允许我们在程序中调用Javac编译器。要使用这个接口,首先需要引入`tools...

    java反编译+api

    结合Java反编译和Oracle API,开发者可以深入理解已有的Java库和应用,甚至对它们进行定制和扩展。通过反编译,可以查看Oracle API的实现细节,这对于优化性能、解决兼容性问题或进行安全审计都非常有价值。同时,...

    Java6动态编译案例

    Java6动态编译案例主要涉及的是Java平台中的Java编译器API(Java Compiler API),这是Java SE 6引入的一个重要特性,允许程序在运行时动态地编译源代码。这个功能使得开发者能够在运行的应用程序中生成和编译Java类...

    动态编译字符串成java,并且添加class到jvm

    在Java编程中,动态编译字符串成Java代码并将其加载到JVM(Java虚拟机)是一种高级技巧,常用于运行时代码生成、元编程或插件系统等场景。这一技术的核心在于利用Java的反射API和Java Compiler API。下面将详细阐述...

    Java API文档中文版.zip

    Java API文档是Java开发者不可或缺的参考资料,它详细地介绍了Java平台标准版(Java SE)的各种类库、接口和实现。这个“Java API文档中文版.zip”包含了一个.chm( Compiled HTML Help)文件,这是一种常见的帮助...

    内存中动态编译执行java代码

    首先,`javax.tools.JavaCompiler`是Java编译器工具接口,它是Java 6引入的一个新特性,提供了在运行时动态编译Java源码的能力。通过`ToolProvider`类,我们可以获取到`JavaCompiler`的实例。例如: ```java Java...

    在java中利用动态编译实现eval

    在Java中,实现类似`eval`功能的一种方法是利用Java的动态编译API,例如`javax.tools.JavaCompiler`接口和相关的工具类。以下是一个简单的示例,演示如何将字符串转换为Java方法并执行: ```java import javax....

    动态编译、加载java类

    1. **Java Compiler API**: Java 6引入了`javax.tools.JavaCompiler`接口和相关的工具API,使得在运行时编译Java源代码成为可能。这个API提供了与平台无关的编译服务,可以通过`ToolProvider`获取默认的Java编译器...

    java 动态编译打包 动态编译可以用于实现动态代码生成、动态加载、插件化等功能

    1. **动态代码生成**:在Java中,我们可以通过Java的反射API(Reflection API)来操作已知的类和对象,但若需要在运行时生成新的类或方法,就需要用到动态编译。例如,当我们需要根据特定条件自动生成处理逻辑时,...

    迅雷下载接口java实现

    本话题将深入探讨如何使用Java实现迅雷下载接口,这是一项利用迅雷的动态链接库(DLL)和C++开放接口来提升下载效率和稳定性的技术实践。 首先,我们需要了解迅雷的C++开放接口。迅雷为了方便开发者集成其下载功能...

    JAVA API字典

    10. **反射**:java.lang.reflect包提供了反射API,可以在运行时检查类、接口、构造器和方法的信息,甚至动态调用方法和创建对象。 11. **注解(Annotation)**:Java 6引入了注解,这是一种元数据,可以提供编译时...

    java api1.6中文文档chm

    Java API 1.6中文文档是Java开发者的重要参考资料,它详细介绍了Java 1.6版本中的各种类库、接口、方法以及异常等核心组件。这个文档以CHM(Compiled HTML Help)格式提供,允许开发者在没有网络的情况下进行离线...

    javaapi中文版

    Java API是Java编程语言的核心组成部分,它包含了Java平台标准版(Java SE)的各种类库,为开发者提供了大量的接口、类和方法,使得开发者能够构建出功能丰富的应用程序。本资源包括了Java API的1.5和1.6两个版本的...

    java 动态编译特性的展示工程勘误篇

    这个API提供了一套工具接口,用于与Java编译器进行交互,可以方便地在程序运行时动态编译源代码。核心接口包括`JavaCompiler`,`StandardJavaFileManager`,`DiagnosticCollector`等,它们协同工作以完成编译任务。 ...

    java api下载 英文版

    11. **注解(Annotation)**:`java.lang.annotation`包提供了元数据,可以在编译时或运行时处理类、接口、方法等的附加信息。 12. **并发工具**:`java.util.concurrent`包提供了高级并发工具,如`CountDownLatch`...

Global site tag (gtag.js) - Google Analytics