diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000000..9841008d7e --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,13 @@ +{ + "permissions": { + "allow": [ + "Bash(./gradlew test:*)", + "Bash(find:*)", + "WebFetch(domain:github.com)", + "Bash(git checkout:*)", + "Bash(git add:*)", + "Bash(git commit:*)" + ], + "deny": [] + } +} \ No newline at end of file diff --git a/src/main/java/org/openrewrite/java/migrate/lombok/LombokOnXToOnX_.java b/src/main/java/org/openrewrite/java/migrate/lombok/LombokOnXToOnX_.java new file mode 100644 index 0000000000..7052490aaf --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/lombok/LombokOnXToOnX_.java @@ -0,0 +1,115 @@ +/* + * Copyright 2025 the original author or authors. + *
+ * Licensed under the Moderne Source Available License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *
+ * https://docs.moderne.io/licensing/moderne-source-available-license + *
+ * 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.openrewrite.ExecutionContext;
+import org.openrewrite.Preconditions;
+import org.openrewrite.Recipe;
+import org.openrewrite.TreeVisitor;
+import org.openrewrite.internal.ListUtils;
+import org.openrewrite.java.AnnotationMatcher;
+import org.openrewrite.java.JavaIsoVisitor;
+import org.openrewrite.java.search.UsesType;
+import org.openrewrite.java.tree.Expression;
+import org.openrewrite.java.tree.J;
+
+import java.util.Collections;
+import java.util.Set;
+
+public class LombokOnXToOnX_ extends Recipe {
+
+ private static final AnnotationMatcher LOMBOK_GETTER = new AnnotationMatcher("@lombok.Getter");
+ private static final AnnotationMatcher LOMBOK_SETTER = new AnnotationMatcher("@lombok.Setter");
+ private static final AnnotationMatcher LOMBOK_WITH = new AnnotationMatcher("@lombok.With");
+ private static final AnnotationMatcher LOMBOK_WITHER = new AnnotationMatcher("@lombok.Wither");
+ private static final AnnotationMatcher LOMBOK_EQUALS_AND_HASHCODE = new AnnotationMatcher("@lombok.EqualsAndHashCode");
+ private static final AnnotationMatcher LOMBOK_TO_STRING = new AnnotationMatcher("@lombok.ToString");
+ private static final AnnotationMatcher LOMBOK_REQUIRED_ARGS_CONSTRUCTOR = new AnnotationMatcher("@lombok.RequiredArgsConstructor");
+ private static final AnnotationMatcher LOMBOK_ALL_ARGS_CONSTRUCTOR = new AnnotationMatcher("@lombok.AllArgsConstructor");
+ private static final AnnotationMatcher LOMBOK_NO_ARGS_CONSTRUCTOR = new AnnotationMatcher("@lombok.NoArgsConstructor");
+
+ @Override
+ public String getDisplayName() {
+ return "Migrate Lombok's `@__` syntax to `onX_` for Java 8+";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Migrates Lombok's `onX` annotations from the Java 7 style using `@__` to the Java 8+ style " +
+ "using `onX_`. For example, `@Getter(onMethod=@__({@Id}))` becomes `@Getter(onMethod_={@Id})`.";
+ }
+
+ @Override
+ public Set
+ * Licensed under the Moderne Source Available License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://docs.moderne.io/licensing/moderne-source-available-license
+ *
+ * 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.junitpioneer.jupiter.ExpectedToFail;
+import org.openrewrite.DocumentExample;
+import org.openrewrite.java.JavaParser;
+import org.openrewrite.test.RecipeSpec;
+import org.openrewrite.test.RewriteTest;
+import org.openrewrite.test.TypeValidation;
+
+import static org.openrewrite.java.Assertions.java;
+
+class LombokOnXToOnX_Test implements RewriteTest {
+ @Override
+ public void defaults(RecipeSpec spec) {
+ spec.recipe(new LombokOnXToOnX_())
+ .parser(JavaParser.fromJavaVersion().classpath("lombok"))
+ .typeValidationOptions(TypeValidation.all().identifiers(false));
+ }
+
+ @DocumentExample
+ @Test
+ void migrateGetterOnMethod() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.Getter;
+ class Example {
+ @Getter(onMethod=@__({@Deprecated}))
+ private String field;
+ }
+ """,
+ """
+ import lombok.Getter;
+ class Example {
+ @Getter(onMethod_={@Deprecated})
+ private String field;
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void migrateSetterOnParam() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.Setter;
+ class Example {
+ @Setter(onParam=@__({@SuppressWarnings("unchecked")}))
+ private long unid;
+ }
+ """,
+ """
+ import lombok.Setter;
+ class Example {
+ @Setter(onParam_={@SuppressWarnings("unchecked")})
+ private long unid;
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void migrateMultipleAnnotations() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.Getter;
+ import lombok.Setter;
+ class Example {
+ @Getter(onMethod=@__({@Deprecated, @SuppressWarnings("all")}))
+ @Setter(onParam=@__({@SuppressWarnings("unchecked")}))
+ private long unid;
+ }
+ """,
+ """
+ import lombok.Getter;
+ import lombok.Setter;
+ class Example {
+ @Getter(onMethod_={@Deprecated, @SuppressWarnings("all")})
+ @Setter(onParam_={@SuppressWarnings("unchecked")})
+ private long unid;
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void migrateConstructorAnnotations() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.RequiredArgsConstructor;
+ @RequiredArgsConstructor(onConstructor=@__({@Deprecated}))
+ class Example {
+ private final String field;
+ }
+ """,
+ """
+ import lombok.RequiredArgsConstructor;
+ @RequiredArgsConstructor(onConstructor_={@Deprecated})
+ class Example {
+ private final String field;
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void doNotChangeIfAlreadyMigrated() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.Getter;
+ class Example {
+ @Getter(onMethod_={@Deprecated})
+ private String field;
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void doNotChangeIfNoOnXParameter() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.Getter;
+ class Example {
+ @Getter(lazy=true)
+ private final String field = "value";
+ }
+ """
+ )
+ );
+ }
+
+ @Test
+ void handleEmptyAnnotationList() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.Getter;
+ class Example {
+ @Getter(onMethod=@__({}))
+ private String field;
+ }
+ """,
+ """
+ import lombok.Getter;
+ class Example {
+ @Getter(onMethod_={})
+ private String field;
+ }
+ """
+ )
+ );
+ }
+
+ @ExpectedToFail("Parser bug with @__ syntax causes test failure")
+ @Test
+ void handleWithAnnotation() {
+ //language=java
+ rewriteRun(
+ java(
+ """
+ import lombok.With;
+ class Example {
+ @With(onParam=@__({@SuppressWarnings("unused")}))
+ private final String field;
+
+ Example(String field) {
+ this.field = field;
+ }
+ }
+ """,
+ """
+ import lombok.With;
+ class Example {
+ @With(onParam_={@SuppressWarnings("unused")})
+ private final String field;
+
+ Example(String field) {
+ this.field = field;
+ }
+ }
+ """
+ )
+ );
+ }
+}