From f23f730393f6a515c9afec71f9346ab623228929 Mon Sep 17 00:00:00 2001 From: Lukas Poos Date: Fri, 9 Jun 2023 13:05:15 +0200 Subject: [PATCH 01/20] Intermediate commit --- rewrite-java/build.gradle.kts | 1 + .../openrewrite/java/LombokUtilityClass.java | 93 +++++++++++++++++++ .../java/LombokUtilityClassTest.java | 59 ++++++++++++ 3 files changed, 153 insertions(+) create mode 100644 rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java create mode 100644 rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java diff --git a/rewrite-java/build.gradle.kts b/rewrite-java/build.gradle.kts index 06eba77e65d..b0a07044079 100644 --- a/rewrite-java/build.gradle.kts +++ b/rewrite-java/build.gradle.kts @@ -47,6 +47,7 @@ dependencies { } testImplementation(project(":rewrite-test")) testImplementation(project(":rewrite-java-test")) + testImplementation(project(":rewrite-maven")) testRuntimeOnly(project(":rewrite-java-17")) testImplementation("com.tngtech.archunit:archunit:1.0.1") testImplementation("com.tngtech.archunit:archunit-junit5:1.0.1") diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java new file mode 100644 index 00000000000..754313c0534 --- /dev/null +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -0,0 +1,93 @@ +package org.openrewrite.java; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.tree.J; + +import java.util.stream.Collectors; + +import static java.util.Comparator.comparing; + +/** + * TODO: Check the following criteria: + * - Lombok in dependencies + * - All methods of class are static + * - No instances of given class + * - All static attributes are final + *

+ * TODO: Perform the transformation: + * - Add the annotation + * - Remove static from all attributes and methods + *

+ * TODO: Features to consider: + * - Transformation: Add Lombok config if not present + supported configuration options for utility class + * - Transformation: Replace instantiation with static calls to methods + */ +public class LombokUtilityClass extends Recipe { + @Override + public String getDisplayName() { + return "Lombok UtilityClass"; + } + + @Override + public String getDescription() { + return "This recipe will check if any class is transformable (only static methods in class)" + + " into the Lombok UtilityClass and will perform the change if applicable."; + } + + @Override + public TreeVisitor getVisitor() { + return new LombokUtilityClassVisitor(); + } + + private static class LombokUtilityClassVisitor extends JavaIsoVisitor { + + @Override + public J.ClassDeclaration visitClassDeclaration( + final J.ClassDeclaration classDecl, + final ExecutionContext executionContext + ) { + if (classDecl.getLeadingAnnotations().stream().anyMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { + return super.visitClassDeclaration(classDecl, executionContext); + } + + maybeAddImport("lombok.experimental.UtilityClass", false); + + return JavaTemplate + .builder("@UtilityClass") + .imports("lombok.experimental.UtilityClass") + .build() + .apply( + getCursor(), + classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)) + ); + } + + @Override + public J.MethodDeclaration visitMethodDeclaration( + final J.MethodDeclaration method, + final ExecutionContext executionContext + ) { + final J.ClassDeclaration classDecl = getCursor().firstEnclosing(J.ClassDeclaration.class); + if (classDecl == null) { + return super.visitMethodDeclaration(method, executionContext); + } + + if (classDecl.getLeadingAnnotations().stream().noneMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { + return super.visitMethodDeclaration(method, executionContext); + } + + if (!method.hasModifier(J.Modifier.Type.Static)) { + return super.visitMethodDeclaration(method, executionContext); + } + + return super.visitMethodDeclaration( + method.withModifiers(method.getModifiers().stream() + .filter(m -> m.getType() != J.Modifier.Type.Static) + .collect(Collectors.toList())), + executionContext + ); + } + } +} diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java new file mode 100644 index 00000000000..0d79a6d6776 --- /dev/null +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -0,0 +1,59 @@ +package org.openrewrite.java; + +import org.junit.jupiter.api.Test; +import org.openrewrite.internal.lang.Nullable; +import org.openrewrite.maven.AddDependency; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class LombokUtilityClassTest implements RewriteTest { + + @Test + void happyPath1() { + rewriteRun( + recipeSpec -> recipeSpec + .recipes( + addDependency("org.projectlombok:lombok:1.18.28", "false"), + new LombokUtilityClass() + ), + java( + """ + public class A { + public static int add(final int x, final int y) { + return x + y; + } + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + """ + ) + ); + } + + private AddDependency addDependency(String gav, String onlyIfUsing) { + return addDependency(gav, onlyIfUsing, null, null); + } + + private AddDependency addDependency(String gav, String onlyIfUsing, Boolean acceptTransitive) { + return addDependency(gav, onlyIfUsing, null, acceptTransitive); + } + + private AddDependency addDependency(String gav, String onlyIfUsing, @Nullable String scope) { + return addDependency(gav, onlyIfUsing, scope, null); + } + + private AddDependency addDependency(String gav, String onlyIfUsing, @Nullable String scope, @Nullable Boolean acceptTransitive) { + String[] gavParts = gav.split(":"); + return new AddDependency(gavParts[0], gavParts[1], gavParts[2], null, scope, true, onlyIfUsing, null, null, + false, null, acceptTransitive); + } +} \ No newline at end of file From ce62e604c933b84565fba54872755a48f1a462ac Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Fri, 9 Jun 2023 14:21:03 +0200 Subject: [PATCH 02/20] #3156 = add some tests --- .../java/LombokUtilityClassTest.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 0d79a6d6776..4953a8b5cb6 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -27,7 +27,7 @@ public static int add(final int x, final int y) { """, """ import lombok.experimental.UtilityClass; - + @UtilityClass public class A { public int add(final int x, final int y) { @@ -39,6 +39,64 @@ public int add(final int x, final int y) { ); } + + @Test + void doNotUpgradeToUtilityClassIfNonStaticVariables() { + rewriteRun( + recipeSpec -> recipeSpec + .recipes( + new LombokUtilityClass() + ), + java( + """ + public class A { + private final int x = 0; + public static int add(final int x, final int y) { + return x + y; + } + } + """, + """ + public class A { + private final int x = 0; + public static int add(final int x, final int y) { + return x + y; + } + } + """ + ) + ); + } + + + @Test + void doNotUpgradeToUtilityClassIfNonStaticMethods() { + rewriteRun( + recipeSpec -> recipeSpec + .recipes( + addDependency("org.projectlombok:lombok:1.18.28", "false"), + new LombokUtilityClass() + ), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + """, + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + """ + ) + ); + } + + private AddDependency addDependency(String gav, String onlyIfUsing) { return addDependency(gav, onlyIfUsing, null, null); } From 40df9470de9cb6337aff793271a3c4a4274e6a2c Mon Sep 17 00:00:00 2001 From: Lukas Poos Date: Fri, 9 Jun 2023 14:21:50 +0200 Subject: [PATCH 03/20] #3156: Add JavaParser to JavaTemplate --- .../src/main/java/org/openrewrite/java/LombokUtilityClass.java | 1 + 1 file changed, 1 insertion(+) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index 754313c0534..a39833109f7 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -57,6 +57,7 @@ public J.ClassDeclaration visitClassDeclaration( return JavaTemplate .builder("@UtilityClass") .imports("lombok.experimental.UtilityClass") + .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) .build() .apply( getCursor(), From 09806c2f9868cb89ae4e008521cbe99f023e4dfe Mon Sep 17 00:00:00 2001 From: Lukas Poos Date: Fri, 9 Jun 2023 14:27:40 +0200 Subject: [PATCH 04/20] #3156: Remove dependency to rewrite-maven --- rewrite-java/build.gradle.kts | 1 - .../java/LombokUtilityClassTest.java | 34 ++----------------- 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/rewrite-java/build.gradle.kts b/rewrite-java/build.gradle.kts index b0a07044079..06eba77e65d 100644 --- a/rewrite-java/build.gradle.kts +++ b/rewrite-java/build.gradle.kts @@ -47,7 +47,6 @@ dependencies { } testImplementation(project(":rewrite-test")) testImplementation(project(":rewrite-java-test")) - testImplementation(project(":rewrite-maven")) testRuntimeOnly(project(":rewrite-java-17")) testImplementation("com.tngtech.archunit:archunit:1.0.1") testImplementation("com.tngtech.archunit:archunit-junit5:1.0.1") diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 4953a8b5cb6..12c1b1c2817 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -1,8 +1,6 @@ package org.openrewrite.java; import org.junit.jupiter.api.Test; -import org.openrewrite.internal.lang.Nullable; -import org.openrewrite.maven.AddDependency; import org.openrewrite.test.RewriteTest; import static org.openrewrite.java.Assertions.java; @@ -13,9 +11,7 @@ class LombokUtilityClassTest implements RewriteTest { void happyPath1() { rewriteRun( recipeSpec -> recipeSpec - .recipes( - addDependency("org.projectlombok:lombok:1.18.28", "false"), - new LombokUtilityClass() + .recipe(new LombokUtilityClass() ), java( """ @@ -44,9 +40,7 @@ public int add(final int x, final int y) { void doNotUpgradeToUtilityClassIfNonStaticVariables() { rewriteRun( recipeSpec -> recipeSpec - .recipes( - new LombokUtilityClass() - ), + .recipe(new LombokUtilityClass()), java( """ public class A { @@ -73,10 +67,7 @@ public static int add(final int x, final int y) { void doNotUpgradeToUtilityClassIfNonStaticMethods() { rewriteRun( recipeSpec -> recipeSpec - .recipes( - addDependency("org.projectlombok:lombok:1.18.28", "false"), - new LombokUtilityClass() - ), + .recipe(new LombokUtilityClass()), java( """ public class A { @@ -95,23 +86,4 @@ public int add(final int x, final int y) { ) ); } - - - private AddDependency addDependency(String gav, String onlyIfUsing) { - return addDependency(gav, onlyIfUsing, null, null); - } - - private AddDependency addDependency(String gav, String onlyIfUsing, Boolean acceptTransitive) { - return addDependency(gav, onlyIfUsing, null, acceptTransitive); - } - - private AddDependency addDependency(String gav, String onlyIfUsing, @Nullable String scope) { - return addDependency(gav, onlyIfUsing, scope, null); - } - - private AddDependency addDependency(String gav, String onlyIfUsing, @Nullable String scope, @Nullable Boolean acceptTransitive) { - String[] gavParts = gav.split(":"); - return new AddDependency(gavParts[0], gavParts[1], gavParts[2], null, scope, true, onlyIfUsing, null, null, - false, null, acceptTransitive); - } } \ No newline at end of file From f063d99184ea9e3058ff5d1402d5b1321eba8a0e Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Fri, 9 Jun 2023 16:01:49 +0200 Subject: [PATCH 05/20] #3156 = correct tests, fix logic do not transform to UtilityClass iff non-static fields or methods are present --- .../openrewrite/java/LombokUtilityClass.java | 96 +++++++++++++------ .../java/LombokUtilityClassTest.java | 15 --- 2 files changed, 66 insertions(+), 45 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index a39833109f7..804e0dffe64 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -2,9 +2,12 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.Recipe; +import org.openrewrite.Tree; import org.openrewrite.TreeVisitor; +import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.J; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import static java.util.Comparator.comparing; @@ -38,57 +41,90 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return new LombokUtilityClassVisitor(); + return new LombokUtilityClassChangeVisitor(); } - private static class LombokUtilityClassVisitor extends JavaIsoVisitor { + private static class LombokUtilityClassCheckVisitor extends JavaIsoVisitor { @Override public J.ClassDeclaration visitClassDeclaration( final J.ClassDeclaration classDecl, - final ExecutionContext executionContext + final AtomicInteger counter ) { if (classDecl.getLeadingAnnotations().stream().anyMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { - return super.visitClassDeclaration(classDecl, executionContext); + counter.getAndIncrement(); } - - maybeAddImport("lombok.experimental.UtilityClass", false); - - return JavaTemplate - .builder("@UtilityClass") - .imports("lombok.experimental.UtilityClass") - .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) - .build() - .apply( - getCursor(), - classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)) - ); + return super.visitClassDeclaration(classDecl, counter); } @Override public J.MethodDeclaration visitMethodDeclaration( final J.MethodDeclaration method, - final ExecutionContext executionContext + final AtomicInteger counter ) { - final J.ClassDeclaration classDecl = getCursor().firstEnclosing(J.ClassDeclaration.class); - if (classDecl == null) { - return super.visitMethodDeclaration(method, executionContext); + if (!method.hasModifier(J.Modifier.Type.Static)) { + counter.getAndIncrement(); } + return super.visitMethodDeclaration(method, counter); + } - if (classDecl.getLeadingAnnotations().stream().noneMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { - return super.visitMethodDeclaration(method, executionContext); + @Override + public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, AtomicInteger counter) { + if (variable.isField(getCursor()) && !variable.getVariableType().hasFlags(Flag.Static)) { + counter.getAndIncrement(); } + return super.visitVariable(variable, counter); + } - if (!method.hasModifier(J.Modifier.Type.Static)) { - return super.visitMethodDeclaration(method, executionContext); + public static int countViolations(Tree t) { + return new LombokUtilityClassCheckVisitor().reduce(t, new AtomicInteger(0)).get(); + } + } + + private static class LombokUtilityClassChangeVisitor extends JavaIsoVisitor { + + private int violations = 0; + + @Override + public J.ClassDeclaration visitClassDeclaration( + final J.ClassDeclaration classDecl, + final ExecutionContext executionContext + ) { + this.violations = LombokUtilityClassCheckVisitor.countViolations(classDecl); + + if (violations == 0) { + + maybeAddImport("lombok.experimental.UtilityClass", false); + + return JavaTemplate + .builder("@UtilityClass") + .imports("lombok.experimental.UtilityClass") + .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) + .build() + .apply( + getCursor(), + classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)) + ); + } + + return super.visitClassDeclaration(classDecl, executionContext); + } + + @Override + public J.MethodDeclaration visitMethodDeclaration( + final J.MethodDeclaration method, + final ExecutionContext executionContext + ) { + if (violations == 0) { + return super.visitMethodDeclaration( + method.withModifiers(method.getModifiers().stream() + .filter(m -> m.getType() != J.Modifier.Type.Static) + .collect(Collectors.toList())), + executionContext + ); } - return super.visitMethodDeclaration( - method.withModifiers(method.getModifiers().stream() - .filter(m -> m.getType() != J.Modifier.Type.Static) - .collect(Collectors.toList())), - executionContext - ); + return super.visitMethodDeclaration(method, executionContext); } } } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 12c1b1c2817..73aebcc6a30 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -42,14 +42,6 @@ void doNotUpgradeToUtilityClassIfNonStaticVariables() { recipeSpec -> recipeSpec .recipe(new LombokUtilityClass()), java( - """ - public class A { - private final int x = 0; - public static int add(final int x, final int y) { - return x + y; - } - } - """, """ public class A { private final int x = 0; @@ -69,13 +61,6 @@ void doNotUpgradeToUtilityClassIfNonStaticMethods() { recipeSpec -> recipeSpec .recipe(new LombokUtilityClass()), java( - """ - public class A { - public int add(final int x, final int y) { - return x + y; - } - } - """, """ public class A { public int add(final int x, final int y) { From c73542c8152ca4c5e9db5c4346fe63a4c97ffa6d Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 10 Jun 2023 18:40:10 +0200 Subject: [PATCH 06/20] #3156 = fix implementation of happy path, add failing tests --- .../openrewrite/java/LombokUtilityClass.java | 34 +++++---- .../java/LombokUtilityClassTest.java | 70 +++++++++++++++++++ 2 files changed, 89 insertions(+), 15 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index 804e0dffe64..7a9cc56a02a 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -28,6 +28,8 @@ * - Transformation: Replace instantiation with static calls to methods */ public class LombokUtilityClass extends Recipe { + private int violations = -1; + @Override public String getDisplayName() { return "Lombok UtilityClass"; @@ -81,30 +83,32 @@ public static int countViolations(Tree t) { } } - private static class LombokUtilityClassChangeVisitor extends JavaIsoVisitor { - - private int violations = 0; + private class LombokUtilityClassChangeVisitor extends JavaIsoVisitor { @Override public J.ClassDeclaration visitClassDeclaration( final J.ClassDeclaration classDecl, final ExecutionContext executionContext ) { - this.violations = LombokUtilityClassCheckVisitor.countViolations(classDecl); + if (LombokUtilityClass.this.violations == -1) { + LombokUtilityClass.this.violations = LombokUtilityClassCheckVisitor.countViolations(classDecl); + } - if (violations == 0) { + if (LombokUtilityClass.this.violations == 0 + && classDecl.getLeadingAnnotations().stream().noneMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { maybeAddImport("lombok.experimental.UtilityClass", false); - return JavaTemplate - .builder("@UtilityClass") - .imports("lombok.experimental.UtilityClass") - .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) - .build() - .apply( - getCursor(), - classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)) - ); + return super.visitClassDeclaration( + JavaTemplate + .builder("@UtilityClass") + .imports("lombok.experimental.UtilityClass") + .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) + .build() + .apply( + getCursor(), + classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)) + ), executionContext); } return super.visitClassDeclaration(classDecl, executionContext); @@ -115,7 +119,7 @@ public J.MethodDeclaration visitMethodDeclaration( final J.MethodDeclaration method, final ExecutionContext executionContext ) { - if (violations == 0) { + if (LombokUtilityClass.this.violations == 0) { return super.visitMethodDeclaration( method.withModifiers(method.getModifiers().stream() .filter(m -> m.getType() != J.Modifier.Type.Static) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 73aebcc6a30..3a4db21fb70 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -71,4 +71,74 @@ public int add(final int x, final int y) { ) ); } + + @Test + void onlyUpgradeRelevantToUtilityClass() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass()), + java( + """ + public class A { + public static int add(final int x, final int y) { + return x + y; + } + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + """ + ), + java(""" + public class B { + public int add(final int x, final int y) { + return x + y; + } + } + """ + ) + ); + } + + @Test + void doNotChangeReferenced() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass()), + java( + """ + public class A { + public static int add(final int x, final int y) { + return x + y; + } + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + """ + ), + java(""" + public class B { + public int add(final int x, final int y) { + return A.add(x, y); + } + } + """ + ) + ); + } } \ No newline at end of file From 1e9539e3989dad169115d1152732ac4c3c7e8ffd Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 10 Jun 2023 18:57:47 +0200 Subject: [PATCH 07/20] #3156 = add/refine tests related to non-public, inner and nested classes --- .../java/LombokUtilityClassTest.java | 118 +++++++++++++++++- 1 file changed, 117 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 3a4db21fb70..023eba08bf2 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -8,7 +8,7 @@ class LombokUtilityClassTest implements RewriteTest { @Test - void happyPath1() { + void happyPathSimple() { rewriteRun( recipeSpec -> recipeSpec .recipe(new LombokUtilityClass() @@ -141,4 +141,120 @@ public int add(final int x, final int y) { ) ); } + + @Test + void happyPathInner() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass()), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + private class B { + private static int substract(final int x, final int y) { + return x - y; + } + } + } + """, + """ + import lombok.experimental.UtilityClass; + + public class A { + public int add(final int x, final int y) { + return x + y; + } + + @UtilityClass + private class B { + private int substract(final int x, final int y) { + return x - y; + } + } + } + """ + ) + ); + } + + /** + * Nested ~ inner static + */ + @Test + void happyPathNested() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass()), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + private static class B { + private static int substract(final int x, final int y) { + return x - y; + } + } + } + """, + """ + import lombok.experimental.UtilityClass; + + public class A { + public int add(final int x, final int y) { + return x + y; + } + + @UtilityClass + private static class B { + private int substract(final int x, final int y) { + return x - y; + } + } + } + """ + ) + ); + } + + @Test + void happyPathNonPublic() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass()), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + class B { + public static int substract(final int x, final int y) { + return x - y; + } + } + """, + """ + import lombok.experimental.UtilityClass; + + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + @UtilityClass + class B { + public int substract(final int x, final int y) { + return x - y; + } + } + """ + ) + ); + } } \ No newline at end of file From 9843177a727204d4cae3f0853f2ff714e35f3d39 Mon Sep 17 00:00:00 2001 From: Lukas Poos Date: Sun, 11 Jun 2023 10:21:59 +0200 Subject: [PATCH 08/20] #3156: Simplify check visitor calls --- .../openrewrite/java/LombokUtilityClass.java | 113 +++++++++--------- .../java/LombokUtilityClassTest.java | 69 ++++++----- 2 files changed, 93 insertions(+), 89 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index 7a9cc56a02a..ad74b592c35 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -2,12 +2,11 @@ import org.openrewrite.ExecutionContext; import org.openrewrite.Recipe; -import org.openrewrite.Tree; import org.openrewrite.TreeVisitor; import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.J; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import static java.util.Comparator.comparing; @@ -28,7 +27,6 @@ * - Transformation: Replace instantiation with static calls to methods */ public class LombokUtilityClass extends Recipe { - private int violations = -1; @Override public String getDisplayName() { @@ -43,92 +41,95 @@ public String getDescription() { @Override public TreeVisitor getVisitor() { - return new LombokUtilityClassChangeVisitor(); + return new ChangeVisitor(); } - private static class LombokUtilityClassCheckVisitor extends JavaIsoVisitor { + + private static class ChangeVisitor extends JavaIsoVisitor { @Override public J.ClassDeclaration visitClassDeclaration( final J.ClassDeclaration classDecl, - final AtomicInteger counter + final ExecutionContext executionContext ) { - if (classDecl.getLeadingAnnotations().stream().anyMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { - counter.getAndIncrement(); + if (!CheckVisitor.shouldPerformChanges(classDecl)) { + return super.visitClassDeclaration(classDecl, executionContext); } - return super.visitClassDeclaration(classDecl, counter); + + maybeAddImport("lombok.experimental.UtilityClass", false); + + return super.visitClassDeclaration( + JavaTemplate + .builder("@UtilityClass") + .imports("lombok.experimental.UtilityClass") + .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) + .build() + .apply( + getCursor(), + classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)) + ), + executionContext + ); } @Override public J.MethodDeclaration visitMethodDeclaration( final J.MethodDeclaration method, - final AtomicInteger counter + final ExecutionContext executionContext ) { - if (!method.hasModifier(J.Modifier.Type.Static)) { - counter.getAndIncrement(); + final J.ClassDeclaration classDecl = getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class); + if (!CheckVisitor.shouldPerformChanges(classDecl)) { + return super.visitMethodDeclaration(method, executionContext); } - return super.visitMethodDeclaration(method, counter); - } - - @Override - public J.VariableDeclarations.NamedVariable visitVariable(J.VariableDeclarations.NamedVariable variable, AtomicInteger counter) { - if (variable.isField(getCursor()) && !variable.getVariableType().hasFlags(Flag.Static)) { - counter.getAndIncrement(); - } - return super.visitVariable(variable, counter); - } - public static int countViolations(Tree t) { - return new LombokUtilityClassCheckVisitor().reduce(t, new AtomicInteger(0)).get(); + return super.visitMethodDeclaration( + method.withModifiers(method.getModifiers().stream() + .filter(m -> m.getType() != J.Modifier.Type.Static) + .collect(Collectors.toList())), + executionContext + ); } } - private class LombokUtilityClassChangeVisitor extends JavaIsoVisitor { + private static class CheckVisitor extends JavaIsoVisitor { @Override public J.ClassDeclaration visitClassDeclaration( final J.ClassDeclaration classDecl, - final ExecutionContext executionContext + final AtomicBoolean shouldPerformChanges ) { - if (LombokUtilityClass.this.violations == -1) { - LombokUtilityClass.this.violations = LombokUtilityClassCheckVisitor.countViolations(classDecl); - } - - if (LombokUtilityClass.this.violations == 0 - && classDecl.getLeadingAnnotations().stream().noneMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { - - maybeAddImport("lombok.experimental.UtilityClass", false); - - return super.visitClassDeclaration( - JavaTemplate - .builder("@UtilityClass") - .imports("lombok.experimental.UtilityClass") - .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) - .build() - .apply( - getCursor(), - classDecl.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName)) - ), executionContext); + if (classDecl.getLeadingAnnotations().stream().anyMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { + shouldPerformChanges.set(false); } - - return super.visitClassDeclaration(classDecl, executionContext); + return super.visitClassDeclaration(classDecl, shouldPerformChanges); } @Override public J.MethodDeclaration visitMethodDeclaration( final J.MethodDeclaration method, - final ExecutionContext executionContext + final AtomicBoolean shouldPerformChanges + ) { + if (!method.hasModifier(J.Modifier.Type.Static)) { + shouldPerformChanges.set(false); + } + return super.visitMethodDeclaration(method, shouldPerformChanges); + } + + @Override + public J.VariableDeclarations.NamedVariable visitVariable( + final J.VariableDeclarations.NamedVariable variable, + final AtomicBoolean shouldPerformChanges ) { - if (LombokUtilityClass.this.violations == 0) { - return super.visitMethodDeclaration( - method.withModifiers(method.getModifiers().stream() - .filter(m -> m.getType() != J.Modifier.Type.Static) - .collect(Collectors.toList())), - executionContext - ); + if (variable.isField(getCursor()) + && variable.getVariableType() != null + && !variable.getVariableType().hasFlags(Flag.Static)) { + shouldPerformChanges.set(false); } + return super.visitVariable(variable, shouldPerformChanges); + } - return super.visitMethodDeclaration(method, executionContext); + private static boolean shouldPerformChanges(final J.ClassDeclaration classDecl) { + return new CheckVisitor().reduce(classDecl, new AtomicBoolean(true)).get(); } } } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 023eba08bf2..cbd41665649 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -150,30 +150,31 @@ void happyPathInner() { java( """ public class A { - public int add(final int x, final int y) { - return x + y; - } - private class B { - private static int substract(final int x, final int y) { - return x - y; + public int add(final int x, final int y) { + return x + y; + } + + private class B { + private static int substract(final int x, final int y) { + return x - y; + } } - } } """, """ import lombok.experimental.UtilityClass; public class A { - public int add(final int x, final int y) { - return x + y; - } - - @UtilityClass - private class B { - private int substract(final int x, final int y) { - return x - y; + public int add(final int x, final int y) { + return x + y; + } + + @UtilityClass + private class B { + private int substract(final int x, final int y) { + return x - y; + } } - } } """ ) @@ -191,30 +192,31 @@ void happyPathNested() { java( """ public class A { - public int add(final int x, final int y) { - return x + y; - } - private static class B { - private static int substract(final int x, final int y) { - return x - y; + public int add(final int x, final int y) { + return x + y; + } + + private static class B { + private static int substract(final int x, final int y) { + return x - y; + } } - } } """, """ import lombok.experimental.UtilityClass; - + public class A { - public int add(final int x, final int y) { - return x + y; - } - - @UtilityClass - private static class B { - private int substract(final int x, final int y) { - return x - y; + public int add(final int x, final int y) { + return x + y; + } + + @UtilityClass + private static class B { + private int substract(final int x, final int y) { + return x - y; + } } - } } """ ) @@ -247,6 +249,7 @@ public int add(final int x, final int y) { return x + y; } } + @UtilityClass class B { public int substract(final int x, final int y) { From 3d9c9e6652f6905793b52ff2aff7bafa2cda97d9 Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sun, 11 Jun 2023 10:38:51 +0200 Subject: [PATCH 09/20] #3156 = wip --- .../openrewrite/java/LombokUtilityClass.java | 26 +++++++++++++++++++ .../java/LombokUtilityClassTest.java | 26 ++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index ad74b592c35..71341dffb05 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -5,7 +5,10 @@ import org.openrewrite.TreeVisitor; import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -89,6 +92,29 @@ public J.MethodDeclaration visitMethodDeclaration( executionContext ); } + + @Override + public J.VariableDeclarations.NamedVariable visitVariable( + final J.VariableDeclarations.NamedVariable variable, + final ExecutionContext executionContext + ) { + final J.ClassDeclaration classDecl = getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class); + if (!CheckVisitor.shouldPerformChanges(classDecl)) { + return super.visitVariable(variable, executionContext); + } + + JavaType.Variable vari = variable.getVariableType(); + Set flags = new HashSet<>(vari.getFlags()); + flags.remove(Flag.Static); + + return super.visitVariable( + variable + .withName(variable.getName().withSimpleName(variable.getName().getSimpleName().toLowerCase())) + //.withVariableType(vari.withFlags(Collections.emptySet())), + .withVariableType(new JavaType.Variable(null, Flag.Final.getBitMask(), "", null, null, null)), + executionContext + ); + } } private static class CheckVisitor extends JavaIsoVisitor { diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index cbd41665649..1d8017678c3 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -8,7 +8,7 @@ class LombokUtilityClassTest implements RewriteTest { @Test - void happyPathSimple() { + void happyPathSimpleMethod() { rewriteRun( recipeSpec -> recipeSpec .recipe(new LombokUtilityClass() @@ -35,6 +35,30 @@ public int add(final int x, final int y) { ); } + @Test + void happyPathSimpleField() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass() + ), + java( + """ + public class A { + public static final int C = 0; + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public final int c = 0; + } + """ + ) + ); + } + @Test void doNotUpgradeToUtilityClassIfNonStaticVariables() { From e9e61a12b66e1a5c7cb772cc52bda5ef5423f5f5 Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sun, 11 Jun 2023 10:47:26 +0200 Subject: [PATCH 10/20] #3156 = add multi-variable test --- .../java/LombokUtilityClassTest.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 1d8017678c3..93f181606cd 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -59,6 +59,30 @@ public class A { ); } + @Test + void happyPathMultiVariableField() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass() + ), + java( + """ + public class A { + public static final int A, B, C = 0; + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public final int a, b, c = 0; + } + """ + ) + ); + } + @Test void doNotUpgradeToUtilityClassIfNonStaticVariables() { From 10b5c968ee66a232a32aa52c8fe1412ca817a18d Mon Sep 17 00:00:00 2001 From: Lukas Poos Date: Sun, 11 Jun 2023 10:50:06 +0200 Subject: [PATCH 11/20] #3156: Update static class members correctly --- .../openrewrite/java/LombokUtilityClass.java | 29 +++++----- .../java/LombokUtilityClassTest.java | 57 ++++++++----------- 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index 71341dffb05..cd46bc99e69 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -5,10 +5,7 @@ import org.openrewrite.TreeVisitor; import org.openrewrite.java.tree.Flag; import org.openrewrite.java.tree.J; -import org.openrewrite.java.tree.JavaType; -import java.util.HashSet; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; @@ -60,7 +57,6 @@ public J.ClassDeclaration visitClassDeclaration( } maybeAddImport("lombok.experimental.UtilityClass", false); - return super.visitClassDeclaration( JavaTemplate .builder("@UtilityClass") @@ -94,24 +90,25 @@ public J.MethodDeclaration visitMethodDeclaration( } @Override - public J.VariableDeclarations.NamedVariable visitVariable( - final J.VariableDeclarations.NamedVariable variable, + public J.VariableDeclarations visitVariableDeclarations( + final J.VariableDeclarations multiVariable, final ExecutionContext executionContext ) { final J.ClassDeclaration classDecl = getCursor().firstEnclosingOrThrow(J.ClassDeclaration.class); if (!CheckVisitor.shouldPerformChanges(classDecl)) { - return super.visitVariable(variable, executionContext); + return super.visitVariableDeclarations(multiVariable, executionContext); } - JavaType.Variable vari = variable.getVariableType(); - Set flags = new HashSet<>(vari.getFlags()); - flags.remove(Flag.Static); - - return super.visitVariable( - variable - .withName(variable.getName().withSimpleName(variable.getName().getSimpleName().toLowerCase())) - //.withVariableType(vari.withFlags(Collections.emptySet())), - .withVariableType(new JavaType.Variable(null, Flag.Final.getBitMask(), "", null, null, null)), + return super.visitVariableDeclarations( + multiVariable + .withModifiers(multiVariable.getModifiers().stream() + .filter(m -> m.getType() != J.Modifier.Type.Static) + .collect(Collectors.toList()) + ) + .withVariables(multiVariable.getVariables().stream() + .map(v -> v.withName(v.getName().withSimpleName(v.getName().getSimpleName().toLowerCase()))) + .collect(Collectors.toList()) + ), executionContext ); } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 93f181606cd..6ab10395c72 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -10,9 +10,7 @@ class LombokUtilityClassTest implements RewriteTest { @Test void happyPathSimpleMethod() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass() - ), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -62,9 +60,7 @@ public class A { @Test void happyPathMultiVariableField() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass() - ), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -87,8 +83,7 @@ public class A { @Test void doNotUpgradeToUtilityClassIfNonStaticVariables() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass()), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -106,8 +101,7 @@ public static int add(final int x, final int y) { @Test void doNotUpgradeToUtilityClassIfNonStaticMethods() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass()), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -123,8 +117,7 @@ public int add(final int x, final int y) { @Test void onlyUpgradeRelevantToUtilityClass() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass()), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -145,12 +138,12 @@ public int add(final int x, final int y) { """ ), java(""" - public class B { - public int add(final int x, final int y) { - return x + y; - } - } - """ + public class B { + public int add(final int x, final int y) { + return x + y; + } + } + """ ) ); } @@ -158,8 +151,7 @@ public int add(final int x, final int y) { @Test void doNotChangeReferenced() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass()), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -180,12 +172,12 @@ public int add(final int x, final int y) { """ ), java(""" - public class B { - public int add(final int x, final int y) { - return A.add(x, y); - } - } - """ + public class B { + public int add(final int x, final int y) { + return A.add(x, y); + } + } + """ ) ); } @@ -193,8 +185,7 @@ public int add(final int x, final int y) { @Test void happyPathInner() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass()), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -235,8 +226,7 @@ private int substract(final int x, final int y) { @Test void happyPathNested() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass()), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -253,7 +243,7 @@ private static int substract(final int x, final int y) { """, """ import lombok.experimental.UtilityClass; - + public class A { public int add(final int x, final int y) { return x + y; @@ -274,8 +264,7 @@ private int substract(final int x, final int y) { @Test void happyPathNonPublic() { rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass()), + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( """ public class A { @@ -297,7 +286,7 @@ public int add(final int x, final int y) { return x + y; } } - + @UtilityClass class B { public int substract(final int x, final int y) { From bb366ab5ab99467ca552c868507871f414f6dc82 Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sun, 11 Jun 2023 10:57:21 +0200 Subject: [PATCH 12/20] #3156 = fix non-final fields, mark progress --- .../openrewrite/java/LombokUtilityClass.java | 18 ++++++++++-------- .../java/LombokUtilityClassTest.java | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index cd46bc99e69..09f847de122 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -13,18 +13,20 @@ /** * TODO: Check the following criteria: - * - Lombok in dependencies - * - All methods of class are static - * - No instances of given class - * - All static attributes are final + * - Lombok in dependencies + + * - All methods of class are static + + * - No instances of given class + + * - All static attributes are final + *

* TODO: Perform the transformation: - * - Add the annotation - * - Remove static from all attributes and methods + * - Add the annotation + + * - Remove static from all attributes and methods + *

* TODO: Features to consider: * - Transformation: Add Lombok config if not present + supported configuration options for utility class - * - Transformation: Replace instantiation with static calls to methods + * - Transformation: Replace instantiation with static calls to methods --> na + * - Anonymous classes ??? + * - Reflection ??? */ public class LombokUtilityClass extends Recipe { @@ -145,7 +147,7 @@ public J.VariableDeclarations.NamedVariable visitVariable( ) { if (variable.isField(getCursor()) && variable.getVariableType() != null - && !variable.getVariableType().hasFlags(Flag.Static)) { + && !variable.getVariableType().hasFlags(Flag.Static, Flag.Final)) { shouldPerformChanges.set(false); } return super.visitVariable(variable, shouldPerformChanges); diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 6ab10395c72..95922296fc9 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -57,6 +57,22 @@ public class A { ); } + @Test + void doNotChangeFieldIfNotFinal() { + rewriteRun( + recipeSpec -> recipeSpec + .recipe(new LombokUtilityClass() + ), + java( + """ + public class A { + public static int C = 0; + } + """ + ) + ); + } + @Test void happyPathMultiVariableField() { rewriteRun( From 25c9dda30ff686dff6348c440979b741f601a655 Mon Sep 17 00:00:00 2001 From: Lukas Poos Date: Sun, 11 Jun 2023 11:20:37 +0200 Subject: [PATCH 13/20] #3156: Organize test cases --- .../java/LombokUtilityClassTest.java | 457 +++++++++--------- 1 file changed, 227 insertions(+), 230 deletions(-) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 95922296fc9..091f8562530 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -1,137 +1,245 @@ package org.openrewrite.java; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.openrewrite.test.RewriteTest; import static org.openrewrite.java.Assertions.java; +/** + * Cases to test: + * - Interfaces + * - Empty classes & interfaces + * - inheritance + * - abstract classes + * - instantiations of changed classes + * - constructor + */ class LombokUtilityClassTest implements RewriteTest { - @Test - void happyPathSimpleMethod() { - rewriteRun( - recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), - java( - """ - public class A { - public static int add(final int x, final int y) { - return x + y; - } - } - """, - """ - import lombok.experimental.UtilityClass; - - @UtilityClass - public class A { - public int add(final int x, final int y) { - return x + y; - } - } - """ - ) - ); - } + @Nested + class ShouldApplyLombokUtility implements RewriteTest { - @Test - void happyPathSimpleField() { - rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass() - ), - java( - """ - public class A { - public static final int C = 0; - } - """, - """ - import lombok.experimental.UtilityClass; - - @UtilityClass - public class A { - public final int c = 0; - } - """ - ) - ); - } + @Test + void givenOneStaticMethod() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public static int add(final int x, final int y) { + return x + y; + } + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + """ + ) + ); + } - @Test - void doNotChangeFieldIfNotFinal() { - rewriteRun( - recipeSpec -> recipeSpec - .recipe(new LombokUtilityClass() - ), - java( - """ - public class A { - public static int C = 0; - } - """ - ) - ); - } + @Test + void givenOneStaticFinalMember() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public static final int C = 0; + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public final int c = 0; + } + """ + ) + ); + } - @Test - void happyPathMultiVariableField() { - rewriteRun( - recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), - java( - """ - public class A { - public static final int A, B, C = 0; - } - """, - """ - import lombok.experimental.UtilityClass; - - @UtilityClass - public class A { - public final int a, b, c = 0; - } - """ - ) - ); - } + @Test + void givenMultipleStaticFinalMembers() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public static final int A, B, C = 0; + } + """, + """ + import lombok.experimental.UtilityClass; + + @UtilityClass + public class A { + public final int a, b, c = 0; + } + """ + ) + ); + } + @Test + void givenStaticInnerClassWithOneStaticMethod() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + + private static class B { + private static int substract(final int x, final int y) { + return x - y; + } + } + } + """, + """ + import lombok.experimental.UtilityClass; + + public class A { + public int add(final int x, final int y) { + return x + y; + } + + @UtilityClass + private static class B { + private int substract(final int x, final int y) { + return x - y; + } + } + } + """ + ) + ); + } - @Test - void doNotUpgradeToUtilityClassIfNonStaticVariables() { - rewriteRun( - recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), - java( - """ - public class A { - private final int x = 0; - public static int add(final int x, final int y) { - return x + y; - } - } - """ - ) - ); + @Test + void givenInnerClassWithOneStaticMethod() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + + private class B { + private static int substract(final int x, final int y) { + return x - y; + } + } + } + """, + """ + import lombok.experimental.UtilityClass; + + public class A { + public int add(final int x, final int y) { + return x + y; + } + + @UtilityClass + private class B { + private int substract(final int x, final int y) { + return x - y; + } + } + } + """ + ) + ); + } + + @Test + void givenNotPublicClassWithOneStaticMethod() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + class B { + public static int substract(final int x, final int y) { + return x - y; + } + } + """, + """ + import lombok.experimental.UtilityClass; + + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + + @UtilityClass + class B { + public int substract(final int x, final int y) { + return x - y; + } + } + """ + ) + ); + } } + @Nested + class ShouldNotApplyLombokUtility implements RewriteTest { + @Test + void givenStaticMemberIsNotFinal() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public static int C = 0; + } + """ + ) + ); + } + + @Test + void givenMethodIsNotStatic() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public int add(final int x, final int y) { + return x + y; + } + } + """ + ) + ); + } - @Test - void doNotUpgradeToUtilityClassIfNonStaticMethods() { - rewriteRun( - recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), - java( - """ - public class A { - public int add(final int x, final int y) { - return x + y; - } - } - """ - ) - ); } @Test - void onlyUpgradeRelevantToUtilityClass() { + void shouldNotChangeClassWhenStaticMethodOfChangedClassIsCalled() { rewriteRun( recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( @@ -156,7 +264,7 @@ public int add(final int x, final int y) { java(""" public class B { public int add(final int x, final int y) { - return x + y; + return A.add(x, y); } } """ @@ -164,8 +272,9 @@ public int add(final int x, final int y) { ); } + @Test - void doNotChangeReferenced() { + void shoulOnlyUpgradeRelevantToUtilityClass() { rewriteRun( recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( @@ -190,7 +299,7 @@ public int add(final int x, final int y) { java(""" public class B { public int add(final int x, final int y) { - return A.add(x, y); + return x + y; } } """ @@ -198,119 +307,7 @@ public int add(final int x, final int y) { ); } - @Test - void happyPathInner() { - rewriteRun( - recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), - java( - """ - public class A { - public int add(final int x, final int y) { - return x + y; - } - - private class B { - private static int substract(final int x, final int y) { - return x - y; - } - } - } - """, - """ - import lombok.experimental.UtilityClass; - - public class A { - public int add(final int x, final int y) { - return x + y; - } - - @UtilityClass - private class B { - private int substract(final int x, final int y) { - return x - y; - } - } - } - """ - ) - ); - } - /** - * Nested ~ inner static - */ - @Test - void happyPathNested() { - rewriteRun( - recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), - java( - """ - public class A { - public int add(final int x, final int y) { - return x + y; - } - - private static class B { - private static int substract(final int x, final int y) { - return x - y; - } - } - } - """, - """ - import lombok.experimental.UtilityClass; - - public class A { - public int add(final int x, final int y) { - return x + y; - } - - @UtilityClass - private static class B { - private int substract(final int x, final int y) { - return x - y; - } - } - } - """ - ) - ); - } - @Test - void happyPathNonPublic() { - rewriteRun( - recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), - java( - """ - public class A { - public int add(final int x, final int y) { - return x + y; - } - } - class B { - public static int substract(final int x, final int y) { - return x - y; - } - } - """, - """ - import lombok.experimental.UtilityClass; - - public class A { - public int add(final int x, final int y) { - return x + y; - } - } - - @UtilityClass - class B { - public int substract(final int x, final int y) { - return x - y; - } - } - """ - ) - ); - } + } \ No newline at end of file From 6d87f63a3c3c38ad848899553c62e72868ccf10b Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Mon, 12 Jun 2023 09:48:34 +0200 Subject: [PATCH 14/20] #3156 = add additional suggestion for a test case --- .../test/java/org/openrewrite/java/LombokUtilityClassTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 091f8562530..e89957e29f6 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -14,6 +14,7 @@ * - abstract classes * - instantiations of changed classes * - constructor + * - public static void main */ class LombokUtilityClassTest implements RewriteTest { From 2a27d55be8d37e1efda208497cceca8443cf6a78 Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 17 Jun 2023 22:58:21 +0200 Subject: [PATCH 15/20] #3156 = add test and exclusion for main method --- .../org/openrewrite/java/LombokUtilityClass.java | 4 ++++ .../openrewrite/java/LombokUtilityClassTest.java | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index 09f847de122..5d0e7d428e1 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -137,6 +137,10 @@ public J.MethodDeclaration visitMethodDeclaration( if (!method.hasModifier(J.Modifier.Type.Static)) { shouldPerformChanges.set(false); } + + if (method.getSimpleName().equalsIgnoreCase("main")) { + shouldPerformChanges.set(false); + } return super.visitMethodDeclaration(method, shouldPerformChanges); } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index e89957e29f6..ca27cee88e8 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -14,7 +14,6 @@ * - abstract classes * - instantiations of changed classes * - constructor - * - public static void main */ class LombokUtilityClassTest implements RewriteTest { @@ -237,6 +236,21 @@ public int add(final int x, final int y) { ); } + @Test + void givenMain() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + public static void main(String[] args) { + } + } + """ + ) + ); + } + } @Test From 28581b03febbbad1e322b5db7d3367c4d15e7902 Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 17 Jun 2023 23:00:07 +0200 Subject: [PATCH 16/20] #3156 = add license --- .../org/openrewrite/java/LombokUtilityClass.java | 15 +++++++++++++++ .../openrewrite/java/LombokUtilityClassTest.java | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index 5d0e7d428e1..ea9f35475a8 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -1,3 +1,18 @@ +/* + * Copyright 2023 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. + */ package org.openrewrite.java; import org.openrewrite.ExecutionContext; diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index ca27cee88e8..47c1ec6cdd3 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2023 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. + */ package org.openrewrite.java; import org.junit.jupiter.api.Nested; From acb5cf54cf9f8aac0c15d12da5f0fe0da6150c28 Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 17 Jun 2023 23:04:44 +0200 Subject: [PATCH 17/20] #3156 = do not transform abstract --- .../org/openrewrite/java/LombokUtilityClass.java | 3 +++ .../openrewrite/java/LombokUtilityClassTest.java | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index ea9f35475a8..a5134570fbe 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -138,6 +138,9 @@ public J.ClassDeclaration visitClassDeclaration( final J.ClassDeclaration classDecl, final AtomicBoolean shouldPerformChanges ) { + if (classDecl.hasModifier(J.Modifier.Type.Abstract)) { + shouldPerformChanges.set(false); + } if (classDecl.getLeadingAnnotations().stream().anyMatch(a -> "UtilityClass".equals(a.getSimpleName()))) { shouldPerformChanges.set(false); } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 47c1ec6cdd3..953a6102625 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -26,7 +26,6 @@ * - Interfaces * - Empty classes & interfaces * - inheritance - * - abstract classes * - instantiations of changed classes * - constructor */ @@ -266,6 +265,21 @@ public static void main(String[] args) { ); } + @Test + void givenAbstractClass() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public abstract class A { + public static void doSmth() { + }; + } + """ + ) + ); + } + } @Test From 722f905c10edd615f4d98f44319b594bde2e498a Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 17 Jun 2023 23:12:27 +0200 Subject: [PATCH 18/20] #3156 = do not transform interfaces --- .../openrewrite/java/LombokUtilityClass.java | 3 +++ .../java/LombokUtilityClassTest.java | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java index a5134570fbe..8b67e5ea9a8 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/LombokUtilityClass.java @@ -138,6 +138,9 @@ public J.ClassDeclaration visitClassDeclaration( final J.ClassDeclaration classDecl, final AtomicBoolean shouldPerformChanges ) { + if (classDecl.getType().hasFlags(Flag.Interface)) { + shouldPerformChanges.set(false); + } if (classDecl.hasModifier(J.Modifier.Type.Abstract)) { shouldPerformChanges.set(false); } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index 953a6102625..b4d05876896 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -23,7 +23,6 @@ /** * Cases to test: - * - Interfaces * - Empty classes & interfaces * - inheritance * - instantiations of changed classes @@ -280,6 +279,22 @@ public static void doSmth() { ); } + @Test + void givenInteface() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public interface A { + int CONST = 1; + static void doSmth() { + } + } + """ + ) + ); + } + } @Test From 270b43d8a32026d1f52c4e2ff39ebd88a41abdde Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 17 Jun 2023 23:31:52 +0200 Subject: [PATCH 19/20] #3156 = add failing test --- .../openrewrite/java/LombokUtilityClassTest.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index b4d05876896..bc4660503f5 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -280,7 +280,7 @@ public static void doSmth() { } @Test - void givenInteface() { + void givenInterface() { rewriteRun( recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), java( @@ -295,6 +295,20 @@ static void doSmth() { ); } + // FIXME: use messaging on getCursor() to notify class of existing methods or fields? + @Test + void givenEmptyClass() { + rewriteRun( + recipeSpec -> recipeSpec.recipe(new LombokUtilityClass()), + java( + """ + public class A { + } + """ + ) + ); + } + } @Test From 66e9dbf63ea56614390dc510e3c29bedb785106d Mon Sep 17 00:00:00 2001 From: Alexei Bratuhin Date: Sat, 17 Jun 2023 23:32:24 +0200 Subject: [PATCH 20/20] #3156 = remove todo --- .../test/java/org/openrewrite/java/LombokUtilityClassTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java index bc4660503f5..f067871ffda 100644 --- a/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java +++ b/rewrite-java/src/test/java/org/openrewrite/java/LombokUtilityClassTest.java @@ -23,7 +23,6 @@ /** * Cases to test: - * - Empty classes & interfaces * - inheritance * - instantiations of changed classes * - constructor