diff --git a/src/main/java/org/openrewrite/java/migrate/lang/ExplicitRecordImport.java b/src/main/java/org/openrewrite/java/migrate/lang/ExplicitRecordImport.java new file mode 100644 index 000000000..e5576cb5e --- /dev/null +++ b/src/main/java/org/openrewrite/java/migrate/lang/ExplicitRecordImport.java @@ -0,0 +1,62 @@ +/* + * Copyright 2024 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.lang; + +import org.openrewrite.ExecutionContext; +import org.openrewrite.Preconditions; +import org.openrewrite.Recipe; +import org.openrewrite.TreeVisitor; +import org.openrewrite.java.JavaIsoVisitor; +import org.openrewrite.java.search.UsesType; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaSourceFile; +import org.openrewrite.java.tree.JavaType; + +public class ExplicitRecordImport extends Recipe { + @Override + public String getDisplayName() { + return "Add explicit import for `Record` classes"; + } + + @Override + public String getDescription() { + return "Add explicit import for `Record` classes when upgrading past Java 14+, to avoid conflicts with `java.lang.Record`."; + } + + @Override + public TreeVisitor getVisitor() { + return Preconditions.check( + new UsesType<>("*..Record", false), + new JavaIsoVisitor() { + @Override + public J.CompilationUnit visitCompilationUnit(J.CompilationUnit cu, ExecutionContext ctx) { + JavaSourceFile javaSourceFile = getCursor().firstEnclosing(JavaSourceFile.class); + if (javaSourceFile != null) { + for (JavaType type : cu.getTypesInUse().getTypesInUse()) { + if (type instanceof JavaType.FullyQualified) { + JavaType.FullyQualified ref = (JavaType.FullyQualified) type; + if ("Record".equals(ref.getClassName()) && !ref.getPackageName().startsWith("java.lang")) { + maybeAddImport(ref.getFullyQualifiedName()); + } + } + } + } + return cu; + } + } + ); + } +} diff --git a/src/main/resources/META-INF/rewrite/java-version-17.yml b/src/main/resources/META-INF/rewrite/java-version-17.yml index 798059e8c..4eb233dcd 100644 --- a/src/main/resources/META-INF/rewrite/java-version-17.yml +++ b/src/main/resources/META-INF/rewrite/java-version-17.yml @@ -34,6 +34,7 @@ recipeList: - org.openrewrite.java.migrate.RemovedRuntimeTraceMethods - org.openrewrite.java.migrate.RemovedToolProviderConstructor - org.openrewrite.java.migrate.RemovedModifierAndConstantBootstrapsConstructors + - org.openrewrite.java.migrate.lang.ExplicitRecordImport - org.openrewrite.java.migrate.lang.UseTextBlocks: convertStringsWithoutNewlines: false - org.openrewrite.java.migrate.lang.StringFormatted: diff --git a/src/test/java/org/openrewrite/java/migrate/lang/ExplicitRecordImportTest.java b/src/test/java/org/openrewrite/java/migrate/lang/ExplicitRecordImportTest.java new file mode 100644 index 000000000..f7da06d7f --- /dev/null +++ b/src/test/java/org/openrewrite/java/migrate/lang/ExplicitRecordImportTest.java @@ -0,0 +1,123 @@ +/* + * Copyright 2024 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.lang; + +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.openrewrite.DocumentExample; +import org.openrewrite.Issue; +import org.openrewrite.java.JavaParser; +import org.openrewrite.test.RecipeSpec; +import org.openrewrite.test.RewriteTest; + +import static org.openrewrite.java.Assertions.java; + +class ExplicitRecordImportTest implements RewriteTest { + + @Override + public void defaults(RecipeSpec spec) { + spec.recipe(new ExplicitRecordImport()) + //language=java + .parser(JavaParser.fromJavaVersion().dependsOn(""" + package com.acme.music; + public class Record { + String name; + } + """ + ) + ); + } + + @DocumentExample + @Issue("https://github.com/openrewrite/rewrite-migrate-java/issues/540") + @Test + void addImportFromSamePackage() { + rewriteRun( + //language=java + java( + """ + package com.acme.music; + + public class Test { + Record record; + } + """, + """ + package com.acme.music; + + import com.acme.music.Record; + + public class Test { + Record record; + } + """ + ) + ); + } + + + @Test + @Disabled("Not handled yet; deemed unlikely") + void noChangeIfAlreadyFullyQualified() { + rewriteRun( + //language=java + java( + """ + package com.acme.music; + + public class Test { + com.acme.music.Record record; + } + """ + ) + ); + } + + + @Test + void noChangeIfAlreadyImported() { + rewriteRun( + //language=java + java( + """ + package com.acme.music; + + import com.acme.music.Record; + + public class Test { + Record record; + } + """ + ) + ); + } + + @Test + void noImportAddedForJavaLangRecord() { + rewriteRun( + //language=java + java( + """ + package foo.bar; + + public class Test { + Record record; + } + """ + ) + ); + } +}