编写自定义 Lombok 注释处理程序

Writing custom Lombok Annotation handlers

我想编写自定义 Lombok 注释处理程序。我知道http://notatube.blogspot.de/2010/12/project-lombok-creating-custom.html。但是当前的lombok jar文件并不包含很多.class文件,而是包含名为.SCL.lombok的文件。

我发现,.SCL.lombok 文件是.class 文件,Lombok 的构建脚本在生成 jar 文件时确实重命名了它们,而 ShadowClassLoader 能够loading these classes -- 首字母缩写词 SCL 似乎来自于此。看来这样做的原因只是为了 "Avoid contaminating the namespace of any project using an SCL-based jar. Autocompleters in IDEs will NOT suggest anything other than actual public API."

我只能通过

编译自定义处理程序

此外,为了能够使用我的自定义处理程序,我需要创建一个包含 lombok classes 和我的自定义处理程序的新 fat jar。自定义 lombok class 加载器基本上可以防止在其他多个 jar 中添加自定义处理程序。

这是扩展 Lombok 的唯一方法吗?还是我遗漏了什么?

我正在使用以下构建脚本

apply plugin: 'java'

repositories {
    jcenter()
}

configurations {
    lombok
    compileOnly
}

def unpackedAndRenamedLombokDir = file("$buildDir/lombok")

task unpackAndRenameLombok {
    inputs.files configurations.lombok
    outputs.dir unpackedAndRenamedLombokDir
    doFirst {
        mkdir unpackedAndRenamedLombokDir
        delete unpackedAndRenamedLombokDir.listFiles()
    }
    doLast {
        copy {
            from zipTree(configurations.lombok.singleFile)
            into unpackedAndRenamedLombokDir
            rename "(.*)[.]SCL[.]lombok", '.class'
        }
    }
}

sourceSets {
    main {
        compileClasspath += configurations.compileOnly
        output.dir(unpackedAndRenamedLombokDir, builtBy: unpackAndRenameLombok)
    }
}

tasks.compileJava {
    dependsOn unpackAndRenameLombok
}

dependencies {
    compile files("${System.properties['java.home']}/../lib/tools.jar")
    compile "org.eclipse.jdt:org.eclipse.jdt.core:3.10.0"
    compile 'javax.inject:javax.inject:1'
    lombok 'org.projectlombok:lombok:1.16.6'

    compileOnly files(unpackedAndRenamedLombokDir)
}

同时 Reinier Zwitserloot 创建了一个新的 git-branch sclExpansionUpdate, that contains an updated version of the ShadowClassLoader:

ShadowClassLoader is now friendlier to trying to extend lombok.

Your (separate) jar/dir should have a file named META-INF/ShadowClassLoader. This file should contain the string 'lombok'. If you have that, any classes in that jar/dir will be loaded in the same space as lombok classes. You can also rename the class files to .SCL.lombok to avoid other loaders from finding them.

我想这还没有进入主分支,因为它肯定没有经过太多测试 - 我只是自己尝试了一下,它包含一个小错误,阻止加载所需的 META-INF/services从扩展。要修复它,您应该将对 partOfShadow 的两个方法调用替换为 inOwnBase:

[... line 443]
Enumeration<URL> sec = super.getResources(name);
while (sec.hasMoreElements()) {
    URL item = sec.nextElement();
    if (!inOwnBase(item, name)) vector.add(item); // <<-- HERE
}

if (altName != null) {
    Enumeration<URL> tern = super.getResources(altName);
    while (tern.hasMoreElements()) {
        URL item = tern.nextElement();
        if (!inOwnBase(item, altName)) vector.add(item); // <<-- AND HERE
    }
}

我用上面的修复程序测试了它,它似乎工作正常(虽然没有测试太多)。

旁注:有了这个新的扩展机制,现在终于可以在与 "lombok" 不同的命名空间中使用扩展注解处理程序和注解了 - 太好了!

使用来自这个问题和另一个答案(由 Balder 提供)的输入,我们设法组合了一个自定义 Lombok 注释处理程序:Symbok。随意使用它作为编写您自己的示例。

顺便说一句,除了编写自定义 Lombok 处理程序,您还可以实现一个 javac plugin instead —— 它可能更简单。