当前位置: 首页 > 知识库问答 >
问题:

使用注释处理器替换代码

卫高明
2023-03-14

我正在尝试编写一个注释处理器来插入类上的方法和字段......留档如此稀疏。我走不远,我不知道我是否正确地接近它。

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

@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()。替换(".", "/") ".java"(获取合格的类型名称并将其转换为包和源文件路径)不是解决问题的好方法。API的其余部分设计过度,但似乎没有一种方便的方法来检索原始源代码。

真正的问题是,然后编译器会被输出目录中的第二个源文件(“错误:duplicate class”)打乱,现在我被卡住了。

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

共有3个答案

鲜于峰
2023-03-14

我不知道这个提示是否符合您的需求,但您的想法将与依赖注入(例如Spring)一起工作。

  1. 为Spring将忽略的类型和保留“源”创建自定义注释
  2. 在注释处理器中对代码进行所需的更改,将Spring的@Component注释添加到生成的Java类型中,并将其保存为原始类型的子类型,其类名与原始类型不同
  3. 当Spring创建上下文时,它将根据您的处理结果而不是原始结果加载类

相反,Lombok直接操作抽象源代码树,这比生成源代码复杂得多。这里的问题是,Java编译器模块是公开的(Jigsaw)。

另一种替代方法是使用字节码api,比如ByteBuddy,在运行时代理原始类。如果不想为实例化类编写代码,这也需要依赖项注入。这里的魔力是配置类中类型集合的自动连接字段。如果你对此感兴趣,请告诉我。然后我会在这里补充更多细节。

韩捷
2023-03-14

有点晚了:),但一个解决方案可能是在构建过程中使用Byte Buddy的transformer。参见https://github.com/raphw/byte-buddy/tree/master/byte-buddy-maven-plugin.

萧宁
2023-03-14

注释处理器背后的意图是允许开发人员添加新类,而不是替换现有类。也就是说,有一个bug允许您向现有类添加代码。ProjectLombok利用这一点将getter和setter(以及其他内容)添加到编译的java类中。

“替换”方法/字段的方法是从输入类扩展或委托给输入类。这允许您覆盖/转移对目标类的调用。

因此,如果这是您的输入类:

inputinpl。爪哇:

public class InputImpl implements Input{
    public void foo(){
        System.out.println("foo");
    }
    public void bar(){
        System.out.println("bar");
    }
}

您可以生成以下内容来“替换”它:

我mpl.java:

public class InputReplacementImpl implements Input{

    private Input delegate;

    //setup delegate....

    public void foo(){
        System.out.println("foo replacement");
    }
    public void bar(){
        delegate.bar();
    }
}

这就引出了一个问题,如何引用InputReplace ementImpl而不是InputImpl。您可以生成更多代码来执行包装,也可以简单地调用预期生成的代码的构造函数。

我不太确定你的问题是什么,但我希望这能对你的问题有所启发。

 类似资料:
  • 我的处理器中有一个简单的注释,如下所示: 这适用于java文件,但一旦我将文件转换为kotlin,注释的导入就不再有效。为什么? 我需要改变什么才能让他的注释也在Kotlin中工作?从文档中,我可以看到kotlin与java注释100%兼容,所以我有点困惑这里有什么问题...如果处理器不工作,需要调整以与kotlin一起工作,我会理解,但我不知道为什么导入本身不工作... 我说的图书馆在这里:ht

  • 需要注释处理器的帮助。我创建了一个简单的注释处理器,它使用@autoservice注释来检查注释的字段是否为最终字段。但它没有显示任何编译时错误。这是我的配置 注释: 注释处理器: pom文件: 测试文件:

  • 众所周知,我们可以像ProjectLombook的工作人员一样,使用自定义注释和Java注释处理器自动生成代码。但是我们可以从编译的源代码中删除带注释的代码吗? 我试着在网上搜索它,但只出现了“生成代码”主题和“如何生成带有一个注释的服务器”教程。当我在寻找从prod应用程序“编译”调试消息的方法时,我想到了这一点。我可以理解,拥有调试/测试和生产代码不是一个好的实践,但有时需要保持简单。我认为这

  • 我是一名android开发人员,但这对java开发人员来说是一个问题:我在注释处理器行为方面遇到了一些棘手的问题。 现在我一直在开发两个项目:一个-具有自定义注释和处理这些自定义注释的处理器(lib-project)和使用此lib-project(test-project)的测试应用程序。我使用Eclipse IDE作为开发人员工具(ADT)。 我遇到了这样一个麻烦:我的lib项目作为jar li

  • 我喜欢使用Lombok,但它需要在IDEs设置中启用注释处理器。因为开发人员使用不同的IDE,CI/CD有自己的编译流程,而且我真的不想解释初级开发人员为什么需要选中此复选框,我正在寻找一种方法来避免选中此复选框。理想的情况下,我想让一个年轻人来运行git clone,然后/格拉德卢跑。Gradle是否可以完全设置注释处理器(无需手动单击)? 如果它能在比IntelliJ IDEA更多的地方工作,

  • 我正在使用注释处理器来处理方法参数的注释。 用于参数的注释类型有一个注释@参数 现在,当注释处理器运行时,我想检查参数注释()是否有参数注释。我通过执行以下代码来实现这一点。 由于某种原因,arg始终为空。是否有注释未返回的原因?