使用注释处理器替换代码 [英] Code replacement with an annotation processor

查看:129
本文介绍了使用注释处理器替换代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写注释处理器在类上插入方法和字段......文档很稀疏。我没有走得太远,我不知道我是否正确接近它。

I'm trying to write an annotation processor to 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.

处理环境提供了 Filer 对象,它有方便的方法来创建新的源文件和类文件。那些工作正常,但后来我试图弄清楚如何读取现有的源文件,它提供的只是getResource。所以在我的处理器实现中我做到了这一点:

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:

@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;
}

我的第一个窘境是我不禁感慨 element.asType()。toString()。replace(。,/)+。java(获取限定类型名称并将其转换为包和源文件路径)不是解决问题的好方法。 API的其余部分是如此过度设计,但似乎没有一个方便的方法来检索原始源代码。

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.

真正的问题是,那么编译器被输出目录中的第二个源文件(错误:重复类)自发地打乱了,现在我被卡住了。

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.

我已经编写了其余的这是一个宏词法分析器和解析器,以及用于计算某些数据和插入字段值和方法的东西 - 但它作为编译器之外的第一步操作。除了原始文件不能具有.java扩展名(以防止编译器看到它们)之外,这很好用。然后我听说注释可以做代码生成,我认为它会更合适和方便,但我找不到太多的指导。

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.

推荐答案

注释处理器背后的意图是允许开发人员添加新类,而不是替换现有类。话虽如此,但是有一个错误允许您向现有类添加代码。 Project Lombok 利用这个将getter和setter(以及其他东西)添加到已编译的java类中。

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 Lombok has leveraged this to add getter and setter (among other things) to your compiled java classes.

我已经采取'替换'方法/字段的方法是从输入类扩展或委托给输入类。这允许你覆盖/转移对目标类的调用。

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();
    }
}

这引出了一个问题,你如何引用 InputReplacementImpl 而不是 InputImpl 。您可以生成更多代码来执行换行,也可以只调用期望生成的代码的构造函数。

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.

我不确定你的问题是什么,但我希望这能为你的问题提供一些启示。

I'm not really sure what your question is, but I hope this sheds some light on your issues.

这篇关于使用注释处理器替换代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆