读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 是 Java 中的一个编译器接口,提供了编译 Java 源代码的功能。在 Java SE6 中,JavaCompiler 接口是 javax.tools 包的一部分,提供了标准的方式来...
本文将深入探讨如何利用Java的API来动态编译.java源文件,并执行编译后的类。 首先,Java的`javac`命令行工具是用于编译Java源代码的标准方式,但在程序中实现动态编译则需要使用`javax.tools`包中的接口和类。这个...
Java 6及以后的版本引入了`javax.tools.JavaCompiler`接口,它提供了一套API用于在运行时编译Java源码。首先,我们需要获取`ToolProvider`的实例,然后使用`getSystemJavaCompiler()`方法来获取`JavaCompiler`实例...
Java的`javax.tools.JavaCompiler` API 提供了这样的能力,让我们能够在运行时动态编译Java源文件。 首先,我们需要引入`javax.tools`和`java.compiler`这两个Java标准库。它们包含了编译Java源文件所需的所有工具...
1. **Java编译API:Javacompiler接口** Java提供了一个内置的`javax.tools.JavaCompiler`接口,它是Java工具接口(Java Tool API)的一部分,允许我们在程序中调用Javac编译器。要使用这个接口,首先需要引入`tools...
结合Java反编译和Oracle API,开发者可以深入理解已有的Java库和应用,甚至对它们进行定制和扩展。通过反编译,可以查看Oracle API的实现细节,这对于优化性能、解决兼容性问题或进行安全审计都非常有价值。同时,...
Java6动态编译案例主要涉及的是Java平台中的Java编译器API(Java Compiler API),这是Java SE 6引入的一个重要特性,允许程序在运行时动态地编译源代码。这个功能使得开发者能够在运行的应用程序中生成和编译Java类...
在Java编程中,动态编译字符串成Java代码并将其加载到JVM(Java虚拟机)是一种高级技巧,常用于运行时代码生成、元编程或插件系统等场景。这一技术的核心在于利用Java的反射API和Java Compiler API。下面将详细阐述...
Java API文档是Java开发者不可或缺的参考资料,它详细地介绍了Java平台标准版(Java SE)的各种类库、接口和实现。这个“Java API文档中文版.zip”包含了一个.chm( Compiled HTML Help)文件,这是一种常见的帮助...
首先,`javax.tools.JavaCompiler`是Java编译器工具接口,它是Java 6引入的一个新特性,提供了在运行时动态编译Java源码的能力。通过`ToolProvider`类,我们可以获取到`JavaCompiler`的实例。例如: ```java Java...
在Java中,实现类似`eval`功能的一种方法是利用Java的动态编译API,例如`javax.tools.JavaCompiler`接口和相关的工具类。以下是一个简单的示例,演示如何将字符串转换为Java方法并执行: ```java import javax....
1. **Java Compiler API**: Java 6引入了`javax.tools.JavaCompiler`接口和相关的工具API,使得在运行时编译Java源代码成为可能。这个API提供了与平台无关的编译服务,可以通过`ToolProvider`获取默认的Java编译器...
1. **动态代码生成**:在Java中,我们可以通过Java的反射API(Reflection API)来操作已知的类和对象,但若需要在运行时生成新的类或方法,就需要用到动态编译。例如,当我们需要根据特定条件自动生成处理逻辑时,...
本话题将深入探讨如何使用Java实现迅雷下载接口,这是一项利用迅雷的动态链接库(DLL)和C++开放接口来提升下载效率和稳定性的技术实践。 首先,我们需要了解迅雷的C++开放接口。迅雷为了方便开发者集成其下载功能...
10. **反射**:java.lang.reflect包提供了反射API,可以在运行时检查类、接口、构造器和方法的信息,甚至动态调用方法和创建对象。 11. **注解(Annotation)**:Java 6引入了注解,这是一种元数据,可以提供编译时...
Java API 1.6中文文档是Java开发者的重要参考资料,它详细介绍了Java 1.6版本中的各种类库、接口、方法以及异常等核心组件。这个文档以CHM(Compiled HTML Help)格式提供,允许开发者在没有网络的情况下进行离线...
Java API是Java编程语言的核心组成部分,它包含了Java平台标准版(Java SE)的各种类库,为开发者提供了大量的接口、类和方法,使得开发者能够构建出功能丰富的应用程序。本资源包括了Java API的1.5和1.6两个版本的...
这个API提供了一套工具接口,用于与Java编译器进行交互,可以方便地在程序运行时动态编译源代码。核心接口包括`JavaCompiler`,`StandardJavaFileManager`,`DiagnosticCollector`等,它们协同工作以完成编译任务。 ...
11. **注解(Annotation)**:`java.lang.annotation`包提供了元数据,可以在编译时或运行时处理类、接口、方法等的附加信息。 12. **并发工具**:`java.util.concurrent`包提供了高级并发工具,如`CountDownLatch`...