#import "../_scaffold.html" as main> <@main.scaffold title="Lombok Execution Path">
With javac
(and netbeans, maven, gradle, and most other build systems), lombok runs as an annotation processor.
Lombok is on the classpath, and javac
will load every META-INF/services/javax.annotation.processing.Processor
file on the classpath it can find, reading each line and loading that class, then executing it as an annotation processor. lombok.jar
has this file, it lists lombok.launch.AnnotationProcessorHider$AnnotationProcessor
as entry.
This class is not actually visible (it is public, but its outer class (AnnotationProcessorHider
) is package private, making it invisible to java-the-language), however, it is considered visible for the purposes of java-the-VM and therefore it will run. This convoluted trick is used to ensure that anybody who develops with lombok on the classpath doesn't get lombok's classes or lombok's dependencies injected into their 'namespace' (for example, if you add lombok to your project, your IDE will not start suggesting lombok classes for auto-complete dialogs).
The lombok.launch.AnnotationProcessorHider$AnnotationProcessor
class is loaded by javac
, instantiated, and init()
is called on it. This class starts lombok's ShadowClassLoader
; it finds the jar file it is in, then will start loading classes from this jar file. It looks not for files ending in .class
like normal loaders, it looks for files ending in .SCL.lombok
instead (this too is for the purpose of hiding lombok's classes from IDEs and such). Via this classloader, the real annotation processor is launched, which is class lombok.core.AnnotationProcessor
.
The lombok.core.AnnotationProcessor
is also a delegating processor. It can delegate to one of 2 sub-processors based on the environment lombok finds itself in: If it's javac, class lombok.javac.apt.LombokProcessor
is used (and if the plexus compiler framework is used, which can be the case when compiling with javac, some extra code runs to patch lombok into its modular classloading architecture). If it's ecj (eclipse's compiler, which means we're either running inside eclipse itself, or being invoked as annotation processor for ecj, the standalone eclipse compiler), errors/warnings are injected into the compilation process to tell the user they should use different parameters to use lombok in eclipse/ecj.
lombok.javac.apt.LombokProcessor
is the 'real' annotation processor that does the work of transforming your code.
code transformation is fundamentally a cyclic concept: To generate some code you want to know about the code (which annotations are in it, for example), but when you generate new code, interpreting it means we start over. The same applies to lombok itself: Some of lombok's transformations add methods which then have an effect on other lombok transformations. Because of that, lombok divides up the handlers into 'levels'. All handlers at the highest level are executed, then a new annotation round is forced (which integrates generated stuff into the symbol tables and such), and then the handlers at the next level are executed. These levels are indicated via the @HandlerPriority
annotation. You force javac to run another round by generating a file. We don't actually want to generate any files, so we generate a dummy file and patch the javac filer to not actually save lombok-generated dummy files anywhere. The various HandleX
classes, which apply the actual lombok transformations, are stored in HandlerLibrary
which uses SPI to discover the handle classes.
With ecj
and eclipse
, lombok starts as an 'agent'. That's a bit like a debugger: It lets lombok inspect raw class bytecode before the JVM actually loads these classes, and lombok will modify this code in order to ensure that ecj/eclipse involves lombok in the compilation process.
The patching of classes is done by the code in the src/eclipseAgent
sourcedir. Note that the patching code has to patch equinox, the eclipse module system, to ensure lombok and the java compilation module (The 'JDT' module, in eclipse parlance) can see each other.
A bunch of ad-hoc fixes to issues (such as the eclipse format-my-code feature needing a few tactical bytecode patches to ensure it doesn't mess up formatting source) are applied, but the main 'run lombok as part of the compilation process' hook injected into ecj/eclipse leads to the lombok.eclipse.TransformEclipseAST
class, which can be considered the entrypoint. Unless you want to mess with how lombok is loaded into eclipse/ecj, start there.
Each HandleX
class is discovered via SPI and lombok will invoke the handle classes as needed. Handle classes find lombok annotations and apply the desired transformations. The handlers are in the lombok.eclipse.handlers
package from the src/core
sourcedir.
Lombok support in these two IDEs is taken care of by plugins for these IDEs.