From fd9d5270d6816225899b2647a3918a30ceaa669e Mon Sep 17 00:00:00 2001 From: timo <1398557+timo-a@users.noreply.github.com> Date: Tue, 24 Dec 2024 12:36:17 +0100 Subject: [PATCH 1/3] migrate recipe as-is --- .../migrate/lombok/UseDataParameterized.java | 123 ++++++++++++ .../use-lombok-data-convert-negligently.yml | 27 +++ .../META-INF/rewrite/use-lombok-data.yml | 25 +++ .../lombok/UseDataNegligentlyTest.java | 139 ++++++++++++++ .../java/migrate/lombok/UseDataTest.java | 179 ++++++++++++++++++ 5 files changed, 493 insertions(+) create mode 100644 src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java create mode 100644 src/main/resources/META-INF/rewrite/use-lombok-data-convert-negligently.yml create mode 100644 src/main/resources/META-INF/rewrite/use-lombok-data.yml create mode 100644 src/test/java/org/openrewrite/java/migrate/lombok/UseDataNegligentlyTest.java create mode 100644 src/test/java/org/openrewrite/java/migrate/lombok/UseDataTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java b/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java new file mode 100644 index 0000000000..1ce9fce77e --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java @@ -0,0 +1,123 @@ +/* + * Copyright 2024 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.migrate.lombok; + +import lombok.EqualsAndHashCode; +import lombok.Value; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaParser; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.tree.J; + +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static java.util.Comparator.comparing; + +@Value +@EqualsAndHashCode(callSuper = false) +public class UseDataParameterized extends Recipe { + @Override + public String getDisplayName() { + return "Summarize class annotations into @Data"; + } + + @Override + public String getDescription() { + return "Summarize class annotations into @Data."; + } + + List exceptions; + + @Override + public TreeVisitor getVisitor() { + return new Summarizer(exceptions == null ? Collections.emptyList(): exceptions); + } + + private static class Summarizer extends JavaIsoVisitor { + + Set annotationsToReplace = Stream + .of( + "ToString", + "EqualsAndHashCode", + "Getter", + "Setter", + "RequiredArgsConstructor") + .collect(Collectors.toSet()); + + Set needed; + + public Summarizer(List exceptions) { + needed = annotationsToReplace + .stream() + .filter(a -> !exceptions.contains(a)) + .collect(Collectors.toSet()); + } + + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext ctx) { + + J.ClassDeclaration visited = super.visitClassDeclaration(classDecl, ctx); + + Set namesOfRemainingAnotations = visited.getLeadingAnnotations() + .stream() + .map(J.Annotation::getSimpleName) + .collect(Collectors.toSet()); + Set namesOfRemovedAnnotations = classDecl.getLeadingAnnotations() + .stream() + .map(J.Annotation::getSimpleName) + .filter(a -> !namesOfRemainingAnotations.contains(a)) + .collect(Collectors.toSet()); + + if (visited != classDecl && namesOfRemovedAnnotations.containsAll(needed)) { + + maybeRemoveImport("lombok.ToString"); + maybeRemoveImport("lombok.EqualsAndHashCode"); + maybeRemoveImport("lombok.Getter"); + maybeRemoveImport("lombok.Setter"); + maybeRemoveImport("lombok.RequiredArgsConstructor"); + maybeAddImport("lombok.Data"); + + JavaTemplate template = JavaTemplate.builder("@Data\n") + .imports("lombok.Data") + .javaParser(JavaParser.fromJavaVersion().classpath("lombok")) + .build(); + + return template.apply( + updateCursor(visited), + visited.getCoordinates().addAnnotation(comparing(J.Annotation::getSimpleName))); + } + return classDecl; + } + + @Override + public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) { + return annotationsToReplace.contains(annotation.getSimpleName()) + && annotation.getArguments() == null //no arguments of any kind. Too strict? + //should only trigger on class annotation + && getCursor().getParent().getValue() instanceof J.ClassDeclaration + ? null + : annotation; + } + + } +} diff --git a/src/main/resources/META-INF/rewrite/use-lombok-data-convert-negligently.yml b/src/main/resources/META-INF/rewrite/use-lombok-data-convert-negligently.yml new file mode 100644 index 0000000000..f45cb20aaa --- /dev/null +++ b/src/main/resources/META-INF/rewrite/use-lombok-data-convert-negligently.yml @@ -0,0 +1,27 @@ +# +# Copyright 2024 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. +# + +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.migrate.lombok.UseDataNegligently +displayName: Summarize class annotations into @Data negligently +description: >- + Summarize class annotations into @Data even if @ToString or @EqualsAndHashCode are missing. You might need to manually clean up the result!. +recipeList: + - org.openrewrite.java.migrate.lombok.UseDataParameterized: + exceptions: + - EqualsAndHashCode + - ToString diff --git a/src/main/resources/META-INF/rewrite/use-lombok-data.yml b/src/main/resources/META-INF/rewrite/use-lombok-data.yml new file mode 100644 index 0000000000..21b64477a3 --- /dev/null +++ b/src/main/resources/META-INF/rewrite/use-lombok-data.yml @@ -0,0 +1,25 @@ +# +# Copyright 2024 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. +# + +--- +type: specs.openrewrite.org/v1beta/recipe +name: org.openrewrite.java.migrate.lombok.UseData +displayName: Summarize class annotations into @Data +description: >- + Summarize class annotations into @Data. +recipeList: + - org.openrewrite.java.migrate.lombok.UseDataParameterized: + exceptions: [] diff --git a/src/test/java/org/openrewrite/java/migrate/lombok/UseDataNegligentlyTest.java b/src/test/java/org/openrewrite/java/migrate/lombok/UseDataNegligentlyTest.java new file mode 100644 index 0000000000..9f016f33d0 --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/lombok/UseDataNegligentlyTest.java @@ -0,0 +1,139 @@ +/* + * Copyright 2024 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.migrate.lombok; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class UseDataNegligentlyTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipeFromResources("org.openrewrite.java.migrate.lombok.UseDataNegligently") + .parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true) + .classpath("lombok")); + } + + @DocumentExample + @Test + void replaceOneFieldData() { + rewriteRun(// language=java + java( + """ + import lombok.Getter; + import lombok.Setter; + import lombok.RequiredArgsConstructor; + + @Getter + @Setter + @RequiredArgsConstructor + class A {} + """, + """ + import lombok.Data; + + @Data + class A {} + """ + ) + ); + } + + @Test + void replaceWhenOptionalAnnotationsPresent() { + rewriteRun(// language=java + java( + """ + import lombok.ToString; + import lombok.EqualsAndHashCode; + import lombok.Getter; + import lombok.Setter; + import lombok.RequiredArgsConstructor; + + @ToString + @EqualsAndHashCode + @Getter + @Setter + @RequiredArgsConstructor + class A {} + """, + """ + import lombok.Data; + + @Data + class A {} + """ + ) + ); + } + + @Test + void otherAnnotationsAround() { + rewriteRun(// language=java + java( + """ + import lombok.*; + import lombok.extern.java.Log; + + @NoArgsConstructor + @ToString + @EqualsAndHashCode + @Getter + @Setter + @RequiredArgsConstructor + @Log + class A {} + """, + """ + import lombok.Data; + import lombok.NoArgsConstructor; + import lombok.extern.java.Log; + + @Data + @NoArgsConstructor + @Log + class A {} + """ + ) + ); + } + + @Test + void oneAnnotationMissing() { + rewriteRun(// language=java + java( + """ + import lombok.*; + import lombok.extern.java.Log; + + @NoArgsConstructor + @ToString + @EqualsAndHashCode + @Getter + @RequiredArgsConstructor + @Log + class A {} + """ + ) + ); + } + +} diff --git a/src/test/java/org/openrewrite/java/migrate/lombok/UseDataTest.java b/src/test/java/org/openrewrite/java/migrate/lombok/UseDataTest.java new file mode 100644 index 0000000000..bdc6db9eab --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/lombok/UseDataTest.java @@ -0,0 +1,179 @@ +/* + * Copyright 2024 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.migrate.lombok; + +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class UseDataTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipeFromResources("org.openrewrite.java.migrate.lombok.UseData") + .parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true) + .classpath("lombok")); + } + + @DocumentExample + @Test + void replaceOneFieldData() { + rewriteRun(// language=java + java( + """ + import lombok.ToString; + import lombok.EqualsAndHashCode; + import lombok.Getter; + import lombok.Setter; + import lombok.RequiredArgsConstructor; + + @ToString + @EqualsAndHashCode + @Getter + @Setter + @RequiredArgsConstructor + class A {} + """, + """ + import lombok.Data; + + @Data + class A {} + """ + ) + ); + } + + @Test + void otherAnnotationAbove() { + rewriteRun(// language=java + java( + """ + import lombok.ToString; + import lombok.EqualsAndHashCode; + import lombok.Getter; + import lombok.Setter; + import lombok.RequiredArgsConstructor; + import lombok.extern.java.Log; + + @Log + @ToString + @EqualsAndHashCode + @Getter + @Setter + @RequiredArgsConstructor + class A {} + """, + """ + import lombok.Data; + import lombok.extern.java.Log; + + @Data + @Log + class A {} + """ + ) + ); + } + + @Test + void otherAnnotationBelow() { + rewriteRun(// language=java + java( + """ + import lombok.ToString; + import lombok.EqualsAndHashCode; + import lombok.Getter; + import lombok.Setter; + import lombok.RequiredArgsConstructor; + import lombok.extern.java.Log; + + @ToString + @EqualsAndHashCode + @Getter + @Setter + @RequiredArgsConstructor + @Log + class A {} + """, + """ + import lombok.Data; + import lombok.extern.java.Log; + + @Data + @Log + class A {} + """ + ) + ); + } + + @Test + void otherAnnotationsAround() { + rewriteRun(// language=java + java( + """ + import lombok.*; + import lombok.extern.java.Log; + + @NoArgsConstructor + @ToString + @EqualsAndHashCode + @Getter + @Setter + @RequiredArgsConstructor + @Log + class A {} + """, + """ + import lombok.Data; + import lombok.NoArgsConstructor; + import lombok.extern.java.Log; + + @Data + @NoArgsConstructor + @Log + class A {} + """ + ) + ); + } + + @Test + void oneAnnotationMissing() { + rewriteRun(// language=java + java( + """ + import lombok.*; + import lombok.extern.java.Log; + + @NoArgsConstructor + @ToString + @EqualsAndHashCode + @Getter + @RequiredArgsConstructor + @Log + class A {} + """ + ) + ); + } + +} From 4641fb6f343bc7d24c4d121b21634b482347fbea Mon Sep 17 00:00:00 2001 From: timo <1398557+timo-a@users.noreply.github.com> Date: Sun, 16 Feb 2025 17:28:06 +0100 Subject: [PATCH 2/3] reviewbot suggestions --- .../java/migrate/lombok/UseDataParameterized.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java b/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java index 1ce9fce77e..6c87638fdb 100644 --- a/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java +++ b/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java @@ -111,12 +111,10 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex @Override public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) { - return annotationsToReplace.contains(annotation.getSimpleName()) - && annotation.getArguments() == null //no arguments of any kind. Too strict? + return annotationsToReplace.contains(annotation.getSimpleName()) && + annotation.getArguments() == null //no arguments of any kind. Too strict? //should only trigger on class annotation - && getCursor().getParent().getValue() instanceof J.ClassDeclaration - ? null - : annotation; + && getCursor().getParent().getValue() instanceof J.ClassDeclaration ? null : annotation; } } From c4a557ac821938f2b1f6ddd6a81af135aba444cf Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Mon, 11 Aug 2025 10:37:35 +0200 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../openrewrite/java/migrate/lombok/UseDataParameterized.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java b/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java index 6c87638fdb..c152cf253f 100644 --- a/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java +++ b/src/main/java/org/openrewrite/java/migrate/lombok/UseDataParameterized.java @@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode; import lombok.Value; +import org.jspecify.annotations.Nullable; import org.openrewrite.ExecutionContext; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; @@ -110,7 +111,7 @@ public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, Ex } @Override - public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) { + public J.@Nullable Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) { return annotationsToReplace.contains(annotation.getSimpleName()) && annotation.getArguments() == null //no arguments of any kind. Too strict? //should only trigger on class annotation