问题的背景:
创建一个包含具有不存在的超类的类的java文件;获取javac解析类,但不编译它;以编程方式生成超类(这意味着没有类文件);最后让javac成功生成一个类文件。
这是CompilerAPITest.java
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.Locale;
import java.util.logging.Logger;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
/**
* A test class to test dynamic compilation API.
*
*/
public class CompilerAPITest {
static final Logger logger = Logger.getLogger(CompilerAPITest.class.getName()) ;
public void doCompilation (){
File[] files = {new File("/home/guestu/GeneratedClass.java")};
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager stdFileManager = compiler.getStandardFileManager(null, Locale.getDefault(), null);
/* Prepare a list of compilation units (java source code file objects) to input to compilation task*/
Iterable<? extends JavaFileObject> compilationUnits = stdFileManager.getJavaFileObjects(files);
/*Create a diagnostic controller, which holds the compilation problems*/
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
/*Create a compilation task from compiler by passing in the required input objects prepared above*/
CompilationTask compilerTask = compiler.getTask(null, stdFileManager, diagnostics, null, null, compilationUnits) ;
boolean status = compilerTask.call();
if (!status){//If compilation error occurs
/*Iterate through each compilation problem and print it*/
for (Diagnostic diagnostic : diagnostics.getDiagnostics()){
System.out.format("Error on line %d in %s", diagnostic.getLineNumber(), diagnostic);
}
}
try {
stdFileManager.close() ;//Close the file manager
} catch (IOException e) {
}
//Here is Helloworld.java
public class Helloworld extends GeneratedClass{
public static void main(String[] args){
System.out.println("Hello");
}
}
//And here is GeneratedClass.java
package com.sun.tools.javac.parser;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.JCTree.JCAnnotation;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Name;
import com.sun.tools.javac.util.Names;
/* This class programmatically produces the superclass "GeneratedClass" with signature public class GeneratedClass{} */
public class GeneratedClass {
TreeMaker maker;
Names names;
public GeneratedClass(ParserFactory fac) {
maker = fac. F;
names = fac.names;
}
public JCCompilationUnit getTree() {
ListBuffer<JCTree> defs = new ListBuffer<JCTree>();
defs.append(makeClassDecl());
return maker.TopLevel(List.<JCAnnotation>nil(), null, defs.toList());
}
/* This is a class decalaration node for public class GeneratedClass{}*/
protected JCClassDecl makeClassDecl() {
JCModifiers mods = maker.Modifiers(Flags.PUBLIC);
Name name = names.fromString("GeneratedClass");
return maker.ClassDef(mods, name, List.<JCTypeParameter>nil(), null, List.<JCExpression>nil(), List.<JCTree>nil());
}
}
我当前的挑战
我以编程方式生成了一个类文件(GeneratedClass)。我希望它能被java编译器选中以编译Helloworld.java。我已经尝试了上面的方法但是Helloworld没有编译,因为它无法获取GeneratedClass。有没有办法可以做到这一点? 谢谢你的时间。
答案 0 :(得分:0)
我猜你必须自定义文件管理器。但是你的任务似乎非常适合注释处理器。代码将被解析,如果缺少某些类,则完全没问题。解析后的代码模型将传递给注释处理器,注释处理器可以执行任何选择。甚至还有一些用于编写生成的类的基础结构。参见
http://docs.oracle.com/javase/7/docs/api/javax/annotation/processing/Processor.html
和
http://deors.wordpress.com/2011/10/08/annotation-processors/