From 31498703fd800e578c245deb5c3d8d9f4dfeff94 Mon Sep 17 00:00:00 2001 From: jbessels <69236284+jbessels@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:25:47 +0100 Subject: [PATCH 1/8] Added file for AddSerialAnnotationToserialVersionUID --- ...AddSerialAnnotationToserialVersionUID.java | 140 ++++++++++++++++++ ...erialAnnotationToserialVersionUIDTest.java | 118 +++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java create mode 100644 src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java diff --git a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java new file mode 100644 index 000000000..136e37cf7 --- /dev/null +++ b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java @@ -0,0 +1,140 @@ +package org.openrewrite.staticanalysis; + +import org.jetbrains.annotations.NotNull; +import org.openrewrite.ExecutionContext; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.internal.ListUtils; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.TreeVisitingPrinter; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; +import org.openrewrite.java.tree.Statement; +import org.openrewrite.java.tree.TypeUtils; + +import java.time.Duration; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.UnaryOperator; + +public class AddSerialAnnotationToserialVersionUID extends Recipe { + + + + @Override + @NotNull + public String getDisplayName() { + System.out.println("Entering getDisplayName"); + return "Add @Serial annotation to serialVersionUID"; + } + + @Override + @NotNull + public String getDescription() { + System.out.println("Entering getDescription"); + return "Add a @Serial annotation above a serialVersionUID attribute identifier line."; + } + + @Override + @NotNull + public Duration getEstimatedEffortPerOccurrence() { + System.out.println("Entering getEstimatedEffortPerOccurrence"); + return Duration.ofMinutes(1); + } + + @Override + @NotNull + public TreeVisitor getVisitor() { + return new JavaIsoVisitor() { + + @Override + @NotNull + public J.MethodDeclaration visitMethodDeclaration(J.@NotNull MethodDeclaration method, @NotNull ExecutionContext ctx) { + // Anonymous classes are not of interest + System.out.println("Entering visitMethodDeclaration Anonymous classes are not of interest"); + return method; + } + + @Override + @NotNull + public J.VariableDeclarations visitVariableDeclarations(J.@NotNull VariableDeclarations multiVariable, @NotNull ExecutionContext ctx) { + // Anonymous classes are not of interest + System.out.println("Entering visitVariableDeclarations (plural with an s) Anonymous classes are not of interest"); + return multiVariable; + } + + @Override + @NotNull + public J.ClassDeclaration visitClassDeclaration(J.@NotNull ClassDeclaration classDecl, @NotNull ExecutionContext ctx) { + System.out.println("\n\nEntering visitClassDeclaration"); + System.out.println(TreeVisitingPrinter.printTree(getCursor())); + + System.out.println("BEFORE calling 'super.visitClassDeclaration'"); + J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); + System.out.println("AFTER calling 'super.visitClassDeclaration'"); + if (c.getKind() != J.ClassDeclaration.Kind.Type.Class) { + return c; + } + + AtomicBoolean needsSerialAnnotation = new AtomicBoolean(false); + c = c.withBody(c.getBody().withStatements(ListUtils.map(c.getBody().getStatements(), new UnaryOperator() { + @Override + public Statement apply(Statement s) { + if (!(s instanceof J.VariableDeclarations)) { + return s; + } + J.VariableDeclarations varDecls = (J.VariableDeclarations) s; + // Yes I know deprecated: varDecls.getAllAnnotations() + List allAnnotations = varDecls.getAllAnnotations(); + long count = allAnnotations.stream().count(); + System.out.println("Nr of annotations: " + count); + + AtomicBoolean hasSerialAnnotation = new AtomicBoolean(false); + for (J.Annotation annotation : allAnnotations) { + String simpleName = annotation.getSimpleName(); + System.out.println("Annotation name: " + simpleName); + if (simpleName.equals("Serial")) { + hasSerialAnnotation.set(true); + } + } + + + for (J.VariableDeclarations.NamedVariable v : varDecls.getVariables()) { + System.out.println("Variable: " + v.getSimpleName()); + if ("serialVersionUID".equals(v.getSimpleName())) { + + JavaType type = v.getType(); + + if (type instanceof JavaType.Primitive) { + if (TypeUtils.asPrimitive(v.getType()) == JavaType.Primitive.Long) { + if (hasSerialAnnotation.get()) { + System.out.println("Found serialVersionUID WITH @Serial annotation"); + needsSerialAnnotation.set(false); + } else { + System.out.println("Found serialVersionUID"); + needsSerialAnnotation.set(true); + } + return s; + } + } + } + } + return s; + } + }))); + if (needsSerialAnnotation.get()) { + System.out.println("needsSerialAnnotation TRUE: " + needsSerialAnnotation.get()); + c = JavaTemplate.apply("@Serial", getCursor(), c.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); + // It HAS to be added. This method seems to be the easiest way to do it. Does NOT work + maybeAddImport("java.io.Serial"); + } else { + System.out.println("needsSerialAnnotation FALSE: " + needsSerialAnnotation.get()); + } + System.out.println("I believe this is the very end of all processing\n\n"); + return c; + } + }; + } +} diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java new file mode 100644 index 000000000..7226eded2 --- /dev/null +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -0,0 +1,118 @@ +package org.openrewrite.staticanalysis; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class AddSerialAnnotationToserialVersionUIDTest implements RewriteTest { + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new AddSerialAnnotationToserialVersionUID()); + } + + @Test + void serialAnnotationAlreadyPresent() { + rewriteRun( + //language=java + java( + """ + import java.io.Serializable; + import java.io.Serial; + + public class Example implements Serializable { + String var1 = "first variable"; + @Serial + private static final long serialVersionUID = 1L; + int var3 = 666; + } + """ + ) + ); + } + + @Disabled + @Test + void addSerialAnnotation() { + rewriteRun( + //language=java + java( + """ + import java.io.Serializable; + import java.io.Serial; + + public class Example implements Serializable { + String var1 = "first variable"; + private static final long serialVersionUID = 1L; + int var3 = 666; + } + """, + """ + import java.io.Serializable; + import java.io.Serial; + + public class Example implements Serializable { + String var1 = "first variable"; + @Serial + private static final long serialVersionUID = 1L; + int var3 = 666; + String wolvie = "wolverine"; + } + """ + ) + ); + } + + + // Borowed from AddSerialVersionUidToSerializableTest of recipe AddSerialVersionUidToSerializableTest + @Disabled + @Test + void methodDeclarationsAreNotVisited() { + rewriteRun( + //language=java + java( + """ + import java.io.Serializable; + + public class Example implements Serializable { + private String fred; + private int numberOfFreds; + void doSomething() { + long serialVersionUID = 1L; + } + } + """ + ) + ); + } + + // Borowed from AddSerialVersionUidToSerializableTest of recipe AddSerialVersionUidToSerializableTest + @Disabled + @Test + void serializableInnerClass() { + rewriteRun( + //language=java + java( + """ + import java.io.Serializable; + public class Outer implements Serializable { + public static class Inner implements Serializable { + } + } + """, + """ + import java.io.Serializable; + public class Outer implements Serializable { + private static final long serialVersionUID = 1; + public static class Inner implements Serializable { + private static final long serialVersionUID = 1; + } + } + """ + ) + ); + } + +} \ No newline at end of file From 3e464682a21e5c88da0a2bbab2f699048fa3702f Mon Sep 17 00:00:00 2001 From: jbessels <69236284+jbessels@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:54:48 +0100 Subject: [PATCH 2/8] Ran gradlew licenseFormat --- .../AddSerialAnnotationToserialVersionUID.java | 15 +++++++++++++++ ...AddSerialAnnotationToserialVersionUIDTest.java | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java index 136e37cf7..f81b49ffb 100644 --- a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java +++ b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java @@ -1,3 +1,18 @@ +/* + * 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.staticanalysis; import org.jetbrains.annotations.NotNull; diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java index 7226eded2..27654ff69 100644 --- a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -1,3 +1,18 @@ +/* + * 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.staticanalysis; import org.junit.jupiter.api.Disabled; From c7437e20565bfc0fbb83af90f1b344ae67380e23 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 4 Jul 2024 11:03:40 +0200 Subject: [PATCH 3/8] Apply suggestions from code review --- .../staticanalysis/AddSerialAnnotationToserialVersionUID.java | 3 --- .../AddSerialAnnotationToserialVersionUIDTest.java | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java index f81b49ffb..c029b2cfa 100644 --- a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java +++ b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java @@ -41,21 +41,18 @@ public class AddSerialAnnotationToserialVersionUID extends Recipe { @Override @NotNull public String getDisplayName() { - System.out.println("Entering getDisplayName"); return "Add @Serial annotation to serialVersionUID"; } @Override @NotNull public String getDescription() { - System.out.println("Entering getDescription"); return "Add a @Serial annotation above a serialVersionUID attribute identifier line."; } @Override @NotNull public Duration getEstimatedEffortPerOccurrence() { - System.out.println("Entering getEstimatedEffortPerOccurrence"); return Duration.ofMinutes(1); } diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java index 27654ff69..77e01ff41 100644 --- a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -80,8 +80,6 @@ public class Example implements Serializable { ); } - - // Borowed from AddSerialVersionUidToSerializableTest of recipe AddSerialVersionUidToSerializableTest @Disabled @Test void methodDeclarationsAreNotVisited() { @@ -103,7 +101,6 @@ void doSomething() { ); } - // Borowed from AddSerialVersionUidToSerializableTest of recipe AddSerialVersionUidToSerializableTest @Disabled @Test void serializableInnerClass() { From 9c7fdc57272561f19c3387ac8100fd866c83914e Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Thu, 4 Jul 2024 11:11:31 +0200 Subject: [PATCH 4/8] Apply suggestions from code review Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../AddSerialAnnotationToserialVersionUID.java | 5 ----- .../AddSerialAnnotationToserialVersionUIDTest.java | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java index c029b2cfa..4267f0334 100644 --- a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java +++ b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java @@ -15,7 +15,6 @@ */ package org.openrewrite.staticanalysis; -import org.jetbrains.annotations.NotNull; import org.openrewrite.ExecutionContext; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; @@ -101,8 +100,6 @@ public Statement apply(Statement s) { // Yes I know deprecated: varDecls.getAllAnnotations() List allAnnotations = varDecls.getAllAnnotations(); long count = allAnnotations.stream().count(); - System.out.println("Nr of annotations: " + count); - AtomicBoolean hasSerialAnnotation = new AtomicBoolean(false); for (J.Annotation annotation : allAnnotations) { String simpleName = annotation.getSimpleName(); @@ -114,7 +111,6 @@ public Statement apply(Statement s) { for (J.VariableDeclarations.NamedVariable v : varDecls.getVariables()) { - System.out.println("Variable: " + v.getSimpleName()); if ("serialVersionUID".equals(v.getSimpleName())) { JavaType type = v.getType(); @@ -122,7 +118,6 @@ public Statement apply(Statement s) { if (type instanceof JavaType.Primitive) { if (TypeUtils.asPrimitive(v.getType()) == JavaType.Primitive.Long) { if (hasSerialAnnotation.get()) { - System.out.println("Found serialVersionUID WITH @Serial annotation"); needsSerialAnnotation.set(false); } else { System.out.println("Found serialVersionUID"); diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java index 77e01ff41..14b56aa25 100644 --- a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -48,7 +48,7 @@ public class Example implements Serializable { ); } - @Disabled + @DocumentExample @Test void addSerialAnnotation() { rewriteRun( From 65f37fe65bc85241704f7236ffca344040a491b9 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sat, 13 Jul 2024 02:07:37 +0200 Subject: [PATCH 5/8] Apply formatter and remove offending elements --- ...AddSerialAnnotationToserialVersionUID.java | 134 +++++++----------- ...erialAnnotationToserialVersionUIDTest.java | 110 +++++++------- 2 files changed, 107 insertions(+), 137 deletions(-) diff --git a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java index 4267f0334..119f556da 100644 --- a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java +++ b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java @@ -16,12 +16,14 @@ package org.openrewrite.staticanalysis; import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; import org.openrewrite.internal.ListUtils; +import org.openrewrite.internal.lang.NonNull; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaTemplate; -import org.openrewrite.java.TreeVisitingPrinter; +import org.openrewrite.java.search.UsesJavaVersion; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.Statement; @@ -34,114 +36,82 @@ import java.util.function.UnaryOperator; public class AddSerialAnnotationToserialVersionUID extends Recipe { - - - @Override - @NotNull public String getDisplayName() { - return "Add @Serial annotation to serialVersionUID"; + return "Add `@Serial` annotation to `serialVersionUID`"; } @Override - @NotNull public String getDescription() { - return "Add a @Serial annotation above a serialVersionUID attribute identifier line."; + return "Annotation any `serialVersionUID` fields with `@Serial` to indicate it's part of the serialization mechanism."; } @Override - @NotNull public Duration getEstimatedEffortPerOccurrence() { return Duration.ofMinutes(1); } @Override - @NotNull + @NonNull public TreeVisitor getVisitor() { - return new JavaIsoVisitor() { - - @Override - @NotNull - public J.MethodDeclaration visitMethodDeclaration(J.@NotNull MethodDeclaration method, @NotNull ExecutionContext ctx) { - // Anonymous classes are not of interest - System.out.println("Entering visitMethodDeclaration Anonymous classes are not of interest"); - return method; - } - - @Override - @NotNull - public J.VariableDeclarations visitVariableDeclarations(J.@NotNull VariableDeclarations multiVariable, @NotNull ExecutionContext ctx) { - // Anonymous classes are not of interest - System.out.println("Entering visitVariableDeclarations (plural with an s) Anonymous classes are not of interest"); - return multiVariable; - } - - @Override - @NotNull - public J.ClassDeclaration visitClassDeclaration(J.@NotNull ClassDeclaration classDecl, @NotNull ExecutionContext ctx) { - System.out.println("\n\nEntering visitClassDeclaration"); - System.out.println(TreeVisitingPrinter.printTree(getCursor())); - - System.out.println("BEFORE calling 'super.visitClassDeclaration'"); - J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); - System.out.println("AFTER calling 'super.visitClassDeclaration'"); - if (c.getKind() != J.ClassDeclaration.Kind.Type.Class) { - return c; - } - - AtomicBoolean needsSerialAnnotation = new AtomicBoolean(false); - c = c.withBody(c.getBody().withStatements(ListUtils.map(c.getBody().getStatements(), new UnaryOperator() { + return Preconditions.check( + new UsesJavaVersion<>(14), + new JavaIsoVisitor() { @Override - public Statement apply(Statement s) { - if (!(s instanceof J.VariableDeclarations)) { - return s; - } - J.VariableDeclarations varDecls = (J.VariableDeclarations) s; - // Yes I know deprecated: varDecls.getAllAnnotations() - List allAnnotations = varDecls.getAllAnnotations(); - long count = allAnnotations.stream().count(); - AtomicBoolean hasSerialAnnotation = new AtomicBoolean(false); - for (J.Annotation annotation : allAnnotations) { - String simpleName = annotation.getSimpleName(); - System.out.println("Annotation name: " + simpleName); - if (simpleName.equals("Serial")) { - hasSerialAnnotation.set(true); - } + @NonNull + public J.ClassDeclaration visitClassDeclaration(J.@NonNull ClassDeclaration classDecl, @NonNull ExecutionContext ctx) { + J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); + if (c.getKind() != J.ClassDeclaration.Kind.Type.Class) { + return c; } + AtomicBoolean needsSerialAnnotation = new AtomicBoolean(false); + c = c.withBody(c.getBody().withStatements(ListUtils.map(c.getBody().getStatements(), new UnaryOperator() { + @Override + public Statement apply(Statement s) { + if (!(s instanceof J.VariableDeclarations)) { + return s; + } + J.VariableDeclarations varDecls = (J.VariableDeclarations) s; + // Yes I know deprecated: varDecls.getAllAnnotations() + List allAnnotations = varDecls.getAllAnnotations(); + long count = allAnnotations.stream().count(); + AtomicBoolean hasSerialAnnotation = new AtomicBoolean(false); + for (J.Annotation annotation : allAnnotations) { + String simpleName = annotation.getSimpleName(); + if (simpleName.equals("Serial")) { + hasSerialAnnotation.set(true); + } + } - for (J.VariableDeclarations.NamedVariable v : varDecls.getVariables()) { - if ("serialVersionUID".equals(v.getSimpleName())) { - JavaType type = v.getType(); + for (J.VariableDeclarations.NamedVariable v : varDecls.getVariables()) { + if ("serialVersionUID".equals(v.getSimpleName())) { + JavaType type = v.getType(); - if (type instanceof JavaType.Primitive) { - if (TypeUtils.asPrimitive(v.getType()) == JavaType.Primitive.Long) { - if (hasSerialAnnotation.get()) { - needsSerialAnnotation.set(false); - } else { - System.out.println("Found serialVersionUID"); - needsSerialAnnotation.set(true); + if (type instanceof JavaType.Primitive) { + if (TypeUtils.asPrimitive(v.getType()) == JavaType.Primitive.Long) { + if (hasSerialAnnotation.get()) { + needsSerialAnnotation.set(false); + } else { + needsSerialAnnotation.set(true); + } + return s; + } } - return s; } } + return s; } + }))); + if (needsSerialAnnotation.get()) { + c = JavaTemplate.apply("@Serial", getCursor(), c.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); + // It HAS to be added. This method seems to be the easiest way to do it. Does NOT work + maybeAddImport("java.io.Serial"); } - return s; + return c; } - }))); - if (needsSerialAnnotation.get()) { - System.out.println("needsSerialAnnotation TRUE: " + needsSerialAnnotation.get()); - c = JavaTemplate.apply("@Serial", getCursor(), c.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); - // It HAS to be added. This method seems to be the easiest way to do it. Does NOT work - maybeAddImport("java.io.Serial"); - } else { - System.out.println("needsSerialAnnotation FALSE: " + needsSerialAnnotation.get()); } - System.out.println("I believe this is the very end of all processing\n\n"); - return c; - } - }; + ); } } diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java index 14b56aa25..31114cd5b 100644 --- a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; import org.openrewrite.test.RecipeSpec; import org.openrewrite.test.RewriteTest; @@ -34,16 +35,16 @@ void serialAnnotationAlreadyPresent() { //language=java java( """ - import java.io.Serializable; - import java.io.Serial; - - public class Example implements Serializable { - String var1 = "first variable"; - @Serial - private static final long serialVersionUID = 1L; - int var3 = 666; - } - """ + import java.io.Serializable; + import java.io.Serial; + + class Example implements Serializable { + String var1 = "first variable"; + @Serial + private static final long serialVersionUID = 1L; + int var3 = 666; + } + """ ) ); } @@ -55,27 +56,27 @@ void addSerialAnnotation() { //language=java java( """ - import java.io.Serializable; - import java.io.Serial; - - public class Example implements Serializable { - String var1 = "first variable"; - private static final long serialVersionUID = 1L; - int var3 = 666; - } - """, + import java.io.Serializable; + import java.io.Serial; + + class Example implements Serializable { + String var1 = "first variable"; + private static final long serialVersionUID = 1L; + int var3 = 666; + } + """, """ - import java.io.Serializable; - import java.io.Serial; - - public class Example implements Serializable { - String var1 = "first variable"; - @Serial - private static final long serialVersionUID = 1L; - int var3 = 666; - String wolvie = "wolverine"; - } - """ + import java.io.Serializable; + import java.io.Serial; + + class Example implements Serializable { + String var1 = "first variable"; + @Serial + private static final long serialVersionUID = 1L; + int var3 = 666; + String wolvie = "wolverine"; + } + """ ) ); } @@ -87,16 +88,16 @@ void methodDeclarationsAreNotVisited() { //language=java java( """ - import java.io.Serializable; - - public class Example implements Serializable { - private String fred; - private int numberOfFreds; - void doSomething() { - long serialVersionUID = 1L; - } - } - """ + import java.io.Serializable; + + class Example implements Serializable { + private String fred; + private int numberOfFreds; + void doSomething() { + long serialVersionUID = 1L; + } + } + """ ) ); } @@ -108,23 +109,22 @@ void serializableInnerClass() { //language=java java( """ - import java.io.Serializable; - public class Outer implements Serializable { - public static class Inner implements Serializable { - } - } - """, + import java.io.Serializable; + public class Outer implements Serializable { + public static class Inner implements Serializable { + } + } + """, """ - import java.io.Serializable; - public class Outer implements Serializable { - private static final long serialVersionUID = 1; - public static class Inner implements Serializable { - private static final long serialVersionUID = 1; - } - } - """ + import java.io.Serializable; + class Outer implements Serializable { + private static final long serialVersionUID = 1; + static class Inner implements Serializable { + private static final long serialVersionUID = 1; + } + } + """ ) ); } - } \ No newline at end of file From bbf76ba8d8e1b80e6262a38e537f3aec92b0b717 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sat, 13 Jul 2024 02:39:39 +0200 Subject: [PATCH 6/8] Complete implementation for fields --- ...AddSerialAnnotationToserialVersionUID.java | 74 +++++-------------- ...erialAnnotationToserialVersionUIDTest.java | 69 +++++++++++------ 2 files changed, 65 insertions(+), 78 deletions(-) diff --git a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java index 119f556da..1082f0311 100644 --- a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java +++ b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java @@ -19,21 +19,17 @@ import org.openrewrite.Preconditions; import org.openrewrite.Recipe; import org.openrewrite.TreeVisitor; -import org.openrewrite.internal.ListUtils; import org.openrewrite.internal.lang.NonNull; import org.openrewrite.java.JavaIsoVisitor; import org.openrewrite.java.JavaTemplate; +import org.openrewrite.java.search.FindAnnotations; import org.openrewrite.java.search.UsesJavaVersion; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; -import org.openrewrite.java.tree.Statement; import org.openrewrite.java.tree.TypeUtils; import java.time.Duration; import java.util.Comparator; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.UnaryOperator; public class AddSerialAnnotationToserialVersionUID extends Recipe { @Override @@ -58,58 +54,26 @@ public TreeVisitor getVisitor() { new UsesJavaVersion<>(14), new JavaIsoVisitor() { @Override - @NonNull - public J.ClassDeclaration visitClassDeclaration(J.@NonNull ClassDeclaration classDecl, @NonNull ExecutionContext ctx) { - J.ClassDeclaration c = super.visitClassDeclaration(classDecl, ctx); - if (c.getKind() != J.ClassDeclaration.Kind.Type.Class) { - return c; - } - - AtomicBoolean needsSerialAnnotation = new AtomicBoolean(false); - c = c.withBody(c.getBody().withStatements(ListUtils.map(c.getBody().getStatements(), new UnaryOperator() { - @Override - public Statement apply(Statement s) { - if (!(s instanceof J.VariableDeclarations)) { - return s; - } - J.VariableDeclarations varDecls = (J.VariableDeclarations) s; - // Yes I know deprecated: varDecls.getAllAnnotations() - List allAnnotations = varDecls.getAllAnnotations(); - long count = allAnnotations.stream().count(); - AtomicBoolean hasSerialAnnotation = new AtomicBoolean(false); - for (J.Annotation annotation : allAnnotations) { - String simpleName = annotation.getSimpleName(); - if (simpleName.equals("Serial")) { - hasSerialAnnotation.set(true); - } - } - - - for (J.VariableDeclarations.NamedVariable v : varDecls.getVariables()) { - if ("serialVersionUID".equals(v.getSimpleName())) { - JavaType type = v.getType(); - - if (type instanceof JavaType.Primitive) { - if (TypeUtils.asPrimitive(v.getType()) == JavaType.Primitive.Long) { - if (hasSerialAnnotation.get()) { - needsSerialAnnotation.set(false); - } else { - needsSerialAnnotation.set(true); - } - return s; - } - } - } - } - return s; - } - }))); - if (needsSerialAnnotation.get()) { - c = JavaTemplate.apply("@Serial", getCursor(), c.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); - // It HAS to be added. This method seems to be the easiest way to do it. Does NOT work + public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { + J.VariableDeclarations vd = super.visitVariableDeclarations(multiVariable, ctx); + if (isPrivateStaticFinalLongSerialVersionUID(vd) && + FindAnnotations.find(vd, "@java.io.Serial").isEmpty()) { maybeAddImport("java.io.Serial"); + return JavaTemplate.builder("@Serial") + .imports("java.io.Serial") + .build() + .apply(getCursor(), vd.getCoordinates().addAnnotation(Comparator.comparing(J.Annotation::getSimpleName))); } - return c; + return vd; + } + + private boolean isPrivateStaticFinalLongSerialVersionUID(J.VariableDeclarations vd) { + return vd.hasModifier(J.Modifier.Type.Private) && + vd.hasModifier(J.Modifier.Type.Static) && + vd.hasModifier(J.Modifier.Type.Final) && + TypeUtils.asPrimitive(vd.getType()) == JavaType.Primitive.Long && + vd.getVariables().size() == 1 && + "serialVersionUID".equals(vd.getVariables().get(0).getSimpleName()); } } ); diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java index 31114cd5b..9a856626e 100644 --- a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -15,43 +15,51 @@ */ package org.openrewrite.staticanalysis; -import org.junit.jupiter.api.Disabled; 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; +import static org.openrewrite.java.Assertions.javaVersion; class AddSerialAnnotationToserialVersionUIDTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { - spec.recipe(new AddSerialAnnotationToserialVersionUID()); + spec.recipe(new AddSerialAnnotationToserialVersionUID()) + .parser(JavaParser.fromJavaVersion()) + .allSources(sourceSpec -> sourceSpec.markers(javaVersion(17))); } + @DocumentExample @Test - void serialAnnotationAlreadyPresent() { + void addSerialAnnotation() { rewriteRun( //language=java java( """ import java.io.Serializable; + + class Example implements Serializable { + private static final long serialVersionUID = 1L; + } + """, + """ import java.io.Serial; + import java.io.Serializable; class Example implements Serializable { - String var1 = "first variable"; @Serial private static final long serialVersionUID = 1L; - int var3 = 666; } """ ) ); } - @DocumentExample @Test - void addSerialAnnotation() { + void shouldNoopIfAlreadyPresent() { rewriteRun( //language=java java( @@ -61,29 +69,34 @@ void addSerialAnnotation() { class Example implements Serializable { String var1 = "first variable"; + @Serial private static final long serialVersionUID = 1L; int var3 = 666; } - """, + """ + ) + ); + } + + @Test + void shouldNotAnnotateOnJava11() { + rewriteRun( + //language=java + java( """ import java.io.Serializable; - import java.io.Serial; - class Example implements Serializable { - String var1 = "first variable"; - @Serial + class Example implements Serializable { private static final long serialVersionUID = 1L; - int var3 = 666; - String wolvie = "wolverine"; } - """ + """, + spec -> spec.markers(javaVersion(11)) ) ); } - @Disabled @Test - void methodDeclarationsAreNotVisited() { + void shouldNotAnnotateOtherFields() { rewriteRun( //language=java java( @@ -91,8 +104,12 @@ void methodDeclarationsAreNotVisited() { import java.io.Serializable; class Example implements Serializable { - private String fred; - private int numberOfFreds; + static final long serialVersionUID = 1L; + private final long serialVersionUID = 1L; + private static long serialVersionUID = 1L; + private static final int serialVersionUID = 1L; + private static final long foo = 1L; + void doSomething() { long serialVersionUID = 1L; } @@ -102,24 +119,30 @@ void doSomething() { ); } - @Disabled @Test - void serializableInnerClass() { + void shouldAnnotatedFieldsInInnerClasses() { rewriteRun( //language=java java( """ import java.io.Serializable; - public class Outer implements Serializable { - public static class Inner implements Serializable { + + class Outer implements Serializable { + private static final long serialVersionUID = 1; + static class Inner implements Serializable { + private static final long serialVersionUID = 1; } } """, """ + import java.io.Serial; import java.io.Serializable; + class Outer implements Serializable { + @Serial private static final long serialVersionUID = 1; static class Inner implements Serializable { + @Serial private static final long serialVersionUID = 1; } } From 57242167d84eb492939b96311adaf34e55bced60 Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sat, 13 Jul 2024 02:42:48 +0200 Subject: [PATCH 7/8] Add missing newline at end of file --- .../AddSerialAnnotationToserialVersionUIDTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java index 9a856626e..5f6476bec 100644 --- a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -150,4 +150,4 @@ static class Inner implements Serializable { ) ); } -} \ No newline at end of file +} From 47cfb9beaa0766bdce804875a127fc0239f1cc1c Mon Sep 17 00:00:00 2001 From: Tim te Beek Date: Sat, 13 Jul 2024 02:47:03 +0200 Subject: [PATCH 8/8] Only annotate in serializable classes --- .../AddSerialAnnotationToserialVersionUID.java | 14 +++++++++++++- ...AddSerialAnnotationToserialVersionUIDTest.java | 15 ++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java index 1082f0311..9c209d93c 100644 --- a/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java +++ b/src/main/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUID.java @@ -24,6 +24,7 @@ import org.openrewrite.java.JavaTemplate; import org.openrewrite.java.search.FindAnnotations; import org.openrewrite.java.search.UsesJavaVersion; +import org.openrewrite.java.search.UsesType; import org.openrewrite.java.tree.J; import org.openrewrite.java.tree.JavaType; import org.openrewrite.java.tree.TypeUtils; @@ -51,8 +52,19 @@ public Duration getEstimatedEffortPerOccurrence() { @NonNull public TreeVisitor getVisitor() { return Preconditions.check( - new UsesJavaVersion<>(14), + Preconditions.and( + new UsesJavaVersion<>(14), + new UsesType<>("java.io.Serializable", true) + ), new JavaIsoVisitor() { + @Override + public J.ClassDeclaration visitClassDeclaration(J.ClassDeclaration classDecl, ExecutionContext executionContext) { + if (TypeUtils.isAssignableTo("java.io.Serializable", classDecl.getType())) { + return super.visitClassDeclaration(classDecl, executionContext); + } + return classDecl; + } + @Override public J.VariableDeclarations visitVariableDeclarations(J.VariableDeclarations multiVariable, ExecutionContext ctx) { J.VariableDeclarations vd = super.visitVariableDeclarations(multiVariable, ctx); diff --git a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java index 5f6476bec..5b18adc2d 100644 --- a/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java +++ b/src/test/java/org/openrewrite/staticanalysis/AddSerialAnnotationToserialVersionUIDTest.java @@ -28,7 +28,6 @@ class AddSerialAnnotationToserialVersionUIDTest implements RewriteTest { @Override public void defaults(RecipeSpec spec) { spec.recipe(new AddSerialAnnotationToserialVersionUID()) - .parser(JavaParser.fromJavaVersion()) .allSources(sourceSpec -> sourceSpec.markers(javaVersion(17))); } @@ -78,6 +77,20 @@ class Example implements Serializable { ); } + @Test + void shouldNotAnnotateNonSerializableClass() { + rewriteRun( + //language=java + java( + """ + class Example { + private static final long serialVersionUID = 1L; + } + """ + ) + ); + } + @Test void shouldNotAnnotateOnJava11() { rewriteRun(