Skip to content

Commit

Permalink
Allow gradle incremental compiling with lombok in annotation processo…
Browse files Browse the repository at this point in the history
…r path

Fixes issue projectlombok#1580
  • Loading branch information
pbi-qfs committed May 3, 2018
1 parent a9aafe2 commit a2623f1
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 21 deletions.
4 changes: 4 additions & 0 deletions build.xml
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,9 @@ the common tasks and can be called on to run the main aspects of all the sub-scr
<echo file="build/lombok/META-INF/services/javax.annotation.processing.Processor">lombok.launch.AnnotationProcessorHider$AnnotationProcessor
lombok.launch.AnnotationProcessorHider$ClaimingProcessor</echo>
<echo file="build/lombok/META-INF/services/org.mapstruct.ap.spi.AstModifyingAnnotationProcessor">lombok.launch.AnnotationProcessorHider$AstModificationNotifier</echo>
<mkdir dir="build/lombok/META-INF/gradle" />
<echo file="build/lombok/META-INF/gradle/incremental.annotation.processors">lombok.launch.AnnotationProcessorHider$AnnotationProcessor,isolating
lombok.launch.AnnotationProcessorHider$ClaimingProcessor,isolating</echo>
</target>

<target name="-latestChanges" depends="version">
Expand Down Expand Up @@ -335,6 +338,7 @@ lombok.launch.AnnotationProcessorHider$ClaimingProcessor</echo>
<include name="lombok/launch/**" />
<include name="lombok/delombok/ant/Tasks*" />
<include name="lombok/javac/apt/Processor.class" />
<include name="lombok/META-INF/**" />
</fileset>
<mappedresources>
<fileset dir="build/lombok">
Expand Down
30 changes: 27 additions & 3 deletions src/core/lombok/core/AnnotationProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
Expand Down Expand Up @@ -63,6 +64,27 @@ static abstract class ProcessorDescriptor {
private final List<ProcessorDescriptor> registered = Arrays.asList(new JavacDescriptor(), new EcjDescriptor());
private final List<ProcessorDescriptor> active = new ArrayList<ProcessorDescriptor>();
private final List<String> delayedWarnings = new ArrayList<String>();

/**
* This method is a simplified version of {@link lombok.javac.apt.LombokProcessor.getJavacProcessingEnvironment}
* It simply returns the processing environment, but in case of gradle incremental compilation,
* the delegate ProcessingEnvironment of the gradle wrapper is returned.
*/
public static ProcessingEnvironment getJavacProcessingEnvironment(ProcessingEnvironment procEnv, List<String> delayedWarnings) {
final Class<? extends ProcessingEnvironment> procEnvClass = procEnv.getClass();
if (procEnvClass.getName().equals("org.gradle.api.internal.tasks.compile.processing.IncrementalProcessingEnvironment")) {
try {
Field field = procEnvClass.getDeclaredField("delegate");
field.setAccessible(true);
Object delegate = field.get(procEnv);
return (ProcessingEnvironment) delegate;
} catch (final Exception e) {
delayedWarnings.add("Can't get the delegate of the gradle IncrementalProcessingEnvironment: " + trace(e));
}
}
return procEnv;
}


static class JavacDescriptor extends ProcessorDescriptor {
private Processor processor;
Expand All @@ -72,10 +94,12 @@ static class JavacDescriptor extends ProcessorDescriptor {
}

@Override boolean want(ProcessingEnvironment procEnv, List<String> delayedWarnings) {
if (!procEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) return false;

ProcessingEnvironment javacProcEnv = getJavacProcessingEnvironment(procEnv, delayedWarnings);

if (!javacProcEnv.getClass().getName().equals("com.sun.tools.javac.processing.JavacProcessingEnvironment")) return false;

try {
ClassLoader classLoader = findAndPatchClassLoader(procEnv);
ClassLoader classLoader = findAndPatchClassLoader(javacProcEnv);
processor = (Processor) Class.forName("lombok.javac.apt.LombokProcessor", false, classLoader).newInstance();
} catch (Exception e) {
delayedWarnings.add("You found a bug in lombok; lombok.javac.apt.LombokProcessor is not available. Lombok will not run during this compilation: " + trace(e));
Expand Down
84 changes: 66 additions & 18 deletions src/core/lombok/javac/apt/LombokProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import java.util.SortedSet;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
Expand Down Expand Up @@ -69,7 +70,9 @@
*/
@SupportedAnnotationTypes("*")
public class LombokProcessor extends AbstractProcessor {
private JavacProcessingEnvironment processingEnv;
private ProcessingEnvironment processingEnv;
private JavacProcessingEnvironment javacProcessingEnv;
private JavacFiler javacFiler;
private JavacTransformer transformer;
private Trees trees;
private boolean lombokDisabled = false;
Expand All @@ -81,11 +84,13 @@ public class LombokProcessor extends AbstractProcessor {
lombokDisabled = true;
return;
}

this.processingEnv = (JavacProcessingEnvironment) procEnv;


this.processingEnv = procEnv;
this.javacProcessingEnv = getJavacProcessingEnvironment(procEnv);
this.javacFiler = getJavacFiler(procEnv.getFiler());

placePostCompileAndDontMakeForceRoundDummiesHook();
trees = Trees.instance(procEnv);
trees = Trees.instance(javacProcessingEnv);
transformer = new JavacTransformer(procEnv.getMessager(), trees);
SortedSet<Long> p = transformer.getPriorities();
if (p.isEmpty()) {
Expand Down Expand Up @@ -124,7 +129,7 @@ private static final Field getFieldAccessor(String typeName, String fieldName) {
@SuppressWarnings("unused")
private String listAnnotationProcessorsBeforeOurs() {
try {
Object discoveredProcessors = javacProcessingEnvironment_discoveredProcs.get(this.processingEnv);
Object discoveredProcessors = javacProcessingEnvironment_discoveredProcs.get(this.javacProcessingEnv);
ArrayList<?> states = (ArrayList<?>) discoveredProcessors_procStateList.get(discoveredProcessors);
if (states == null || states.isEmpty()) return null;
if (states.size() == 1) return processorState_processor.get(states.get(0)).getClass().getName();
Expand All @@ -147,7 +152,7 @@ private void placePostCompileAndDontMakeForceRoundDummiesHook() {
stopJavacProcessingEnvironmentFromClosingOurClassloader();

forceMultipleRoundsInNetBeansEditor();
Context context = processingEnv.getContext();
Context context = javacProcessingEnv.getContext();
disablePartialReparseInNetBeansEditor(context);
try {
Method keyMethod = Context.class.getDeclaredMethod("key", Class.class);
Expand All @@ -161,14 +166,14 @@ private void placePostCompileAndDontMakeForceRoundDummiesHook() {
if (!(originalFiler instanceof InterceptingJavaFileManager)) {
final Messager messager = processingEnv.getMessager();
DiagnosticsReceiver receiver = new MessagerDiagnosticsReceiver(messager);
JavaFileManager newFiler = new InterceptingJavaFileManager(originalFiler, receiver);
ht.put(key, newFiler);

JavaFileManager newFilerManager = new InterceptingJavaFileManager(originalFiler, receiver);
ht.put(key, newFilerManager);
Field filerFileManagerField = JavacFiler.class.getDeclaredField("fileManager");
filerFileManagerField.setAccessible(true);
filerFileManagerField.set(processingEnv.getFiler(), newFiler);
replaceFileManagerJdk9(context, newFiler);
filerFileManagerField.set(javacFiler, newFilerManager);

replaceFileManagerJdk9(context, newFilerManager);
}
} catch (Exception e) {
throw Lombok.sneakyThrow(e);
Expand Down Expand Up @@ -203,7 +208,7 @@ private void forceMultipleRoundsInNetBeansEditor() {
try {
Field f = JavacProcessingEnvironment.class.getDeclaredField("isBackgroundCompilation");
f.setAccessible(true);
f.set(processingEnv, true);
f.set(javacProcessingEnv, true);
} catch (NoSuchFieldException e) {
// only NetBeans has it
} catch (Throwable t) {
Expand Down Expand Up @@ -277,10 +282,10 @@ private void stopJavacProcessingEnvironmentFromClosingOurClassloader() {
try {
Field f = JavacProcessingEnvironment.class.getDeclaredField("processorClassLoader");
f.setAccessible(true);
ClassLoader unwrapped = (ClassLoader) f.get(processingEnv);
ClassLoader unwrapped = (ClassLoader) f.get(javacProcessingEnv);
if (unwrapped == null) return;
ClassLoader wrapped = wrapClassLoader(unwrapped);
f.set(processingEnv, wrapped);
f.set(javacProcessingEnv, wrapped);
} catch (NoSuchFieldException e) {
// Some versions of javac have this (and call close on it), some don't. I guess this one doesn't have it.
} catch (Throwable t) {
Expand Down Expand Up @@ -321,7 +326,7 @@ private void stopJavacProcessingEnvironmentFromClosingOurClassloader() {
if (prioOfCu == null || prioOfCu != prio) continue;
cusForThisRound.add(entry.getKey());
}
transformer.transform(prio, processingEnv.getContext(), cusForThisRound);
transformer.transform(prio, javacProcessingEnv.getContext(), cusForThisRound);
}

// Step 3: Push up all CUs to the next level. Set level to null if there is no next level.
Expand Down Expand Up @@ -349,7 +354,7 @@ private void stopJavacProcessingEnvironmentFromClosingOurClassloader() {
newLevels.retainAll(priorityLevelsRequiringResolutionReset);
if (!newLevels.isEmpty()) {
// Force a new round to reset resolution. The next round will cause this method (process) to be called again.
forceNewRound(randomModuleName, (JavacFiler) processingEnv.getFiler());
forceNewRound(randomModuleName, javacFiler);
return false;
}
// None of the new levels need resolution, so just keep going.
Expand Down Expand Up @@ -399,4 +404,47 @@ private JCCompilationUnit toUnit(Element element) {
@Override public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}

/**
* This class casts the given processing environment to a JavacProcessingEnvironment. In case of
* gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned.
*/
public JavacProcessingEnvironment getJavacProcessingEnvironment(ProcessingEnvironment procEnv) {
final Class<?> procEnvClass = procEnv.getClass();
if (procEnv.getClass().getName().equals("org.gradle.api.internal.tasks.compile.processing.IncrementalProcessingEnvironment")) {
try {
Field field = procEnvClass.getDeclaredField("delegate");
field.setAccessible(true);
Object delegate = field.get(procEnv);
return (JavacProcessingEnvironment) delegate;
} catch (final Exception e) {
e.printStackTrace();
procEnv.getMessager().printMessage(Kind.WARNING,
"Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work.");
}
}
return (JavacProcessingEnvironment) procEnv;
}

/**
* This class casts the given filer to a JavacFiler. In case of
* gradle incremental compilation, the delegate Filer of the gradle wrapper is returned.
*/
public JavacFiler getJavacFiler(Filer filer) {
final Class<?> filerSuperClass = filer.getClass().getSuperclass();
if (filerSuperClass.getName().equals("org.gradle.api.internal.tasks.compile.processing.IncrementalFiler")) {
try {
Field field = filerSuperClass.getDeclaredField("delegate");
field.setAccessible(true);
Object delegate = field.get(filer);
return (JavacFiler) delegate;
} catch (final Exception e) {
e.printStackTrace();
processingEnv.getMessager().printMessage(Kind.WARNING,
"Can't get the delegate of the gradle IncrementalFiler. Lombok won't work.");
}
}
return (JavacFiler) filer;
}

}

0 comments on commit a2623f1

Please sign in to comment.