使用注释处理器替换代码
我正在尝试编写一个注释处理器来在类上插入方法和字段……而且文档非常稀疏。 我没有走远,我不知道我是否正确接近它。
处理环境提供了一个Filer
对象,该对象具有创建新的源文件和类文件的便捷方法。 那些工作正常,但后来我试图弄清楚如何读取现有的源文件,它提供的只是“getResource”。 所以在我的处理器实现中,我做到了这一点:
@Override public boolean process(Set 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; }
我的第一个窘境是我不禁感觉到element.asType().toString().replace(".", "/") + ".java"
(获取限定类型名称并将其转换为包和(源文件路径)不是解决问题的好方法。 API的其余部分是如此过度设计,但似乎没有一个方便的方法来检索原始源代码。
真正的问题是,然后编译器会被输出目录中的第二个源文件(“错误:重复类”)自发地打乱,现在我被卡住了。
我已经编写了其余部分 – 宏词法分析器和解析器以及用于计算某些数据和插入字段值和方法的内容 – 但它作为编译器之外的第一步操作。 除了原始文件不能具有.java扩展名(以防止编译器看到它们)之外,这很好用。 然后我听说注释可以做代码生成,我认为它会更合适和方便,但我找不到很多指导。
注释处理器背后的意图是允许开发人员添加新类,而不是替换现有类。 话虽如此,但有一个错误允许您向现有类添加代码。 Project Lombok 利用它将getter和setter(以及其他内容)添加到已编译的java类中。
我用来’替换’方法/字段的方法是从输入类扩展或委托给输入类。 这允许您覆盖/转移对目标类的调用。
所以如果这是你的输入类:
InputImpl.java:
public class InputImpl implmements Input{ public void foo(){ System.out.println("foo"); } public void bar(){ System.out.println("bar"); } }
您可以生成以下内容以“替换”它:
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(); } }
这引出了一个问题,你如何引用InputReplacementImpl
而不是InputImpl
。 您可以生成更多代码来执行包装,也可以只调用期望生成的代码的构造函数。
我不确定你的问题是什么,但我希望这会对你的问题有所了解。