From baa552f3b15820bc4d05c9f12477ec73bf818331 Mon Sep 17 00:00:00 2001 From: timo <1398557+timo-a@users.noreply.github.com> Date: Wed, 11 Dec 2024 23:06:25 +0100 Subject: [PATCH 01/10] migrate recipes as-is --- .../java/migrate/lombok/NormalizeSetter.java | 180 +++++ .../migrate/lombok/NormalizeSetterTest.java | 671 ++++++++++++++++++ 2 files changed, 851 insertions(+) create mode 100644 src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java create mode 100644 src/test/java/org/openrewrite/java/migrate/lombok/NormalizeSetterTest.java diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java b/src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java new file mode 100644 index 000000000..b80e58f3d --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java @@ -0,0 +1,180 @@ +/* + * Copyright 2021 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.RequiredArgsConstructor;
+import lombok.Value;
+import org.jspecify.annotations.Nullable;
+import org.openrewrite.ExecutionContext;
+import org.openrewrite.ScanningRecipe;
+import org.openrewrite.Tree;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.java.ChangeMethodName;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.tree.J;
+import org.openrewrite.java.tree.JavaType;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.stream.Collectors;
+
+@Value
+@EqualsAndHashCode(callSuper = false)
+public class NormalizeSetter extends ScanningRecipe
+ * 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.Disabled;
+import org.junit.jupiter.api.Test;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.ChangeMethodName;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+
+import static org.openrewrite.java.Assertions.java;
+
+class NormalizeSetterTest implements RewriteTest {
+
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new NormalizeSetter())
+ .parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true));
+ }
+
+ @DocumentExample
+
+ @Test
+ void applyDirectly() {//TODO remove again
+ rewriteRun(
+ spec -> spec
+ .recipe(new ChangeMethodName("com.yourorg.whatever.A giveFoo()", "getFoo", null, null))
+ .parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true)),
+ // language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ int giveFoo() { return foo; }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ int getFoo() { return foo; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void applyDirectlyOnSetter() {//TODO remove again
+ rewriteRun(
+ spec -> spec
+ .recipe(new ChangeMethodName("com.yourorg.whatever.A storeFoo(int)", "setFoo", null, null))
+ .parser(JavaParser.fromJavaVersion().logCompilationWarningsAndErrors(true)),
+ // language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ public void storeFoo(int foo) {
+ this.foo = foo;
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ public void setFoo(int foo) {
+ this.foo = foo;
+ }
+ }
+ """
+ )
+ );
+ }
+
+
+
+ @Test
+ void renameInSingleClass() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ public void storeFoo(int foo) {
+ this.foo = foo;
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ public void setFoo(int foo) {
+ this.foo = foo;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void renameInSingleClassWhitespace() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ public void storeFoo( int foo ) {
+ this .foo = foo;
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ public void setFoo( int foo ) {
+ this .foo = foo;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void renamePrimitiveBooleanInSingleClass() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ boolean foo;
+ void storeFoo(boolean foo) { this.foo = foo; }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class A {
+ boolean foo;
+ void setFoo(boolean foo) { this.foo = foo; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void renameClassBooleanInSingleClass() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ Boolean foo;
+ void storeFoo(Boolean foo) { this.foo = foo; }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class A {
+ Boolean foo;
+ void setFoo(Boolean foo) { this.foo = foo; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noBoxing1() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ Boolean Foo;
+ void storeFoo(boolean foo) { this.foo = foo; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void noBoxing2() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ boolean Foo;
+ void storeFoo(Boolean foo) { this.foo = foo; }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void renameAcrossClasses() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ void storeFoo(int foo) { this.foo = foo; }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class A {
+ int foo = 9;
+ void setFoo(int foo) { this.foo = foo; }
+ }
+ """
+ ),// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+ class B {
+ void useIt() {
+ var a = new A();
+ a.storeFoo(4);
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+ class B {
+ void useIt() {
+ var a = new A();
+ a.setFoo(4);
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void shouldNotChangeOverridesOfExternalMethods() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ import java.util.Date;
+
+ class A extends Date {
+
+ private long foo;
+
+ @Override
+ public long setTime(long time) {
+ this.foo = time;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void withoutPackage() {
+ rewriteRun(// language=java
+ java(
+ """
+ class A {
+
+ private long foo;
+
+ public void setTime(long foo) {
+ this.foo = foo;
+ }
+ }
+ """,
+ """
+ class A {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void shouldChangeOverridesOfInternalMethods() {
+ rewriteRun(// language=java
+ java(
+ """
+ class A {
+
+ private long foo;
+
+ public void setTime(long foo) {
+ this.foo = foo;
+ }
+ }
+ """,
+ """
+ class A {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+ }
+ """
+ ),// language=java
+ java(
+ """
+ class B extends A {
+
+ @Override
+ public void setTime(long foo) {
+ }
+ }
+ """,
+ """
+ class B extends A {
+
+ @Override
+ public void setFoo(long foo) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void shouldNotRenameToExistingMethods() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ private long foo;
+
+ public void setTime(long foo) {
+ this.foo = foo;
+ }
+
+ public void setFoo(long foo) {
+ }
+ }
+ """
+ )
+ );
+ }
+
+ /**
+ * If two methods are effectively the same setter then only one can be renamed.
+ * Renaming both would result in a duplicate method definition, so we cannot do this.
+ * Ideally the other effective setter would have their usages renamed but be themselves deleted...
+ * TODO: create a second cleanup recipe that identifies redundant Setters (isEffectiveSetter + field already has the setter annotation)
+ * and redirects their usage (ChangeMethodName with both flags true) and then deletes them.
+ */
+ @Test
+ void shouldNotRenameTwoToTheSame() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ private long foo;
+
+ public void firstToBeRenamed(long foo) {
+ this.foo = foo;
+ }
+
+ public void secondToBeRenamed(long foo) {
+ this.foo = foo;
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+
+ public void secondToBeRenamed(long foo) {
+ this.foo = foo;
+ }
+ }
+ """
+ )
+ );
+ }
+
+ /**
+ * Methods in inner classes should be renamed as well.
+ */
+ @Test
+ void shouldWorkOnInnerClasses() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ class B {
+
+ private long foo;
+
+ public void storeFoo(long foo) {
+ this.foo = foo;
+ }
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ class B {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void shouldWorkOnInnerClasses2() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ class B {
+
+ class C {
+
+ private long foo;
+
+ public void giveFoo(long foo) {
+ this.foo = foo;
+ }
+ }}
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ class B {
+
+ class C {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+ }}
+ }
+ """
+ )
+ );
+ }
+
+ /**
+ * Methods on top level should be renamed just as well when there is an inner class.
+ */
+ @Test
+ void shouldWorkDespiteInnerClassesSameNameMethods() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ private long foo;
+
+ public void storeFoo(long foo) {
+ this.foo = foo;
+ }
+
+ class B {
+
+ private long foo;
+
+ public void storeFoo(long foo) {
+ this.foo = foo;
+ }
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+
+ class B {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ /**
+ * Methods on top level should be renamed just as well when there is an inner class.
+ */
+ @Test
+ void shouldWorkDespiteInnerClassesDifferentNameMethods() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ private long foo;
+
+ public void storeFoo(long foo) {
+ this.foo = foo;
+ }
+
+ class B {
+
+ private long ba;
+
+ public void storeBa(long ba) {
+ this.ba = ba;
+ }
+ }
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ private long foo;
+
+ public void setFoo(long foo) {
+ this.foo = foo;
+ }
+
+ class B {
+
+ private long ba;
+
+ public void setBa(long ba) {
+ this.ba = ba;
+ }
+ }
+ }
+ """
+ )
+ );
+ }
+
+ /**
+ * If existing method names need to be rotated in a loop the recipe should still work.
+ * For now this is not planned.
+ */
+ @Disabled("Not planned to fix but listed here for completeness")
+ @Test
+ void shouldWorkOnCircleCases() {
+ rewriteRun(// language=java
+ java(
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ int foo;
+
+ int bar;
+
+ public void setBar(long bar) {
+ this.foo = bar;
+ }
+
+ public void getFoo(long foo) {
+ this.bar = foo;
+ }
+
+ }
+ """,
+ """
+ package com.yourorg.whatever;
+
+ class A {
+
+ int foo;
+
+ int bar;
+
+ public void getFoo(long foo) {
+ this.foo = foo;
+ }
+
+ public void setBar(long bar) {
+ this.bar = bar;
+ }
+
+ }
+ """
+ )
+ );
+ }
+
+}
From 2077e75a97ef7d9ef676a866e412b762c9e80154 Mon Sep 17 00:00:00 2001
From: timo <1398557+timo-a@users.noreply.github.com>
Date: Sun, 15 Dec 2024 20:11:20 +0100
Subject: [PATCH 02/10] fix year in license
---
.../org/openrewrite/java/migrate/lombok/NormalizeSetter.java | 2 +-
.../openrewrite/java/migrate/lombok/NormalizeSetterTest.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java b/src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java
index b80e58f3d..4f8de64d3 100644
--- a/src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java
+++ b/src/main/java/org/openrewrite/java/migrate/lombok/NormalizeSetter.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 the original author or authors.
+ * 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.
diff --git a/src/test/java/org/openrewrite/java/migrate/lombok/NormalizeSetterTest.java b/src/test/java/org/openrewrite/java/migrate/lombok/NormalizeSetterTest.java
index edc61f761..24bb1b6d7 100644
--- a/src/test/java/org/openrewrite/java/migrate/lombok/NormalizeSetterTest.java
+++ b/src/test/java/org/openrewrite/java/migrate/lombok/NormalizeSetterTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2021 the original author or authors.
+ * 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.
From a752e8b4d1f4654694de4b41b5339eb6ca504926 Mon Sep 17 00:00:00 2001
From: timo <1398557+timo-a@users.noreply.github.com>
Date: Sun, 15 Dec 2024 20:11:51 +0100
Subject: [PATCH 03/10] bring back original helper methods
---
.../java/migrate/lombok/LombokUtils.java | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java b/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java
index a397bf904..454147b9a 100644
--- a/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java
+++ b/src/main/java/org/openrewrite/java/migrate/lombok/LombokUtils.java
@@ -21,6 +21,10 @@
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaType;
+import org.openrewrite.java.tree.Statement;
+
+import java.util.List;
+import java.util.stream.Collectors;
import static lombok.AccessLevel.*;
import static org.openrewrite.java.tree.J.Modifier.Type.*;
@@ -131,6 +135,43 @@ private static boolean hasMatchingSetterMethodName(J.MethodDeclaration method, S
return method.getSimpleName().equals("set" + StringUtils.capitalize(simpleName));
}
+ public static boolean isEffectivelySetter(J.MethodDeclaration method) {
+ boolean isVoid = "void".equals(method.getType().toString());
+ List