Skip to content

Commit

Permalink
Centralize Lombok initialization logic (#5033)
Browse files Browse the repository at this point in the history
* Centralize Lombok initialization logic

The logic to initialize the Lombok annotation processor is now moved to the `rewrite-java-lombok` project and used by all Java parsers.

* Polish

* Polish

* Restore check for Lombok support in Java 1.8 parser
  • Loading branch information
knutwannheden authored Feb 13, 2025
1 parent 4e1a9dd commit 33284be
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 232 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@

import org.jspecify.annotations.Nullable;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
Expand Down Expand Up @@ -64,6 +67,24 @@ public static boolean isClassAvailable(String fullyQualifiedClassName) {
return null;
}

public static List<Path> findClassPathEntriesFor(String resourceName, ClassLoader classLoader) {
List<Path> classPathEntries = new ArrayList<>();
try {
Enumeration<URL> resources = classLoader.getResources(resourceName);
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
if (resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) {
classPathEntries.add(Paths.get(URI.create(resource.getPath().substring(0, resource.getPath().indexOf("!")))));
} else if (resource.getProtocol().equals("file")) {
classPathEntries.add(Paths.get(resource.getPath().substring(0, resource.getPath().indexOf(resourceName))));
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return classPathEntries;
}

private static Method[] getDeclaredMethods(Class<?> clazz) {
Method[] result = DECLARED_METHODS_CACHE.get(clazz);
if (result == null) {
Expand Down
2 changes: 1 addition & 1 deletion rewrite-java-11/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ val javaTck = configurations.create("javaTck") {
dependencies {
api(project(":rewrite-core"))
api(project(":rewrite-java"))
runtimeOnly(project(":rewrite-java-lombok"))
implementation(project(":rewrite-java-lombok"))

compileOnly("org.slf4j:slf4j-api:1.7.+")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
import org.openrewrite.InMemoryExecutionContext;
import org.openrewrite.SourceFile;
import org.openrewrite.internal.MetricsHelper;
import org.openrewrite.internal.StringUtils;
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaParsingException;
import org.openrewrite.java.internal.JavaTypeCache;
import org.openrewrite.java.lombok.LombokSupport;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Space;
import org.openrewrite.style.NamedStyles;
Expand All @@ -53,20 +53,16 @@
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardLocation;
import java.io.*;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;

/**
Expand Down Expand Up @@ -123,62 +119,17 @@ private ReloadableJava11Parser(
// for all other source files and unaffected nodes within the same file.
Options.instance(context).put("should-stop.ifError", "GENERATE");

LOMBOK:
if (classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok-1.18.37"))) {
Processor lombokProcessor = null;
annotationProcessors = new ArrayList<>(1);
if (classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) {
try {
// https://projectlombok.org/contributing/lombok-execution-path
List<String> overrideClasspath = new ArrayList<>();
for (Path part : classpath) {
if (part.toString().contains("lombok-1.18.37") || part.toString().contains("rewrite-java-lombok")) {
overrideClasspath.add(part.toString());
}
}
// make sure the rewrite-java-lombok dependency comes first
boolean found = false;
for (int i = 0; i < overrideClasspath.size(); i++) {
if (overrideClasspath.get(i).contains("rewrite-java-lombok")) {
overrideClasspath.add(0, overrideClasspath.remove(i));
found = true;
}
Processor lombokProcessor = LombokSupport.createLombokProcessor(getClass().getClassLoader());
if (lombokProcessor != null) {
Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor");
annotationProcessors.add(lombokProcessor);
}
if (!found) {
// try to find `rewrite-java-lombok` using class loader
URL resource = getClass().getClassLoader().getResource("org/openrewrite/java/lombok/OpenRewriteConfigurationKeysLoader.class");
if (resource != null && resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) {
String path = Paths.get(URI.create(resource.getPath().substring(0, resource.getPath().indexOf("!")))).toString();
overrideClasspath.add(0, path);
} else {
break LOMBOK;
}
}
System.setProperty("shadow.override.lombok", String.join(File.pathSeparator, overrideClasspath));

Class<?> shadowLoaderClass = Class.forName("lombok.launch.ShadowClassLoader", true, getClass().getClassLoader());
Constructor<?> shadowLoaderConstructor = shadowLoaderClass.getDeclaredConstructor(
Class.forName("java.lang.ClassLoader"),
Class.forName("java.lang.String"),
Class.forName("java.lang.String"),
Class.forName("java.util.List"),
Class.forName("java.util.List"));
shadowLoaderConstructor.setAccessible(true);

ClassLoader lombokShadowLoader = (ClassLoader) shadowLoaderConstructor.newInstance(
getClass().getClassLoader(),
"lombok",
null,
emptyList(),
singletonList("lombok.patcher.Symbols")
);
lombokProcessor = (Processor) lombokShadowLoader.loadClass("lombok.core.AnnotationProcessor").getDeclaredConstructor().newInstance();
Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor");
} catch (ReflectiveOperationException ignore) {
// Lombok was not found or could not be initialized
} finally {
annotationProcessors = lombokProcessor != null ? singletonList(lombokProcessor) : emptyList();
}
} else {
annotationProcessors = emptyList();
}

// MUST be created ahead of compiler construction
Expand Down
2 changes: 1 addition & 1 deletion rewrite-java-17/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ val javaTck = configurations.create("javaTck") {
dependencies {
api(project(":rewrite-core"))
api(project(":rewrite-java"))
runtimeOnly(project(":rewrite-java-lombok"))
implementation(project(":rewrite-java-lombok"))

compileOnly("org.slf4j:slf4j-api:1.7.+")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaParsingException;
import org.openrewrite.java.internal.JavaTypeCache;
import org.openrewrite.java.lombok.LombokSupport;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Space;
import org.openrewrite.style.NamedStyles;
Expand All @@ -52,19 +53,15 @@
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardLocation;
import java.io.*;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;

/**
Expand Down Expand Up @@ -121,62 +118,17 @@ private ReloadableJava17Parser(
// for all other source files and unaffected nodes within the same file.
Options.instance(context).put("should-stop.ifError", "GENERATE");

LOMBOK:
if (classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok-1.18.37"))) {
Processor lombokProcessor = null;
annotationProcessors = new ArrayList<>(1);
if (classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) {
try {
// https://projectlombok.org/contributing/lombok-execution-path
List<String> overrideClasspath = new ArrayList<>();
for (Path part : classpath) {
if (part.toString().contains("lombok-1.18.37") || part.toString().contains("rewrite-java-lombok")) {
overrideClasspath.add(part.toString());
}
}
// make sure the rewrite-java-lombok dependency comes first
boolean found = false;
for (int i = 0; i < overrideClasspath.size(); i++) {
if (overrideClasspath.get(i).contains("rewrite-java-lombok")) {
overrideClasspath.add(0, overrideClasspath.remove(i));
found = true;
}
Processor lombokProcessor = LombokSupport.createLombokProcessor(getClass().getClassLoader());
if (lombokProcessor != null) {
Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor");
annotationProcessors.add(lombokProcessor);
}
if (!found) {
// try to find `rewrite-java-lombok` using class loader
URL resource = getClass().getClassLoader().getResource("org/openrewrite/java/lombok/OpenRewriteConfigurationKeysLoader.class");
if (resource != null && resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) {
String path = Paths.get(URI.create(resource.getPath().substring(0, resource.getPath().indexOf("!")))).toString();
overrideClasspath.add(0, path);
} else {
break LOMBOK;
}
}
System.setProperty("shadow.override.lombok", String.join(File.pathSeparator, overrideClasspath));

Class<?> shadowLoaderClass = Class.forName("lombok.launch.ShadowClassLoader", true, getClass().getClassLoader());
Constructor<?> shadowLoaderConstructor = shadowLoaderClass.getDeclaredConstructor(
Class.forName("java.lang.ClassLoader"),
Class.forName("java.lang.String"),
Class.forName("java.lang.String"),
Class.forName("java.util.List"),
Class.forName("java.util.List"));
shadowLoaderConstructor.setAccessible(true);

ClassLoader lombokShadowLoader = (ClassLoader) shadowLoaderConstructor.newInstance(
getClass().getClassLoader(),
"lombok",
null,
emptyList(),
singletonList("lombok.patcher.Symbols")
);
lombokProcessor = (Processor) lombokShadowLoader.loadClass("lombok.core.AnnotationProcessor").getDeclaredConstructor().newInstance();
Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor");
} catch (ReflectiveOperationException ignore) {
// Lombok was not found or could not be initialized
} finally {
annotationProcessors = lombokProcessor != null ? singletonList(lombokProcessor) : emptyList();
}
} else {
annotationProcessors = emptyList();
}

// MUST be created (registered with the context) after pfm and compilerLog
Expand Down
2 changes: 1 addition & 1 deletion rewrite-java-21/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ val javaTck = configurations.create("javaTck") {
dependencies {
api(project(":rewrite-core"))
api(project(":rewrite-java"))
runtimeOnly(project(":rewrite-java-lombok"))
implementation(project(":rewrite-java-lombok"))

compileOnly("org.slf4j:slf4j-api:1.7.+")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.openrewrite.java.JavaParser;
import org.openrewrite.java.JavaParsingException;
import org.openrewrite.java.internal.JavaTypeCache;
import org.openrewrite.java.lombok.LombokSupport;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.Space;
import org.openrewrite.style.NamedStyles;
Expand All @@ -52,19 +53,15 @@
import javax.tools.SimpleJavaFileObject;
import javax.tools.StandardLocation;
import java.io.*;
import java.lang.reflect.Constructor;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;

/**
Expand Down Expand Up @@ -121,62 +118,17 @@ private ReloadableJava21Parser(
// for all other source files and unaffected nodes within the same file.
Options.instance(context).put("should-stop.ifError", "GENERATE");

LOMBOK:
if (classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok-1.18.37"))) {
Processor lombokProcessor = null;
annotationProcessors = new ArrayList<>(1);
if (classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) {
try {
// https://projectlombok.org/contributing/lombok-execution-path
List<String> overrideClasspath = new ArrayList<>();
for (Path part : classpath) {
if (part.toString().contains("lombok-1.18.37") || part.toString().contains("rewrite-java-lombok")) {
overrideClasspath.add(part.toString());
}
}
// make sure the rewrite-java-lombok dependency comes first
boolean found = false;
for (int i = 0; i < overrideClasspath.size(); i++) {
if (overrideClasspath.get(i).contains("rewrite-java-lombok")) {
overrideClasspath.add(0, overrideClasspath.remove(i));
found = true;
}
Processor lombokProcessor = LombokSupport.createLombokProcessor(getClass().getClassLoader());
if (lombokProcessor != null) {
Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor");
annotationProcessors.add(lombokProcessor);
}
if (!found) {
// try to find `rewrite-java-lombok` using class loader
URL resource = getClass().getClassLoader().getResource("org/openrewrite/java/lombok/OpenRewriteConfigurationKeysLoader.class");
if (resource != null && resource.getProtocol().equals("jar") && resource.getPath().startsWith("file:")) {
String path = Paths.get(URI.create(resource.getPath().substring(0, resource.getPath().indexOf("!")))).toString();
overrideClasspath.add(0, path);
} else {
break LOMBOK;
}
}
System.setProperty("shadow.override.lombok", String.join(File.pathSeparator, overrideClasspath));

Class<?> shadowLoaderClass = Class.forName("lombok.launch.ShadowClassLoader", true, getClass().getClassLoader());
Constructor<?> shadowLoaderConstructor = shadowLoaderClass.getDeclaredConstructor(
Class.forName("java.lang.ClassLoader"),
Class.forName("java.lang.String"),
Class.forName("java.lang.String"),
Class.forName("java.util.List"),
Class.forName("java.util.List"));
shadowLoaderConstructor.setAccessible(true);

ClassLoader lombokShadowLoader = (ClassLoader) shadowLoaderConstructor.newInstance(
getClass().getClassLoader(),
"lombok",
null,
emptyList(),
singletonList("lombok.patcher.Symbols")
);
lombokProcessor = (Processor) lombokShadowLoader.loadClass("lombok.core.AnnotationProcessor").getDeclaredConstructor().newInstance();
Options.instance(context).put(Option.PROCESSOR, "lombok.launch.AnnotationProcessorHider$AnnotationProcessor");
} catch (ReflectiveOperationException ignore) {
// Lombok was not found or could not be initialized
} finally {
annotationProcessors = lombokProcessor != null ? singletonList(lombokProcessor) : emptyList();
}
} else {
annotationProcessors = emptyList();
}

// MUST be created (registered with the context) after pfm and compilerLog
Expand Down
2 changes: 1 addition & 1 deletion rewrite-java-8/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ dependencies {
compileOnly("org.slf4j:slf4j-api:1.7.+")

implementation(project(":rewrite-java"))
runtimeOnly(project(":rewrite-java-lombok"))
implementation(project(":rewrite-java-lombok"))
implementation("org.ow2.asm:asm:latest.release")

implementation("io.micrometer:micrometer-core:1.9.+")
Expand Down
Loading

0 comments on commit 33284be

Please sign in to comment.