java 使用注释处理器替换代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13690272/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Code replacement with an annotation processor
提问by Boann
I'm trying to write an annotation processorto insert methods and fields on a class... and the documentation is so sparse. I'm not getting far and I don't know if I'm approaching it correctly.
我正在尝试编写一个注释处理器来在类上插入方法和字段......而且文档非常稀疏。我没有走远,我不知道我是否正确地接近它。
The processing environment provides a Filer
object which has handy methods for creating new source and class files. Those work fine but then I tried to figure out how read the existing source files, and all it provides is "getResource". So in my Processor implementation I've done this:
处理环境提供了一个Filer
对象,该对象具有用于创建新源文件和类文件的便捷方法。这些工作正常,但后来我试图弄清楚如何读取现有的源文件,它提供的只是“getResource”。所以在我的处理器实现中,我已经做到了:
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
try {
for (TypeElement te : annotations) {
for (Element element : roundEnv.getElementsAnnotatedWith(te)) {
FileObject in_file = processingEnv.getFiler().getResource(
StandardLocation.SOURCE_PATH, "",
element.asType().toString().replace(".", "/") + ".java");
FileObject out_file = processingEnv.getFiler().getResource(
StandardLocation.SOURCE_OUTPUT, "",
element.asType().toString().replace(".", "/") + ".java");
//if (out_file.getLastModified() >= in_file.getLastModified()) continue;
CharSequence data = in_file.getCharContent(false);
data = transform(data); // run the macro processor
JavaFileObject out_file2 = processingEnv.getFiler().createSourceFile(
element.asType().toString(), element);
Writer w = out_file2.openWriter();
w.append(data);
w.close();
}
}
} catch (Exception e) {
e.printStackTrace();
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
}
return true;
}
My first quandary is I can't help feeling that element.asType().toString().replace(".", "/") + ".java"
(to get the qualified type name and convert it into a package and source file path) is not a nice way to approach the problem. The rest of the API is so over-engineered but there doesn't seem to be a handy method for retrieving the original source code.
我的第一个困惑是我不禁觉得element.asType().toString().replace(".", "/") + ".java"
(获取限定类型名称并将其转换为包和源文件路径)不是解决问题的好方法。API 的其余部分被过度设计,但似乎没有一种方便的方法来检索原始源代码。
The real problem is that then the compiler gets spontaneously upset by the second source file in the output directory ("error: duplicate class") and now I'm stuck.
真正的问题是,编译器会自发地被输出目录中的第二个源文件(“错误:重复类”)打乱,现在我被卡住了。
I've already written the rest of this -- a macro lexer and parser and whatnot for calculating some data and inserting the field values and methods -- but it operates as a initial step outside the compiler. Except for the fact that the original files cannot have a .java extension (to prevent the compiler seeing them), this works nicely. Then I heard that annotations can do code generation, which I assume will be more proper and convenient, but I can't find much guidance on it.
我已经写了剩下的部分——一个宏词法分析器和解析器,以及用于计算一些数据和插入字段值和方法的东西——但它作为编译器之外的初始步骤运行。除了原始文件不能有 .java 扩展名(以防止编译器看到它们)之外,这很好用。然后我听说注解可以做代码生成,我认为这会更合适和方便,但我找不到太多关于它的指导。
采纳答案by John Ericksen
The intention behind the annotation processor is to allow a developer to add new classes, not replace existing classes. That being said, there is a bug that allows you to add code to existing classes. Project Lombokhas leveragedthis to add getter and setter (among other things) to your compiled java classes.
注释处理器背后的意图是允许开发人员添加新类,而不是替换现有类。话虽如此,但存在一个允许您向现有类添加代码的错误。 龙目岛项目已利用这getter和setter(除其他事项外)添加到您的编译的Java类。
The approach I have taken to 'replace' methods/fields is either extend from or delegate to the input class. This allows you to override/divert calls to the target class.
我用来“替换”方法/字段的方法是从输入类扩展或委托给输入类。这允许您覆盖/转移对目标类的调用。
So if this is your input class:
因此,如果这是您的输入类:
InputImpl.java:
InputImpl.java:
public class InputImpl implmements Input{
public void foo(){
System.out.println("foo");
}
public void bar(){
System.out.println("bar");
}
}
You could generate the following to "replace" it:
您可以生成以下内容来“替换”它:
InputReplacementImpl.java:
InputReplacementImpl.java:
public class InputReplacementImpl implmements Input{
private Input delegate;
//setup delegate....
public void foo(){
System.out.println("foo replacement");
}
public void bar(){
delegate.bar();
}
}
This begs the question, how do you reference InputReplacementImpl
instead of InputImpl
. You can either generate some more code to perform the wrapping or simply call the constructor of the code expected to be generated.
这就引出了一个问题,你如何引用InputReplacementImpl
而不是InputImpl
. 您可以生成更多代码来执行包装,也可以简单地调用预期生成的代码的构造函数。
I'm not really sure what your question is, but I hope this sheds some light on your issues.
我不太确定你的问题是什么,但我希望这能对你的问题有所了解。
回答by Jonas Bergstr?m
A bit late :), but one solution could be to use Byte Buddy's transformer as part of the build process. See eg https://github.com/raphw/byte-buddy/tree/master/byte-buddy-maven-plugin.
有点晚了 :),但一种解决方案可能是使用 Byte Buddy 的转换器作为构建过程的一部分。参见例如https://github.com/raphw/byte-buddy/tree/master/byte-buddy-maven-plugin。