Skip to content

Commit

Permalink
Polish ReplaceAnnotation recipe, ensure it can type attribute the ann…
Browse files Browse the repository at this point in the history
…otations it produces correctly.
  • Loading branch information
sambsnyd committed Jun 1, 2024
1 parent 246b53e commit 4831b1f
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,8 @@

import lombok.EqualsAndHashCode;
import lombok.Value;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.*;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.JavaCoordinates;
import org.openrewrite.java.tree.JavaType;
Expand All @@ -40,6 +38,15 @@ public class ReplaceAnnotation extends Recipe {
example = "@org.jetbrains.annotations.NotNull(\"Null not permitted\")")
String annotationTemplateToInsert;

@Option(displayName = "Classpath resource",
description = "If the annotation's type is defined by a jar within the META-INF/rewrite/classpath directory provide its name here " +
"so that it can be loaded. " +
"When this parameter is not passed the runtime classpath of the recipe is provided to the parser producing the new annotation. " +
"This is necessary when the annotation is not on the runtime classpath of the recipe and isn't in the Java standard library.",
required = false)
@Nullable
String classpathResourceName;

@Override
public String getDisplayName() {
return "Replace Annotation";
Expand All @@ -53,9 +60,19 @@ public String getDescription() {

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new ReplaceAnnotationVisitor(
new AnnotationMatcher(annotationPatternToReplace),
JavaTemplate.builder(annotationTemplateToInsert).javaParser(JavaParser.fromJavaVersion()).build());
return new TreeVisitor<Tree, ExecutionContext>() {
@Override
public @Nullable Tree visit(@Nullable Tree tree, ExecutionContext ctx) {
JavaTemplate.Builder templateBuilder = JavaTemplate.builder(annotationTemplateToInsert);
if (classpathResourceName == null) {
templateBuilder.javaParser(JavaParser.fromJavaVersion().classpath(JavaParser.runtimeClasspath()));
} else {
templateBuilder.javaParser(JavaParser.fromJavaVersion().classpathFromResources(ctx, classpathResourceName));
}
return new ReplaceAnnotationVisitor(new AnnotationMatcher(annotationPatternToReplace), templateBuilder.build())
.visit(tree, ctx);
}
};
}

public static class ReplaceAnnotationVisitor extends JavaIsoVisitor<ExecutionContext> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package org.openrewrite.java;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.openrewrite.DocumentExample;
Expand All @@ -24,7 +23,6 @@

import static org.openrewrite.java.Assertions.java;

@Disabled
class ReplaceAnnotationTest implements RewriteTest {
@Override
public void defaults(RecipeSpec spec) {
Expand All @@ -35,87 +33,98 @@ public void defaults(RecipeSpec spec) {
class OnMatch {
@Test
void matchNoPrams() {
rewriteRun(spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull", "@lombok.NonNull")), java("""
import org.jetbrains.annotations.NotNull;
class A {
@NotNull
String testMethod() {}
}
""", """
import lombok.NonNull;
class A {
@NonNull
String testMethod() {}
}
"""));
rewriteRun(
spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull", "@lombok.NonNull", null)),
java("""
import org.jetbrains.annotations.NotNull;
class A {
@NotNull
String testMethod() {}
}
""", """
import lombok.NonNull;
class A {
@NonNull
String testMethod() {}
}
"""));
}

@Test
@DocumentExample
void matchWithPrams() {
rewriteRun(spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull(\"Test\")", "@lombok.NonNull")), java("""
import org.jetbrains.annotations.NotNull;
class A {
@NotNull("Test")
String testMethod() {}
}
""", """
import lombok.NonNull;
class A {
@NonNull
String testMethod() {}
}
"""));
rewriteRun(
spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull(\"Test\")", "@lombok.NonNull", null)),
java("""
import org.jetbrains.annotations.NotNull;
class A {
@NotNull("Test")
String testMethod() {}
}
""", """
import lombok.NonNull;
class A {
@NonNull
String testMethod() {}
}
"""));
}

@Test
void insertWithParams() {
rewriteRun(spec -> spec.recipe(new ReplaceAnnotation("@lombok.NonNull", "@org.jetbrains.annotations.NotNull(\"Test\")")), java("""
import lombok.NonNull;
class A {
@NonNull
String testMethod() {}
}
""", """
import org.jetbrains.annotations.NotNull;
class A {
@NotNull("Test")
String testMethod() {}
}
"""));
rewriteRun(
spec -> spec.recipe(new ReplaceAnnotation("@lombok.NonNull", "@org.jetbrains.annotations.NotNull(\"Test\")", null)),
java("""
import lombok.NonNull;
class A {
@NonNull
String testMethod() {}
}
""", """
import org.jetbrains.annotations.NotNull;
class A {
@NotNull("Test")
String testMethod() {}
}
"""));
}
}

@Nested
class NoMatch {
@Test
void noMatchOtherType() {
rewriteRun(spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull", "@lombok.NonNull")), java("""
import org.jetbrains.annotations.Nullable;
class A {
@Nullable("Test")
String testMethod() {}
}
"""));
rewriteRun(
spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull", "@lombok.NonNull", null)),
java("""
import org.jetbrains.annotations.Nullable;
class A {
@Nullable("Test")
String testMethod() {}
}
"""));
}

@Test
void noMatchParameter() {
rewriteRun(spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull(\"Test\")", "@lombok.NonNull")), java("""
import org.jetbrains.annotations.Nullable;
class A {
@Nullable("Other")
String testMethod() {}
}
"""));
rewriteRun(
spec -> spec.recipe(new ReplaceAnnotation("@org.jetbrains.annotations.NotNull(\"Test\")", "@lombok.NonNull", null)),
java("""
import org.jetbrains.annotations.Nullable;
class A {
@Nullable("Other")
String testMethod() {}
}
""")
);
}
}
}

0 comments on commit 4831b1f

Please sign in to comment.