From 761c2ea7b70d6c8366788943dabf3bf615e7332d Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 10:50:43 +0100 Subject: [PATCH 01/26] Support Lombok for java 8 --- .../java/ReloadableJava8Parser.java | 174 +++++++++++++----- .../java/ReloadableJava8ParserVisitor.java | 141 ++++++++++---- .../org/openrewrite/java/package-info.java | 21 +++ 3 files changed, 261 insertions(+), 75 deletions(-) create mode 100644 rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index de46c937d0a..080339b12a7 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -18,12 +18,15 @@ import com.sun.tools.javac.comp.*; import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.main.JavaCompiler; +import com.sun.tools.javac.main.Option; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Timer; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -40,12 +43,17 @@ import org.openrewrite.tree.ParseError; import org.openrewrite.tree.ParsingEventListener; import org.openrewrite.tree.ParsingExecutionContextView; +import org.slf4j.LoggerFactory; +import javax.annotation.processing.Processor; import javax.tools.*; 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.function.Function; @@ -53,6 +61,9 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; +import static com.sun.tools.javac.util.List.nil; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; class ReloadableJava8Parser implements JavaParser { @@ -70,6 +81,7 @@ class ReloadableJava8Parser implements JavaParser { private final JavaCompiler compiler; private final ResettableLog compilerLog; private final Collection styles; + private final List annotationProcessors; ReloadableJava8Parser(@Nullable Collection classpath, Collection classBytesClasspath, @@ -100,6 +112,70 @@ class ReloadableJava8Parser implements JavaParser { Options.instance(context).put("-g", "-g"); Options.instance(context).put("-proc", "none"); + // Ensure type attribution continues despite errors in individual files or nodes. + // If an error occurs in a single file or node, type attribution should still proceed + // for all other source files and unaffected nodes within the same file. + Options.instance(context).put("should-stop.ifError", "GENERATE"); + + LOMBOK: + if (System.getenv().getOrDefault("REWRITE_LOMBOK", System.getProperty("rewrite.lombok")) != null && + classpath != null && classpath.stream().anyMatch(it -> it.toString().contains("lombok"))) { + Processor lombokProcessor = null; + try { + // https://projectlombok.org/contributing/lombok-execution-path + List overrideClasspath = new ArrayList<>(); + for (Path part : classpath) { + if (part.toString().contains("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; + } + } + 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 compiler = new JavaCompiler(context); @@ -118,7 +194,7 @@ public void write(char[] cbuf, int off, int len) { if (logCompilationWarningsAndErrors) { String log = new String(Arrays.copyOfRange(cbuf, off, len)); if (!StringUtils.isBlank(log)) { - org.slf4j.LoggerFactory.getLogger(ReloadableJava8Parser.class).warn(log); + LoggerFactory.getLogger(ReloadableJava8Parser.class).warn(log); } } } @@ -138,45 +214,7 @@ public void close() { @Override public Stream parseInputs(Iterable sourceFiles, @Nullable Path relativeTo, ExecutionContext ctx) { ParsingEventListener parsingListener = ParsingExecutionContextView.view(ctx).getParsingListener(); - if (classpath != null) { // override classpath - if (context.get(JavaFileManager.class) != pfm) { - throw new IllegalStateException("JavaFileManager has been forked unexpectedly"); - } - - try { - pfm.setLocation(StandardLocation.CLASS_PATH, classpath.stream().map(Path::toFile).collect(toList())); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @SuppressWarnings("ConstantConditions") LinkedHashMap cus = acceptedInputs(sourceFiles) - .collect(Collectors.toMap( - Function.identity(), - input -> { - try { - return compiler.parse(new Java8ParserInputFileObject(input, ctx)); - } catch (IllegalStateException e) { - if ("endPosTable already set".equals(e.getMessage())) { - throw new IllegalStateException( - "Call reset() on JavaParser before parsing another set of source files that " + - "have some of the same fully qualified names. Source file [" + - input.getPath() + "]\n[\n" + StringUtils.readFully(input.getSource(ctx), getCharset(ctx)) + "\n]", e); - } - throw e; - } - }, - (e2, e1) -> e1, LinkedHashMap::new)); - - try { - enterAll(cus.values()); - compiler.attribute(new TimedTodo(compiler.todo)); - } catch (Throwable t) { - // when symbol entering fails on problems like missing types, attribution can often times proceed - // unhindered, but it sometimes cannot (so attribution is always a BEST EFFORT in the presence of errors) - ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); - } - + LinkedHashMap cus = parseInputsToCompilerAst(sourceFiles, ctx); return cus.entrySet().stream().map(cuByPath -> { Input input = cuByPath.getKey(); parsingListener.startedParsing(input); @@ -190,6 +228,7 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat ctx, context); J.CompilationUnit cu = (J.CompilationUnit) parser.scan(cuByPath.getValue(), Space.EMPTY); + //noinspection DataFlowIssue cuByPath.setValue(null); // allow memory used by this JCCompilationUnit to be released parsingListener.parsed(input, cu); return requirePrintEqualsInput(cu, input, relativeTo, ctx); @@ -200,6 +239,56 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat }); } + private @NotNull LinkedHashMap parseInputsToCompilerAst(Iterable sourceFiles, ExecutionContext ctx) { + if (classpath != null) { // override classpath + if (context.get(JavaFileManager.class) != pfm) { + throw new IllegalStateException("JavaFileManager has been forked unexpectedly"); + } + + try { + pfm.setLocation(StandardLocation.CLASS_PATH, classpath.stream().map(Path::toFile).collect(toList())); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + LinkedHashMap cus = new LinkedHashMap<>(); + List inputFileObjects = acceptedInputs(sourceFiles) + .map(input -> new Java8ParserInputFileObject(input, ctx)) + .collect(toList()); + if (!annotationProcessors.isEmpty()) { + // TODO there is no `initialFiles` argument in Java 8; first let's see if it works without it before trying to figure out if we really need a workaround. + compiler.initProcessAnnotations(annotationProcessors/*, inputFileObjects, emptyList()*/); + } + try { + //noinspection unchecked + com.sun.tools.javac.util.List jcCompilationUnits = compiler.parseFiles((List) (List) inputFileObjects); + for (int i = 0; i < inputFileObjects.size(); i++) { + cus.put(inputFileObjects.get(i).getInput(), jcCompilationUnits.get(i)); + } + try { + enterAll(cus.values()); + if (!annotationProcessors.isEmpty()) { + compiler.processAnnotations(jcCompilationUnits, nil()); + } + compiler.attribute(new TimedTodo(compiler.todo)); + } catch (Throwable t) { + // when symbol entering fails on problems like missing types, attribution can often times proceed + // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) + ctx.getOnError().accept(new JavaParsingException("Failed symbol entering or attribution", t)); + } + } catch (IllegalStateException e) { + if ("endPosTable already set".equals(e.getMessage())) { + throw new IllegalStateException( + "Call reset() on JavaParser before parsing another set of source files that " + + "have some of the same fully qualified names.", e); + } + throw e; + } + + return cus; + } + @Override public ReloadableJava8Parser reset() { typeCache.clear(); @@ -332,6 +421,7 @@ public Iterable list(Location location, String packageName, Set< private static class PackageAwareJavaFileObject extends SimpleJavaFileObject { private final String pkg; + @Getter private final String className; private final byte[] classBytes; @@ -365,10 +455,6 @@ public String getPackage() { return pkg; } - public String getClassName() { - return className; - } - @Override public InputStream openInputStream() { return new ByteArrayInputStream(classBytes); diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 8a502fd31b8..cff11006581 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -17,6 +17,7 @@ import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; +import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DCTree; @@ -33,7 +34,6 @@ import org.openrewrite.internal.EncodingDetectingInputStream; import org.openrewrite.internal.ListUtils; import org.openrewrite.java.internal.JavaTypeCache; -import org.openrewrite.java.JavaPrinter; import org.openrewrite.java.marker.OmitParentheses; import org.openrewrite.java.tree.*; import org.openrewrite.marker.Markers; @@ -338,7 +338,7 @@ public J visitCase(CaseTree node, Space fmt) { node.getExpression() == null ? EMPTY : sourceBefore("case"), singletonList(node.getExpression() == null ? JRightPadded.build(new J.Identifier(randomId(), Space.EMPTY, Markers.EMPTY, emptyList(), skip("default"), null, null)) : - JRightPadded.build(convertOrNull(node.getExpression())) + JRightPadded.build(convert(node.getExpression())) ), Markers.EMPTY ), @@ -390,7 +390,7 @@ public J visitClass(ClassTree node, Space fmt) { Markers.EMPTY); JLeftPadded extendings = node.getExtendsClause() == null ? null : - padLeft(sourceBefore("extends"), convertOrNull(node.getExtendsClause())); + padLeft(sourceBefore("extends"), convert(node.getExtendsClause())); JContainer implementings = null; if (node.getImplementsClause() != null && !node.getImplementsClause().isEmpty()) { @@ -640,7 +640,7 @@ public J visitForLoop(ForLoopTree node, Space fmt) { commaDelim.apply(t) ); - JRightPadded condition = convertOrNull(node.getCondition(), semiDelim); + JRightPadded condition = convert(node.getCondition(), semiDelim); if (condition == null) { condition = padRight(new J.Empty(randomId(), sourceBefore(";"), Markers.EMPTY), EMPTY); } @@ -908,7 +908,7 @@ public J visitMethod(MethodTree node, Space fmt) { } List returnTypeAnnotations = collectAnnotations(annotationPosTable); - TypeTree returnType = convertOrNull(node.getReturnType()); + TypeTree returnType = convert(node.getReturnType()); if (returnType != null && !returnTypeAnnotations.isEmpty()) { returnType = new J.AnnotatedType(randomId(), Space.EMPTY, Markers.EMPTY, returnTypeAnnotations, returnType); @@ -951,7 +951,7 @@ public J visitMethod(MethodTree node, Space fmt) { JContainer.build(sourceBefore("throws"), convertAll(node.getThrows(), commaDelim, noDelim), Markers.EMPTY); - J.Block body = convertOrNull(node.getBody()); + J.Block body = convert(node.getBody()); JLeftPadded defaultValue = node.getDefaultValue() == null ? null : padLeft(sourceBefore("default"), convert(node.getDefaultValue())); @@ -975,9 +975,9 @@ public J visitNewArray(NewArrayTree node, Space fmt) { while (elementType instanceof JCArrayTypeTree) { elementType = ((JCArrayTypeTree) elementType).elemtype; } - typeExpr = convertOrNull(elementType); + typeExpr = convert(elementType); } else { - typeExpr = convertOrNull(jcVarType); + typeExpr = convert(jcVarType); } List nodeDimensions = node.getDimensions(); @@ -1027,7 +1027,7 @@ public J visitNewClass(NewClassTree node, Space fmt) { } // for enum definitions with anonymous class initializers, endPos of node identifier will be -1 - TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convertOrNull(node.getIdentifier()) : null; + TypeTree clazz = endPos(node.getIdentifier()) >= 0 ? convert(node.getIdentifier()) : null; JContainer args; if (positionOfNext("(", '{') > -1) { @@ -1135,7 +1135,8 @@ public J visitPrimitiveType(PrimitiveTypeTree node, Space fmt) { @Override public J visitReturn(ReturnTree node, Space fmt) { skip("return"); - return new J.Return(randomId(), fmt, Markers.EMPTY, convertOrNull(node.getExpression())); + Expression expression = convert(node.getExpression()); + return new J.Return(randomId(), fmt, Markers.EMPTY, expression); } @Override @@ -1478,8 +1479,22 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm List typeExprAnnotations = collectAnnotations(annotationPosTable); TypeTree typeExpr; - if (vartype == null || endPos(vartype) < 0 || vartype instanceof JCErroneous) { - typeExpr = null; // this is a lambda parameter with an inferred type expression + if (vartype == null || vartype instanceof JCErroneous) { + typeExpr = null; + } else if (endPos(vartype) < 0) { + if ((node.sym.flags() & Flags.PARAMETER) > 0) { + // this is a lambda parameter with an inferred type expression + typeExpr = null; + } else { + boolean lombokVal = isLombokVal(node); + typeExpr = new J.Identifier(randomId(), + sourceBefore(lombokVal ? "val" : "var"), + Markers.build(singletonList(JavaVarKeyword.build())), + emptyList(), + lombokVal ? "val" : "var", + typeMapping.type(vartype), + null); + } } else if (vartype instanceof JCArrayTypeTree) { JCExpression elementType = vartype; while (elementType instanceof JCArrayTypeTree || elementType instanceof JCAnnotatedType) { @@ -1516,10 +1531,9 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm List> vars = new ArrayList<>(nodes.size()); for (int i = 0; i < nodes.size(); i++) { - VariableTree n = nodes.get(i); + JCVariableDecl n = (JCVariableDecl) nodes.get(i); Space namedVarPrefix = sourceBefore(n.getName().toString()); - JCVariableDecl vd = (JCVariableDecl) n; JavaType type = typeMapping.type(n); J.Identifier name = new J.Identifier(randomId(), EMPTY, Markers.EMPTY, emptyList(), n.getName().toString(), @@ -1532,7 +1546,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm new J.VariableDeclarations.NamedVariable(randomId(), namedVarPrefix, Markers.EMPTY, name, dimensionsAfterName, - vd.init != null ? padLeft(sourceBefore("="), convertOrNull(vd.init)) : null, + n.init != null ? padLeft(sourceBefore("="), convert(n.init)) : null, (JavaType.Variable) typeMapping.type(n) ), i == nodes.size() - 1 ? EMPTY : sourceBefore(",") @@ -1589,7 +1603,7 @@ public J visitWildcard(WildcardTree node, Space fmt) { bound = null; } - return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convertOrNull(wildcard.inner)); + return new J.Wildcard(randomId(), fmt, Markers.EMPTY, bound, convert(wildcard.inner)); } /** @@ -1598,9 +1612,12 @@ public J visitWildcard(WildcardTree node, Space fmt) { * -------------- */ - private J2 convert(Tree t) { + private @Nullable J2 convert(@Nullable Tree t) { + if (t == null) { + return null; + } try { - String prefix = source.substring(cursor, max(((JCTree) t).getStartPosition(), cursor)); + String prefix = source.substring(cursor, Math.max(cursor, getActualStartPosition((JCTree) t))); cursor += prefix.length(); @SuppressWarnings("unchecked") J2 j = (J2) scan(t, formatWithCommentTree(prefix, (JCTree) t, docCommentTable.getCommentTree((JCTree) t))); return j; @@ -1630,13 +1647,24 @@ private J2 convert(Tree t) { } } - private JRightPadded convert(Tree t, Function suffix) { + private static int getActualStartPosition(JCTree t) { + // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation + if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); + } + return t.getStartPosition(); + } + + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix) { + if (t == null) { + return null; + } J2 j = convert(t); @SuppressWarnings("ConstantConditions") JRightPadded rightPadded = j == null ? null : new JRightPadded<>(j, suffix.apply(t), Markers.EMPTY); int idx = findFirstNonWhitespaceChar(rightPadded.getAfter().getWhitespace()); if (idx >= 0) { - rightPadded = (JRightPadded) JRightPadded.build(getErroneous(Collections.singletonList(rightPadded))); + rightPadded = (JRightPadded) JRightPadded.build(getErroneous(singletonList(rightPadded))); } // Cursor hasn't been updated but points at the end of erroneous node already // This means that error node start position == end position @@ -1681,14 +1709,6 @@ private long lineNumber(Tree tree) { return lineNumber; } - private @Nullable T convertOrNull(@Nullable Tree t) { - return t == null ? null : convert(t); - } - - private @Nullable JRightPadded convertOrNull(@Nullable Tree t, Function suffix) { - return t == null ? null : convert(t, suffix); - } - private List convertAll(List trees) { List converted = new ArrayList<>(trees.size()); for (Tree tree : trees) { @@ -1800,6 +1820,9 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { + if (isLombokGenerated(t)) { + continue; + } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); } @@ -1829,6 +1852,53 @@ private List> convertStatements(@Nullable List collectAnnotations(Map annotat boolean inMultilineComment = false; for (int i = cursor; i <= maxAnnotationPosition && i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { - annotations.add(convert(annotationPosTable.get(i))); + JCAnnotation jcAnnotation = annotationPosTable.get(i); + if (isLombokGenerated(jcAnnotation)) { + continue; + } + annotations.add(convert(jcAnnotation)); i = cursor; continue; } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java b/rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java new file mode 100644 index 00000000000..e697a3e66c4 --- /dev/null +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/package-info.java @@ -0,0 +1,21 @@ +/* + * Copyright 2020 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@NullMarked +@NonNullFields +package org.openrewrite.java; + +import org.jspecify.annotations.NullMarked; +import org.openrewrite.internal.lang.NonNullFields; From 7cb644f9e90f9e2c3b1771749b4899b96c969eee Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 11:31:07 +0100 Subject: [PATCH 02/26] Support Lombok for java 8 --- .../java/org/openrewrite/java/ReloadableJava8Parser.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index 080339b12a7..495103100a8 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -26,7 +26,6 @@ import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Timer; import lombok.Getter; -import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; @@ -56,8 +55,6 @@ import java.nio.file.Paths; import java.util.*; import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -239,7 +236,7 @@ public Stream parseInputs(Iterable sourceFiles, @Nullable Pat }); } - private @NotNull LinkedHashMap parseInputsToCompilerAst(Iterable sourceFiles, ExecutionContext ctx) { + LinkedHashMap parseInputsToCompilerAst(Iterable sourceFiles, ExecutionContext ctx) { if (classpath != null) { // override classpath if (context.get(JavaFileManager.class) != pfm) { throw new IllegalStateException("JavaFileManager has been forked unexpectedly"); From 69984bae2d699667c71b49efd2c0cbda71a39b01 Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 11:46:09 +0100 Subject: [PATCH 03/26] Support Lombok for java 8 --- .../org/openrewrite/java/tree/LombokTest.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 6a355210012..f8514b03ca3 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -34,7 +34,7 @@ import static org.openrewrite.java.Assertions.java; @SuppressWarnings({"CaughtExceptionImmediatelyRethrown", "LombokGetterMayBeUsed", "LombokSetterMayBeUsed", "DefaultAnnotationParam", "NotNullFieldNotInitialized", "ProtectedMemberInFinalClass", "WriteOnlyObject", "ConcatenationWithEmptyString"}) -@EnabledOnJre({JRE.JAVA_11, JRE.JAVA_17, JRE.JAVA_21}) +@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_17, JRE.JAVA_21}) class LombokTest implements RewriteTest { @BeforeAll @@ -459,6 +459,23 @@ void m() { ); } + @Test + void var() { + rewriteRun( + java( + """ + import lombok.var; + + class Test { + void test() { + var s = "foo"; + } + } + """ + ) + ); + } + @Test void val() { rewriteRun( From 12986eb7a4cc336a44f16edf04d7a1e83a6a9732 Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 13:44:02 +0100 Subject: [PATCH 04/26] Add rewrite-java-lombok to classpath --- rewrite-java-8/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/rewrite-java-8/build.gradle.kts b/rewrite-java-8/build.gradle.kts index 5f92a5f85dd..e07e976892e 100644 --- a/rewrite-java-8/build.gradle.kts +++ b/rewrite-java-8/build.gradle.kts @@ -17,6 +17,7 @@ dependencies { compileOnly("org.slf4j:slf4j-api:1.7.+") implementation(project(":rewrite-java")) + runtimeOnly(project(":rewrite-java-lombok")) implementation("org.ow2.asm:asm:latest.release") implementation("io.micrometer:micrometer-core:1.9.+") From e284bf532c41a15c1286ab0aa6cc9fd73be79775 Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 14:32:38 +0100 Subject: [PATCH 05/26] Improve message --- .../main/java/org/openrewrite/java/ReloadableJava8Parser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index 495103100a8..0a7963b22f2 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -254,7 +254,7 @@ LinkedHashMap parseInputsToCompilerAst(Iterable .map(input -> new Java8ParserInputFileObject(input, ctx)) .collect(toList()); if (!annotationProcessors.isEmpty()) { - // TODO there is no `initialFiles` argument in Java 8; first let's see if it works without it before trying to figure out if we really need a workaround. + // TODO there is neither a `initialFiles` nor `initialClassNames` argument in Java 8, so we need some workaround to make this work compiler.initProcessAnnotations(annotationProcessors/*, inputFileObjects, emptyList()*/); } try { From 80e9ead9e5f831d75e12cee9fed621bd5463b64e Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 15:10:24 +0100 Subject: [PATCH 06/26] Remove `TimedTodo` to be more like the other java parsers --- .../java/ReloadableJava8Parser.java | 34 +------------------ 1 file changed, 1 insertion(+), 33 deletions(-) diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index 0a7963b22f2..e97d62a37df 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -23,8 +23,6 @@ import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; -import io.micrometer.core.instrument.Metrics; -import io.micrometer.core.instrument.Timer; import lombok.Getter; import org.jspecify.annotations.Nullable; import org.objectweb.asm.ClassReader; @@ -33,7 +31,6 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.InMemoryExecutionContext; import org.openrewrite.SourceFile; -import org.openrewrite.internal.MetricsHelper; import org.openrewrite.internal.StringUtils; import org.openrewrite.java.internal.JavaTypeCache; import org.openrewrite.java.tree.J; @@ -268,7 +265,7 @@ LinkedHashMap parseInputsToCompilerAst(Iterable if (!annotationProcessors.isEmpty()) { compiler.processAnnotations(jcCompilationUnits, nil()); } - compiler.attribute(new TimedTodo(compiler.todo)); + compiler.attribute(compiler.todo); } catch (Throwable t) { // when symbol entering fails on problems like missing types, attribution can often times proceed // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) @@ -347,35 +344,6 @@ public void reset(Collection uris) { } } - private static class TimedTodo extends Todo { - private final Todo todo; - private Timer.@Nullable Sample sample; - - private TimedTodo(Todo todo) { - super(new Context()); - this.todo = todo; - } - - @Override - public boolean isEmpty() { - if (sample != null) { - sample.stop(MetricsHelper.successTags( - Timer.builder("rewrite.parse") - .description("The time spent by the JDK in type attributing the source file") - .tag("file.type", "Java") - .tag("step", "(2) Type attribution")) - .register(Metrics.globalRegistry)); - } - return todo.isEmpty(); - } - - @Override - public Env remove() { - this.sample = Timer.start(); - return todo.remove(); - } - } - private static class ByteArrayCapableJavacFileManager extends JavacFileManager { private final List classByteClasspath; From 7a9fb18f9a6def347b17853e6284a7143e7d7323 Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 16:18:30 +0100 Subject: [PATCH 07/26] cleanup --- .../main/java/org/openrewrite/java/ReloadableJava8Parser.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index e97d62a37df..b844de1ad9b 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -251,8 +251,7 @@ LinkedHashMap parseInputsToCompilerAst(Iterable .map(input -> new Java8ParserInputFileObject(input, ctx)) .collect(toList()); if (!annotationProcessors.isEmpty()) { - // TODO there is neither a `initialFiles` nor `initialClassNames` argument in Java 8, so we need some workaround to make this work - compiler.initProcessAnnotations(annotationProcessors/*, inputFileObjects, emptyList()*/); + compiler.initProcessAnnotations(annotationProcessors); } try { //noinspection unchecked From 1531ca470eebd9b965c46593d70fbf9070109745 Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 16:35:26 +0100 Subject: [PATCH 08/26] Add JavaCompiler `delegate` fix --- .../java/org/openrewrite/java/ReloadableJava8Parser.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java index b844de1ad9b..bad6fc19a4d 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8Parser.java @@ -261,10 +261,8 @@ LinkedHashMap parseInputsToCompilerAst(Iterable } try { enterAll(cus.values()); - if (!annotationProcessors.isEmpty()) { - compiler.processAnnotations(jcCompilationUnits, nil()); - } - compiler.attribute(compiler.todo); + JavaCompiler delegate = annotationProcessors.isEmpty() ? compiler : compiler.processAnnotations(jcCompilationUnits, nil()); + delegate.attribute(delegate.todo); } catch (Throwable t) { // when symbol entering fails on problems like missing types, attribution can often times proceed // unhindered, but it sometimes cannot (so attribution is always best-effort in the presence of errors) From b15c51d37d65ce3bd06837b9059afc93b590cd7f Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 17:20:28 +0100 Subject: [PATCH 09/26] Support Lomboks `var` and `val` for Java 8 --- .../ReloadableJava11ParserVisitor.java | 4 +- .../ReloadableJava17ParserVisitor.java | 4 +- .../ReloadableJava21ParserVisitor.java | 4 +- .../java/ReloadableJava8ParserVisitor.java | 39 +++++++++---------- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index b8dd7a5d14f..549ce10de7e 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -1889,8 +1889,8 @@ private static boolean isLombokGenerated(@Nullable Symbol sym) { if (sym == null) { return false; } - // Lombok val is represented as a @lombok.val on a "final" modifier, neither which appear in source - if ("lombok.val".equals(sym.getQualifiedName().toString())) { + // Lombok local variables are represented as `final @lombok.val` and `@lombok.var`, which do not appear in source + if ("lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString())) { return true; } if (sym.getMetadata() == null) { diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 9f56bfb0b3c..f1aa1fd008b 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -1970,8 +1970,8 @@ private static boolean isLombokGenerated(@Nullable Symbol sym) { if (sym == null) { return false; } - // Lombok val is represented as a @lombok.val on a "final" modifier, neither which appear in source - if ("lombok.val".equals(sym.getQualifiedName().toString())) { + // Lombok local variables are represented as `final @lombok.val` and `@lombok.var`, which do not appear in source + if ("lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString())) { return true; } if (sym.getMetadata() == null) { diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index c1c20fd3ff4..523735380f2 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -1970,8 +1970,8 @@ private static boolean isLombokGenerated(@Nullable Symbol sym) { if (sym == null) { return false; } - // Lombok val is represented as a @lombok.val on a "final" modifier, neither which appear in source - if ("lombok.val".equals(sym.getQualifiedName().toString())) { + // Lombok local variables are represented as `final @lombok.val` and `@lombok.var`, which do not appear in source + if ("lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString())) { return true; } if (sym.getMetadata() == null) { diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index cff11006581..c0945be1c36 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -1479,22 +1479,19 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm List typeExprAnnotations = collectAnnotations(annotationPosTable); TypeTree typeExpr; - if (vartype == null || vartype instanceof JCErroneous) { - typeExpr = null; - } else if (endPos(vartype) < 0) { - if ((node.sym.flags() & Flags.PARAMETER) > 0) { - // this is a lambda parameter with an inferred type expression - typeExpr = null; - } else { - boolean lombokVal = isLombokVal(node); - typeExpr = new J.Identifier(randomId(), - sourceBefore(lombokVal ? "val" : "var"), - Markers.build(singletonList(JavaVarKeyword.build())), - emptyList(), - lombokVal ? "val" : "var", - typeMapping.type(vartype), - null); - } + if (vartype == null || endPos(vartype) < 0 || vartype instanceof JCErroneous) { + typeExpr = null; // this is a lambda parameter with an inferred type expression*/ + } else if (isLombokValOrVar(node)) { + Space space = whitespace(); + boolean lombokVal = source.substring(cursor).startsWith("val"); + cursor += 3; + typeExpr = new J.Identifier(randomId(), + space, + Markers.build(singletonList(JavaVarKeyword.build())), + emptyList(), + lombokVal ? "val" : "var", + typeMapping.type(vartype), + null); } else if (vartype instanceof JCArrayTypeTree) { JCExpression elementType = vartype; while (elementType instanceof JCArrayTypeTree || elementType instanceof JCAnnotatedType) { @@ -1649,7 +1646,7 @@ public J visitWildcard(WildcardTree node, Space fmt) { private static int getActualStartPosition(JCTree t) { // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + if (t instanceof JCVariableDecl && isLombokValOrVar((JCVariableDecl) t)) { return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); } return t.getStartPosition(); @@ -1852,10 +1849,10 @@ private List> convertStatements(@Nullable List Date: Tue, 7 Jan 2025 17:25:31 +0100 Subject: [PATCH 10/26] Cleanup --- .../java/isolated/ReloadableJava11ParserVisitor.java | 1 - .../java/isolated/ReloadableJava17ParserVisitor.java | 1 - .../java/isolated/ReloadableJava21ParserVisitor.java | 1 - .../org/openrewrite/java/ReloadableJava8ParserVisitor.java | 5 ++--- 4 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 549ce10de7e..3d4c1b6d5fe 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -2079,7 +2079,6 @@ private ReloadableJava11ModifierResults sortedModifiersAndAnnotations(ModifiersT for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { JCAnnotation jcAnnotation = annotationPosTable.get(i); - // Skip over lombok's "@val" annotation which does not actually appear in source if (isLombokGenerated(jcAnnotation.getAnnotationType())) { continue; } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index f1aa1fd008b..79143712122 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -2162,7 +2162,6 @@ private ReloadableJava17ModifierResults sortedModifiersAndAnnotations(ModifiersT for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { JCAnnotation jcAnnotation = annotationPosTable.get(i); - // Skip over lombok's "@val" annotation which does not actually appear in source if (isLombokGenerated(jcAnnotation.getAnnotationType())) { continue; } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index 523735380f2..a2340d8181c 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -2162,7 +2162,6 @@ private ReloadableJava21ModifierResults sortedModifiersAndAnnotations(ModifiersT for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { JCAnnotation jcAnnotation = annotationPosTable.get(i); - // Skip over lombok's "@val" annotation which does not actually appear in source if (isLombokGenerated(jcAnnotation.getAnnotationType())) { continue; } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index c0945be1c36..cb11ff8d2ab 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -1480,11 +1480,11 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm TypeTree typeExpr; if (vartype == null || endPos(vartype) < 0 || vartype instanceof JCErroneous) { - typeExpr = null; // this is a lambda parameter with an inferred type expression*/ + typeExpr = null; // this is a lambda parameter with an inferred type expression } else if (isLombokValOrVar(node)) { Space space = whitespace(); boolean lombokVal = source.substring(cursor).startsWith("val"); - cursor += 3; + cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), space, Markers.build(singletonList(JavaVarKeyword.build())), @@ -2071,7 +2071,6 @@ private Java8ModifierResults sortedModifiersAndAnnotations(ModifiersTree modifie for (int i = cursor; i < source.length(); i++) { if (annotationPosTable.containsKey(i)) { JCAnnotation jcAnnotation = annotationPosTable.get(i); - // Skip over lombok's "@val" annotation which does not actually appear in source if (isLombokGenerated(jcAnnotation.getAnnotationType())) { continue; } From da9de0c1750fa3ceff6cae9710f4926aed8b52c7 Mon Sep 17 00:00:00 2001 From: lingenj Date: Tue, 7 Jan 2025 17:28:00 +0100 Subject: [PATCH 11/26] Cleanup --- .../src/main/java/org/openrewrite/java/tree/LombokTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index f8514b03ca3..89f5e218b1e 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -34,7 +34,6 @@ import static org.openrewrite.java.Assertions.java; @SuppressWarnings({"CaughtExceptionImmediatelyRethrown", "LombokGetterMayBeUsed", "LombokSetterMayBeUsed", "DefaultAnnotationParam", "NotNullFieldNotInitialized", "ProtectedMemberInFinalClass", "WriteOnlyObject", "ConcatenationWithEmptyString"}) -@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_11, JRE.JAVA_17, JRE.JAVA_21}) class LombokTest implements RewriteTest { @BeforeAll From 71a2e13ea4140293718e51762f7a8f8172d2f49e Mon Sep 17 00:00:00 2001 From: lingenj Date: Wed, 8 Jan 2025 12:18:48 +0100 Subject: [PATCH 12/26] Cleanup of `isLombokGenerated` methods --- .../ReloadableJava17ParserVisitor.java | 39 +++++++----------- .../java/ReloadableJava8ParserVisitor.java | 40 ++++++++----------- 2 files changed, 31 insertions(+), 48 deletions(-) diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 79143712122..6129db1bafd 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -27,6 +27,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; +import lombok.Generated; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; @@ -1572,9 +1573,11 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - boolean lombokVal = isLombokVal(node); + Space space = whitespace(); + boolean lombokVal = source.substring(cursor).startsWith("val"); + cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), - sourceBefore(lombokVal ? "val" : "var"), + space, Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), lombokVal ? "val" : "var", @@ -1723,8 +1726,8 @@ public J visitWildcard(WildcardTree node, Space fmt) { } private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + // The variable's start position in the source is wrongly after lombok's `@val` annotation + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); } return t.getStartPosition(); @@ -1906,7 +1909,7 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { - if (isLombokGenerated(t)) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { continue; } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); @@ -1938,17 +1941,6 @@ private List> convertStatements(@Nullable List nodes, Space fm TypeTree typeExpr; if (vartype == null || endPos(vartype) < 0 || vartype instanceof JCErroneous) { typeExpr = null; // this is a lambda parameter with an inferred type expression - } else if (isLombokValOrVar(node)) { + } else if (isLombokGenerated(node)) { Space space = whitespace(); boolean lombokVal = source.substring(cursor).startsWith("val"); cursor += 3; // skip `val` or `var` @@ -1646,7 +1647,7 @@ public J visitWildcard(WildcardTree node, Space fmt) { private static int getActualStartPosition(JCTree t) { // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokValOrVar((JCVariableDecl) t)) { + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); } return t.getStartPosition(); @@ -1817,7 +1818,7 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { - if (isLombokGenerated(t)) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { continue; } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); @@ -1849,17 +1850,6 @@ private List> convertStatements(@Nullable List".equals(((JCMethodDecl) t).getName().toString())) { + for (JCAnnotation ann : ((JCMethodDecl) t).getModifiers().getAnnotations()) { + if ("@lombok.Generated()".equals(ann.toString())) { + return true; + } + } + } } else if (t instanceof JCTree.JCClassDecl) { sym = ((JCClassDecl) t).sym; } else if (t instanceof JCTree.JCVariableDecl) { sym = ((JCVariableDecl) t).sym; } - return isLombokGenerated(sym); - } - private static boolean isLombokGenerated(@Nullable Symbol sym) { if (sym == null) { return false; } - // Lombok local variables are represented as `final @lombok.val` and `@lombok.var`, which do not appear in source + + // Matches the added `@val` / `@var` JCIdent and JCAnnotation elements if ("lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString())) { return true; } - if (sym.getMetadata() == null) { - return false; - } + for (Attribute.Compound a : sym.getDeclarationAttributes()) { - if ("lombok.Generated".equals(a.type.toString())) { + if ("lombok.val".equals(a.type.toString()) || "lombok.var".equals(a.type.toString())) { return true; } } - return false; + + return sym.getAnnotation(Generated.class) != null; } /** From 6a8c5c67243ae967307b64171daf7313f27b1778 Mon Sep 17 00:00:00 2001 From: lingenj Date: Wed, 8 Jan 2025 15:13:51 +0100 Subject: [PATCH 13/26] Cleanup of `isLombokGenerated` methods --- .../ReloadableJava11ParserVisitor.java | 52 ++++++------------- .../ReloadableJava17ParserVisitor.java | 25 +++------ .../ReloadableJava21ParserVisitor.java | 52 ++++++------------- .../java/ReloadableJava8ParserVisitor.java | 31 ++++------- 4 files changed, 51 insertions(+), 109 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 3d4c1b6d5fe..84c830201e2 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -27,6 +27,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; +import lombok.Generated; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; @@ -1493,9 +1494,11 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - boolean lombokVal = isLombokVal(node); + Space space = whitespace(); + boolean lombokVal = source.substring(cursor).startsWith("val"); + cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), - sourceBefore(lombokVal ? "val" : "var"), + space, Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), lombokVal ? "val" : "var", @@ -1659,8 +1662,8 @@ public J visitWildcard(WildcardTree node, Space fmt) { } private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + // The variable's start position in the source is wrongly after lombok's `@val` annotation + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); } return t.getStartPosition(); @@ -1825,7 +1828,7 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { - if (isLombokGenerated(t)) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { continue; } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); @@ -1857,22 +1860,12 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())) || + sym.getAnnotation(Generated.class) != null + ); } /** diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 6129db1bafd..b20b01fed1f 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -1942,10 +1942,11 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())) || + sym.getAnnotation(Generated.class) != null + ); } /** diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index a2340d8181c..bd3a36a63dc 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -27,6 +27,7 @@ import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.Context; +import lombok.Generated; import org.jspecify.annotations.Nullable; import org.openrewrite.Cursor; import org.openrewrite.ExecutionContext; @@ -1572,9 +1573,11 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm // this is a lambda parameter with an inferred type expression typeExpr = null; } else { - boolean lombokVal = isLombokVal(node); + Space space = whitespace(); + boolean lombokVal = source.substring(cursor).startsWith("val"); + cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), - sourceBefore(lombokVal ? "val" : "var"), + space, Markers.build(singletonList(JavaVarKeyword.build())), emptyList(), lombokVal ? "val" : "var", @@ -1723,8 +1726,8 @@ public J visitWildcard(WildcardTree node, Space fmt) { } private static int getActualStartPosition(JCTree t) { - // not sure if this is a bug in Lombok, but the variable's start position is after the `val` annotation - if (t instanceof JCVariableDecl && isLombokVal((JCVariableDecl) t)) { + // The variable's start position in the source is wrongly after lombok's `@val` annotation + if (t instanceof JCVariableDecl && isLombokGenerated(t)) { return ((JCVariableDecl) t).mods.annotations.get(0).getStartPosition(); } return t.getStartPosition(); @@ -1906,7 +1909,7 @@ private List> convertStatements(@Nullable List> treesGroupedByStartPosition = new LinkedHashMap<>(); for (Tree t : trees) { - if (isLombokGenerated(t)) { + if (!(t instanceof JCVariableDecl) && isLombokGenerated(t)) { continue; } treesGroupedByStartPosition.computeIfAbsent(((JCTree) t).getStartPosition(), k -> new ArrayList<>(1)).add(t); @@ -1938,22 +1941,12 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())) || + sym.getAnnotation(Generated.class) != null + ); } /** diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 1fe1b5ac548..dec3c6f905a 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -54,8 +54,7 @@ import java.util.stream.Collectors; import static java.lang.Math.max; -import static java.util.Collections.emptyList; -import static java.util.Collections.singletonList; +import static java.util.Collections.*; import static java.util.stream.Collectors.toList; import static java.util.stream.StreamSupport.stream; import static org.openrewrite.Tree.randomId; @@ -1851,15 +1850,17 @@ private List> convertStatements(@Nullable List".equals(((JCMethodDecl) t).getName().toString())) { + if (sym == null) { + // In java 8 code, a JCMethodDecl does not always have a symbol, so retrieve the possible @Generated annotation differently for (JCAnnotation ann : ((JCMethodDecl) t).getModifiers().getAnnotations()) { if ("@lombok.Generated()".equals(ann.toString())) { return true; @@ -1872,22 +1873,12 @@ private static boolean isLombokGenerated(Tree t) { sym = ((JCVariableDecl) t).sym; } - if (sym == null) { - return false; - } - - // Matches the added `@val` / `@var` JCIdent and JCAnnotation elements - if ("lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString())) { - return true; - } - - for (Attribute.Compound a : sym.getDeclarationAttributes()) { - if ("lombok.val".equals(a.type.toString()) || "lombok.var".equals(a.type.toString())) { - return true; - } - } - - return sym.getAnnotation(Generated.class) != null; + //noinspection ConstantConditions + return sym != null && ( + "lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString()) || + sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString()) || "lombok.var".equals(a.type.toString())) || + sym.getAnnotation(Generated.class) != null + ); } /** From 1959b5c4d35c20c68987e6ad8ae5f4c8061c6de4 Mon Sep 17 00:00:00 2001 From: lingenj Date: Wed, 8 Jan 2025 15:19:45 +0100 Subject: [PATCH 14/26] Cleanup of `isLombokGenerated` methods --- .../java/isolated/ReloadableJava11ParserVisitor.java | 7 ++----- .../java/isolated/ReloadableJava17ParserVisitor.java | 7 ++----- .../java/isolated/ReloadableJava21ParserVisitor.java | 7 ++----- .../org/openrewrite/java/ReloadableJava8ParserVisitor.java | 2 +- 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 84c830201e2..6e9a9b5f6a2 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -1874,14 +1874,11 @@ private static boolean isLombokGenerated(Tree t) { sym = ((JCClassDecl) t).sym; } else if (t instanceof JCTree.JCVariableDecl) { sym = ((JCVariableDecl) t).sym; + return sym != null && sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString())); } //noinspection ConstantConditions - return sym != null && ( - "lombok.val".equals(sym.getQualifiedName().toString()) || - sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString())) || - sym.getAnnotation(Generated.class) != null - ); + return sym != null && ("lombok.val".equals(sym.getQualifiedName().toString()) || sym.getAnnotation(Generated.class) != null); } /** diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index b20b01fed1f..6cb7445a81d 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -1955,14 +1955,11 @@ private static boolean isLombokGenerated(Tree t) { sym = ((JCClassDecl) t).sym; } else if (t instanceof JCTree.JCVariableDecl) { sym = ((JCVariableDecl) t).sym; + return sym != null && sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString())); } //noinspection ConstantConditions - return sym != null && ( - "lombok.val".equals(sym.getQualifiedName().toString()) || - sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString())) || - sym.getAnnotation(Generated.class) != null - ); + return sym != null && ("lombok.val".equals(sym.getQualifiedName().toString()) || sym.getAnnotation(Generated.class) != null); } /** diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index bd3a36a63dc..a869d80f230 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -1955,14 +1955,11 @@ private static boolean isLombokGenerated(Tree t) { sym = ((JCClassDecl) t).sym; } else if (t instanceof JCTree.JCVariableDecl) { sym = ((JCVariableDecl) t).sym; + return sym != null && sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString())); } //noinspection ConstantConditions - return sym != null && ( - "lombok.val".equals(sym.getQualifiedName().toString()) || - sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString())) || - sym.getAnnotation(Generated.class) != null - ); + return sym != null && ("lombok.val".equals(sym.getQualifiedName().toString()) || sym.getAnnotation(Generated.class) != null); } /** diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index dec3c6f905a..188443df5ad 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -1871,12 +1871,12 @@ private static boolean isLombokGenerated(Tree t) { sym = ((JCClassDecl) t).sym; } else if (t instanceof JCTree.JCVariableDecl) { sym = ((JCVariableDecl) t).sym; + return sym != null && sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString()) || "lombok.var".equals(a.type.toString())); } //noinspection ConstantConditions return sym != null && ( "lombok.val".equals(sym.getQualifiedName().toString()) || "lombok.var".equals(sym.getQualifiedName().toString()) || - sym.getDeclarationAttributes().stream().anyMatch(a -> "lombok.val".equals(a.type.toString()) || "lombok.var".equals(a.type.toString())) || sym.getAnnotation(Generated.class) != null ); } From a21fbbd9d18937503d4a1b68583f2f774d7f2e6c Mon Sep 17 00:00:00 2001 From: lingenj Date: Wed, 8 Jan 2025 15:23:49 +0100 Subject: [PATCH 15/26] Cleanup of `isLombokGenerated` methods --- .../ReloadableJava11ParserVisitor.java | 20 ++++++++--------- .../ReloadableJava17ParserVisitor.java | 20 ++++++++--------- .../ReloadableJava21ParserVisitor.java | 20 ++++++++--------- .../java/ReloadableJava8ParserVisitor.java | 22 +++++++++---------- 4 files changed, 37 insertions(+), 45 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 6e9a9b5f6a2..52695fcc840 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -1861,19 +1861,17 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())); } diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 6cb7445a81d..c1deda1fe7d 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -1942,19 +1942,17 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())); } diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index a869d80f230..576bf9f9a44 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -1942,19 +1942,17 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString())); } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 188443df5ad..018ed78749b 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -1850,27 +1850,25 @@ private List> convertStatements(@Nullable List "lombok.val".equals(a.type.toString()) || "lombok.var".equals(a.type.toString())); } From 5dc7963c487cdff0429e5722e8b4063db3feb92f Mon Sep 17 00:00:00 2001 From: lingenj Date: Wed, 8 Jan 2025 15:30:23 +0100 Subject: [PATCH 16/26] Cleanup of `isLombokGenerated` methods --- .../openrewrite/java/ReloadableJava8ParserVisitor.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 018ed78749b..d7f3a5c25fa 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -15,6 +15,7 @@ */ package org.openrewrite.java; +import com.sun.org.apache.xalan.internal.xsltc.compiler.sym; import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; import com.sun.tools.javac.code.Attribute; @@ -1858,12 +1859,8 @@ private static boolean isLombokGenerated(Tree t) { } else if (tree instanceof JCTree.JCMethodDecl) { sym = ((JCMethodDecl) tree).sym; if (sym == null) { - // In java 8 code, a JCMethodDecl does not always have a symbol, so retrieve the possible @Generated annotation differently - for (JCAnnotation ann : ((JCMethodDecl) tree).getModifiers().getAnnotations()) { - if ("@lombok.Generated()".equals(ann.toString())) { - return true; - } - } + // In java 8 code, a JCMethodDecl does not always have a symbol, so check the possible @Generated annotation directly + return ((JCMethodDecl) tree).getModifiers().getAnnotations().stream().anyMatch(a -> "@lombok.Generated()".equals(a.toString())); } } else if (tree instanceof JCTree.JCClassDecl) { sym = ((JCClassDecl) tree).sym; From baf98bb1c3573ca9759f1f5137b45cf1f381cb33 Mon Sep 17 00:00:00 2001 From: lingenj Date: Wed, 8 Jan 2025 15:32:37 +0100 Subject: [PATCH 17/26] Cleanup --- .../src/main/java/org/openrewrite/java/tree/LombokTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 89f5e218b1e..bb0c5739d06 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -19,8 +19,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledOnJre; -import org.junit.jupiter.api.condition.JRE; import org.openrewrite.java.JavaParser; import org.openrewrite.java.search.FindMissingTypes; import org.openrewrite.test.RecipeSpec; @@ -436,7 +434,7 @@ public class SingularExample { } @Test - void jul() { + void log() { rewriteRun( java( """ From 1b6173e377b24c1914f79515c84889768794a6ac Mon Sep 17 00:00:00 2001 From: lingenj Date: Wed, 8 Jan 2025 17:21:27 +0100 Subject: [PATCH 18/26] Improve `onConstructor` and `onConstructorNoArgs` args --- .../org/openrewrite/java/tree/LombokTest.java | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index bb0c5739d06..1c2c1d7d3b8 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -748,24 +748,25 @@ public class ExampleException extends Exception { @Test void onConstructor() { rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { - assert o instanceof FindMissingTypes.MissingTypeResult; - FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; - // type attribution is missing for annotation args, as it was intentionally removed for processing. - return result.getPath().startsWith("Identifier->Annotation->"); - }).build()), + java( + """ + public @interface Inject {} + public @interface Id {} + public @interface Column { + String name(); + } + public @interface Max { + long value(); + } + """ + ), java( """ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; - import javax.inject.Inject; - import javax.persistence.Id; - import javax.persistence.Column; - import javax.validation.constraints.Max; - - @AllArgsConstructor(onConstructor=@__(@Inject)) + @AllArgsConstructor(onConstructor_=@Inject) //JDK8 public class OnXExample { @Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8 @Setter(onParam_=@Max(10000)) //JDK8 @@ -785,15 +786,11 @@ public void test() { @Test void onConstructorNoArgs() { rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { - assert o instanceof FindMissingTypes.MissingTypeResult; - FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; - if (result.getJ() instanceof J.Identifier identifier) { - // type attribution is missing for annotation args, as it was intentionally removed for processing. - return identifier.getSimpleName().equals("__") || identifier.getSimpleName().equals("Inject"); - } - return false; - }).build()), + java( + """ + public @interface Inject {} + """ + ), java( """ import lombok.NoArgsConstructor; @@ -802,8 +799,8 @@ void onConstructorNoArgs() { import javax.inject.Inject; - @NoArgsConstructor(onConstructor = @__(@Inject)) - @RequiredArgsConstructor(onConstructor = @__(@Inject)) + @NoArgsConstructor(onConstructor_ = @Inject) + @RequiredArgsConstructor(onConstructor_ = @Inject) public class OnXExample { @NonNull private Long unid; From ddde9b09bbb3d740054b60097bd995908d1b2cbb Mon Sep 17 00:00:00 2001 From: lingenj Date: Thu, 9 Jan 2025 09:48:21 +0100 Subject: [PATCH 19/26] Fix missing `onConstructor_` check --- .../org/openrewrite/java/lombok/AllArgsConstructorHandler.java | 1 - .../org/openrewrite/java/lombok/NoArgsConstructorHandler.java | 3 ++- .../java/lombok/RequiredArgsConstructorHandler.java | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java index b629bee724a..b4b04d39c1d 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/AllArgsConstructorHandler.java @@ -40,7 +40,6 @@ public void handle(AnnotationValues annotationValues, JCTree JCTree.JCIdent ident = (JCTree.JCIdent) assign.getVariable(); String name = ident.getName().toString(); if (name.equals("onConstructor") || name.equals("onConstructor_")) { - // In Java 1.8+ the parameter is `onConstructor_` continue; } } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java index b5942688f46..1acfcfb96a1 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/NoArgsConstructorHandler.java @@ -38,7 +38,8 @@ public void handle(AnnotationValues annotationValues, JCTree. if (originalArg instanceof JCTree.JCAssign && ((JCTree.JCAssign) originalArg).getVariable() instanceof JCTree.JCIdent) { JCTree.JCAssign assign = (JCTree.JCAssign) originalArg; JCTree.JCIdent ident = (JCTree.JCIdent) assign.getVariable(); - if ("onConstructor".equals(ident.getName().toString())) { + String name = ident.getName().toString(); + if (name.equals("onConstructor") || name.equals("onConstructor_")) { continue; } } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java index e20877acf3d..c376de6bf22 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/RequiredArgsConstructorHandler.java @@ -38,7 +38,8 @@ public void handle(AnnotationValues annotationValues, J if (originalArg instanceof JCTree.JCAssign && ((JCTree.JCAssign) originalArg).getVariable() instanceof JCTree.JCIdent) { JCTree.JCAssign assign = (JCTree.JCAssign) originalArg; JCTree.JCIdent ident = (JCTree.JCIdent) assign.getVariable(); - if ("onConstructor".equals(ident.getName().toString())) { + String name = ident.getName().toString(); + if (name.equals("onConstructor") || name.equals("onConstructor_")) { continue; } } From 6b3d7640f50b99bd38cf3b87a3cf64d24f39cd7f Mon Sep 17 00:00:00 2001 From: lingenj Date: Thu, 9 Jan 2025 16:28:43 +0100 Subject: [PATCH 20/26] Cleanup --- .../ReloadableJava11ParserVisitor.java | 1 - .../ReloadableJava17ParserVisitor.java | 1 - .../ReloadableJava21ParserVisitor.java | 1 - .../java/ReloadableJava8ParserVisitor.java | 5 +- .../org/openrewrite/java/tree/LombokTest.java | 126 ++++++++++++++++-- 5 files changed, 118 insertions(+), 16 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 52695fcc840..80a21b245b4 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -18,7 +18,6 @@ import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DCTree; diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index c1deda1fe7d..67064f140d7 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -19,7 +19,6 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DocCommentTable; diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index 576bf9f9a44..6a8b640c47c 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -19,7 +19,6 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DocCommentTable; diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index d7f3a5c25fa..1cd039d5fff 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -15,10 +15,8 @@ */ package org.openrewrite.java; -import com.sun.org.apache.xalan.internal.xsltc.compiler.sym; import com.sun.source.tree.*; import com.sun.source.util.TreePathScanner; -import com.sun.tools.javac.code.Attribute; import com.sun.tools.javac.code.Flags; import com.sun.tools.javac.code.Symbol; import com.sun.tools.javac.tree.DCTree; @@ -55,7 +53,8 @@ import java.util.stream.Collectors; import static java.lang.Math.max; -import static java.util.Collections.*; +import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; import static java.util.stream.StreamSupport.stream; import static org.openrewrite.Tree.randomId; diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 1c2c1d7d3b8..b29b3703c68 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -20,7 +20,7 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.java.JavaParser; -import org.openrewrite.java.search.FindMissingTypes; +import org.openrewrite.java.MinimumJava11; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import org.openrewrite.test.TypeValidation; @@ -245,6 +245,12 @@ public class ConstructorExample { public static class NoArgsExample { @NonNull private String field; } + + public void test() { + ConstructorExample x = ConstructorExample.of("desc"); + ConstructorExample y = new ConstructorExample<>("1L"); + ConstructorExample.NoArgsExample z = new ConstructorExample.NoArgsExample(); + } } """ ) @@ -710,6 +716,7 @@ public void both(String s) { } @Test + @MinimumJava11 void jacksonized() { rewriteRun( spec -> spec.parser(JavaParser.fromJavaVersion().classpath("jackson-annotations", "lombok")), @@ -746,18 +753,15 @@ public class ExampleException extends Exception { } @Test + @MinimumJava11 void onConstructor() { rewriteRun( java( """ public @interface Inject {} public @interface Id {} - public @interface Column { - String name(); - } - public @interface Max { - long value(); - } + public @interface Column { String name(); } + public @interface Max { long value(); } """ ), java( @@ -766,10 +770,10 @@ void onConstructor() { import lombok.Getter; import lombok.Setter; - @AllArgsConstructor(onConstructor_=@Inject) //JDK8 + @AllArgsConstructor(onConstructor_=@Inject) public class OnXExample { - @Getter(onMethod_={@Id, @Column(name="unique-id")}) //JDK8 - @Setter(onParam_=@Max(10000)) //JDK8 + @Getter(onMethod_={@Id, @Column(name="unique-id")}) + @Setter(onParam_=@Max(10000)) private long unid; public void test() { @@ -784,6 +788,7 @@ public void test() { } @Test + @MinimumJava11 void onConstructorNoArgs() { rewriteRun( java( @@ -821,6 +826,107 @@ public void test() { @SuppressWarnings("MismatchedReadAndWriteOfArray") @Nested class LessSupported { + /* + java 8 cannot figure out all type checking: + - When the @AllArgsConstructorHandler, @NoArgsConstructorHandler and @NoArgsConstructorHandler annotations are + used with the `onConstructor_` param, Lombok does not call the JavacAnnotationHandlers. + - The @Jacksonized annotation does somehow turns into `ClassDeclaration->CompilationUni` error + */ + + @Test + // TODO: Find solution and remove this test + void jacksonizedForJava8() { + rewriteRun( + spec -> spec + .parser(JavaParser.fromJavaVersion().classpath("jackson-annotations", "lombok")) + .typeValidationOptions(TypeValidation.none()), + java( + """ + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import lombok.Builder; + import lombok.extern.jackson.Jacksonized; + + @Jacksonized + @Builder + @JsonIgnoreProperties(ignoreUnknown = true) + public class JacksonExample { + private List strings; + } + """ + ) + ); + } + + @Test + // TODO: Find solution and remove this test + void onConstructorForJava8() { + rewriteRun( + spec -> spec.typeValidationOptions(TypeValidation.none()), + java( + """ + public @interface Inject {} + public @interface Id {} + public @interface Column { String name(); } + public @interface Max { long value(); } + """ + ), + java( + """ + import lombok.AllArgsConstructor; + import lombok.Getter; + import lombok.Setter; + + @AllArgsConstructor(onConstructor_=@Inject) + public class OnXExample { + @Getter(onMethod_={@Id, @Column(name="unique-id")}) + @Setter(onParam_=@Max(10000)) + private long unid; + + public void test() { + OnXExample x = new OnXExample(1L); + x.setUnid(2L); + System.out.println(x.getUnid()); + } + } + """ + ) + ); + } + + @Test + // TODO: Find solution and remove this test + void onConstructorNoArgsForJava8() { + rewriteRun( + spec -> spec.typeValidationOptions(TypeValidation.none()), + java( + """ + public @interface Inject {} + """ + ), + java( + """ + import lombok.NoArgsConstructor; + import lombok.NonNull; + import lombok.RequiredArgsConstructor; + + import javax.inject.Inject; + + @NoArgsConstructor(onConstructor_ = @Inject) + @RequiredArgsConstructor(onConstructor_ = @Inject) + public class OnXExample { + @NonNull private Long unid; + + public void test() { + new OnXExample(); + new OnXExample(1L); + } + } + """ + ) + ); + } + + @Test void extensionMethod() { rewriteRun( From 75f636b50829be9c28f1472f1e650ce693fc7561 Mon Sep 17 00:00:00 2001 From: Jacob van Lingen Date: Thu, 9 Jan 2025 16:30:49 +0100 Subject: [PATCH 21/26] Apply suggestions from code review Co-authored-by: Knut Wannheden --- .../java/isolated/ReloadableJava11ParserVisitor.java | 2 +- .../java/isolated/ReloadableJava17ParserVisitor.java | 2 +- .../java/isolated/ReloadableJava21ParserVisitor.java | 2 +- .../java/org/openrewrite/java/ReloadableJava8ParserVisitor.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java index 80a21b245b4..edbb98522c3 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11ParserVisitor.java @@ -1494,7 +1494,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm typeExpr = null; } else { Space space = whitespace(); - boolean lombokVal = source.substring(cursor).startsWith("val"); + boolean lombokVal = source.startsWith("val", cursor); cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), space, diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java index 67064f140d7..c5b381b500f 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17ParserVisitor.java @@ -1573,7 +1573,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm typeExpr = null; } else { Space space = whitespace(); - boolean lombokVal = source.substring(cursor).startsWith("val"); + boolean lombokVal = source.startsWith("val", cursor); cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), space, diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java index 6a8b640c47c..4d4a25010fa 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21ParserVisitor.java @@ -1573,7 +1573,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm typeExpr = null; } else { Space space = whitespace(); - boolean lombokVal = source.substring(cursor).startsWith("val"); + boolean lombokVal = source.startsWith("val", cursor); cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), space, diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 1cd039d5fff..f37d991a304 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -1483,7 +1483,7 @@ private J.VariableDeclarations visitVariables(List nodes, Space fm typeExpr = null; // this is a lambda parameter with an inferred type expression } else if (isLombokGenerated(node)) { Space space = whitespace(); - boolean lombokVal = source.substring(cursor).startsWith("val"); + boolean lombokVal = source.startsWith("val", cursor); cursor += 3; // skip `val` or `var` typeExpr = new J.Identifier(randomId(), space, From 3bc94dff81cb880f9cdef9df79e3f91966878bee Mon Sep 17 00:00:00 2001 From: lingenj Date: Thu, 9 Jan 2025 17:20:30 +0100 Subject: [PATCH 22/26] Improve tests --- .../org/openrewrite/java/tree/LombokTest.java | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index b29b3703c68..251904b2a07 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test; import org.openrewrite.java.JavaParser; import org.openrewrite.java.MinimumJava11; +import org.openrewrite.java.search.FindMissingTypes; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; import org.openrewrite.test.TypeValidation; @@ -839,7 +840,14 @@ void jacksonizedForJava8() { rewriteRun( spec -> spec .parser(JavaParser.fromJavaVersion().classpath("jackson-annotations", "lombok")) - .typeValidationOptions(TypeValidation.none()), + .typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + // Using the @Jacksonized annotation in java 8 just breaks it all + return result.getPath().startsWith("ClassDeclaration->CompilationUnit") || + result.getPath().startsWith("Identifier->Annotation")|| + result.getPath().startsWith("Identifier->ParameterizedType"); + }).build()), java( """ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -861,7 +869,13 @@ public class JacksonExample { // TODO: Find solution and remove this test void onConstructorForJava8() { rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.none()), + spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + // The AllArgsConstructorHandler, GetterHandler and SetterHandler do not run at all for java 8, + // so no generated constructors and methods, thus no types. + return result.getPath().startsWith("NewClass->") || result.getPath().startsWith("MethodInvocation->"); + }).build()), java( """ public @interface Inject {} @@ -897,10 +911,17 @@ public void test() { // TODO: Find solution and remove this test void onConstructorNoArgsForJava8() { rewriteRun( - spec -> spec.typeValidationOptions(TypeValidation.none()), + spec -> spec.typeValidationOptions(TypeValidation.builder().allowMissingType(o -> { + assert o instanceof FindMissingTypes.MissingTypeResult; + FindMissingTypes.MissingTypeResult result = (FindMissingTypes.MissingTypeResult) o; + // The NoArgsConstructor and RequiredArgsConstructor do not run at all for java 8, + // so no generated constructors, thus no types. + return result.getPath().startsWith("NewClass->"); + }).build()), java( """ public @interface Inject {} + public @interface Ignore {} // somehow we need this, to prevent `ClassDeclaration->CompilationUnit` errors """ ), java( @@ -911,8 +932,8 @@ void onConstructorNoArgsForJava8() { import javax.inject.Inject; - @NoArgsConstructor(onConstructor_ = @Inject) - @RequiredArgsConstructor(onConstructor_ = @Inject) + @NoArgsConstructor(onConstructor_=@Inject) + @RequiredArgsConstructor(onConstructor_=@Inject) public class OnXExample { @NonNull private Long unid; From e0c917dfd4ca67d1a08fde638d521ee5b9c2dd7c Mon Sep 17 00:00:00 2001 From: lingenj Date: Thu, 9 Jan 2025 18:16:06 +0100 Subject: [PATCH 23/26] Merge branch 'main' into lombok-java-8 --- .../java/org/openrewrite/java/ReloadableJava8ParserVisitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java index 43a2360b906..0d6cf8309fc 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8ParserVisitor.java @@ -1684,7 +1684,7 @@ private static int getActualStartPosition(JCTree t) { return convert(t, suffix, j -> Markers.EMPTY); } - private < @Nullable JRightPadded convert(@Nullable Tree t, Function suffix, Function markers) { + private @Nullable JRightPadded convert(@Nullable Tree t, Function suffix, Function markers) { if (t == null) { return null; } From b59aecc275237dd58b2e0f1561304a91309e439d Mon Sep 17 00:00:00 2001 From: lingenj Date: Fri, 10 Jan 2025 09:25:51 +0100 Subject: [PATCH 24/26] Rename JavacAnnotationHandler with no action to XNoOpHandler --- ...ensionMethodHandler.java => ExtensionMethodNoOpHandler.java} | 2 +- .../java/lombok/{HelperHandler.java => HelperNoOpHandler.java} | 2 +- .../{JacksonizedHandler.java => JacksonizedNoOpHandler.java} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/{ExtensionMethodHandler.java => ExtensionMethodNoOpHandler.java} (91%) rename rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/{HelperHandler.java => HelperNoOpHandler.java} (93%) rename rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/{JacksonizedHandler.java => JacksonizedNoOpHandler.java} (93%) diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodNoOpHandler.java similarity index 91% rename from rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodHandler.java rename to rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodNoOpHandler.java index 68b5543da96..dbc6be1dcf4 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/ExtensionMethodNoOpHandler.java @@ -21,7 +21,7 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; -public class ExtensionMethodHandler extends JavacAnnotationHandler { +public class ExtensionMethodNoOpHandler extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotationValues, JCTree.JCAnnotation jcAnnotation, JavacNode javacNode) { } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperNoOpHandler.java similarity index 93% rename from rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperHandler.java rename to rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperNoOpHandler.java index d1ef2b9fa59..6b7a1be1085 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/HelperNoOpHandler.java @@ -21,7 +21,7 @@ import lombok.javac.JavacAnnotationHandler; import lombok.javac.JavacNode; -public class HelperHandler extends JavacAnnotationHandler { +public class HelperNoOpHandler extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCTree.JCAnnotation ast, JavacNode annotationNode) { } diff --git a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedHandler.java b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedNoOpHandler.java similarity index 93% rename from rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedHandler.java rename to rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedNoOpHandler.java index a9ce02cd671..bd66517d6ff 100644 --- a/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedHandler.java +++ b/rewrite-java-lombok/src/main/java/org/openrewrite/java/lombok/JacksonizedNoOpHandler.java @@ -24,7 +24,7 @@ @SuppressWarnings("SpellCheckingInspection") @HandlerPriority(-512) -public class JacksonizedHandler extends JavacAnnotationHandler { +public class JacksonizedNoOpHandler extends JavacAnnotationHandler { @Override public void handle(AnnotationValues annotation, JCTree.JCAnnotation ast, JavacNode annotationNode) { } From fb52094ee0f4376af3738d513263a22eff0d8314 Mon Sep 17 00:00:00 2001 From: lingenj Date: Fri, 10 Jan 2025 09:26:01 +0100 Subject: [PATCH 25/26] Rename JavacAnnotationHandler with no action to XNoOpHandler --- .../META-INF/services/lombok.javac.JavacAnnotationHandler | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler b/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler index 322964dfb1b..b556f06f95e 100644 --- a/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler +++ b/rewrite-java-lombok/src/main/resources/META-INF/services/lombok.javac.JavacAnnotationHandler @@ -17,10 +17,10 @@ org.openrewrite.java.lombok.AllArgsConstructorHandler org.openrewrite.java.lombok.BuilderHandler org.openrewrite.java.lombok.BuilderDefaultNoOpHandler org.openrewrite.java.lombok.CleanupNoOpHandler -org.openrewrite.java.lombok.ExtensionMethodHandler +org.openrewrite.java.lombok.ExtensionMethodNoOpHandler org.openrewrite.java.lombok.GetterHandler -org.openrewrite.java.lombok.HelperHandler -org.openrewrite.java.lombok.JacksonizedHandler +org.openrewrite.java.lombok.HelperNoOpHandler +org.openrewrite.java.lombok.JacksonizedNoOpHandler org.openrewrite.java.lombok.LockedNoOpHandler org.openrewrite.java.lombok.LockedReadNoOpHandler org.openrewrite.java.lombok.LockedWriteNoOpHandler From 3f2f60b772545ec1061bfaa17071f06ca1d91b36 Mon Sep 17 00:00:00 2001 From: lingenj Date: Fri, 10 Jan 2025 09:26:27 +0100 Subject: [PATCH 26/26] Improve lomboks `ExampleException` test --- .../src/main/java/org/openrewrite/java/tree/LombokTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java index 251904b2a07..aab176f0a7f 100644 --- a/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java +++ b/rewrite-java-tck/src/main/java/org/openrewrite/java/tree/LombokTest.java @@ -747,6 +747,11 @@ void standardException() { @StandardException public class ExampleException extends Exception { + public void test() { + new ExampleException("message"); + new ExampleException(new RuntimeException("message")); + new ExampleException("message", new RuntimeException("message")); + } } """ )