Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing custom Lombok Annotation handlers

Tags:

java

lombok

I want to write custom Lombok Annotation handlers. I know http://notatube.blogspot.de/2010/12/project-lombok-creating-custom.html. But the current lombok jar file does not contain many .class files, but files named .SCL.lombok instead.

I found, the .SCL.lombok files are the .class files, the build script of Lombok does rename them while generating the jar file, and the ShadowClassLoader is capable of loading these classes -- and the acronym SCL seems to come from this. It seems the reason for this is just to "Avoid contaminating the namespace of any project using an SCL-based jar. Autocompleters in IDEs will NOT suggest anything other than actual public API."

I was only able to compile my custom handler by

  • unpacking the contents of the lombok.jar
  • renaming the .SCL.lombok files to .class
  • adding the resulting directory to the compile classpath

In addition, to be able to use my custom handler, I needed to create a new fat jar containing both the lombok classes and my custom handler. The custom lombok class loader essentially prevents adding custom handlers in other multiple jars.

Is this the only way to extend Lombok? Or am I missing something?

I am using the following buildscript

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", '$1.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) } 
like image 819
Tobias Schulte Avatar asked Feb 22 '16 09:02

Tobias Schulte


People also ask

How do I enable annotation processing on Lombok?

Annotation processing isn't enabled by default, though. We need to go to the Preferences | Build, Execution, Deployment | Compiler | Annotation Processors and make sure of the following: Enable annotation processing box is checked. Obtain processors from project classpath option is selected.

What is the use of @data in Lombok?

@Data is a convenient shortcut annotation that bundles the features of @ToString , @EqualsAndHashCode , @Getter / @Setter and @RequiredArgsConstructor together: In other words, @Data generates all the boilerplate that is normally associated with simple POJOs (Plain Old Java Objects) and beans: getters for all fields, ...


1 Answers

In the meantime Reinier Zwitserloot created a new 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.

I guess this did not yet make it into the main branch because it certainly has not been tested that much - I just tried it out for myself and it contains a little bug that prevents loading the required META-INF/services from extensions. To fix it you should replace two method calls to partOfShadow with 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     } } 

I tested it with the above fix and it seems to work fine (not tested much though).

On a side note: with this new extension mechanism, it is now finally also possible to have the extensions annotation handlers and annotations in a different namespace than "lombok" - nice!

like image 71
Balder Avatar answered Oct 13 '22 13:10

Balder