diff --git a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java index 5f3295c40a71..389ec81d3cda 100644 --- a/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java +++ b/rewrite-java-11/src/main/java/org/openrewrite/java/isolated/ReloadableJava11TypeMapping.java @@ -693,7 +693,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java index b7c7ff483ff9..1127166ea7a4 100644 --- a/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java +++ b/rewrite-java-17/src/main/java/org/openrewrite/java/isolated/ReloadableJava17TypeMapping.java @@ -701,7 +701,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java index f55a32132b8e..90cd5685319d 100644 --- a/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java +++ b/rewrite-java-21/src/main/java/org/openrewrite/java/isolated/ReloadableJava21TypeMapping.java @@ -712,7 +712,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java index d52555038102..813e7b973950 100644 --- a/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java +++ b/rewrite-java-21/src/test/java/org/openrewrite/java/Java21ParserTest.java @@ -17,11 +17,17 @@ import org.junit.jupiter.api.Test; import org.openrewrite.InMemoryExecutionContext; +import org.openrewrite.SourceFile; +import org.openrewrite.java.tree.J; +import org.openrewrite.java.tree.JavaType; import org.openrewrite.test.RewriteTest; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; class Java21ParserTest implements RewriteTest { @@ -30,4 +36,35 @@ void shouldLoadResourceFromClasspath() throws IOException { Files.deleteIfExists(Paths.get(System.getProperty("user.home"), ".rewrite", "classpath", "jackson-annotations-2.17.1.jar")); rewriteRun(spec -> spec.parser(JavaParser.fromJavaVersion().classpathFromResources(new InMemoryExecutionContext(), "jackson-annotations"))); } + + @Test + void testPreserveAnnotationsFromClassepath() throws IOException { + JavaParser p = JavaParser.fromJavaVersion().build(); + /** + * Thread.stop() is deprecated in Java 1.2: + * + * @Deprecated(since="1.2", forRemoval=true) + * public final void stop() { + * throw new UnsupportedOperationException(); + * } + */ + List sourceFiles = p.parse( + """ + class Test { + public void test() { + Thread.currentThread().stop(); + } + } + """ + ).toList(); + J.CompilationUnit cu = (J.CompilationUnit) sourceFiles.get(0); + J.MethodDeclaration md = (J.MethodDeclaration) cu.getClasses().get(0).getBody().getStatements().get(0); + J.MethodInvocation mi = (J.MethodInvocation) md.getBody().getStatements().get(0); + JavaType.Annotation annotation = (JavaType.Annotation) mi.getMethodType().getAnnotations().get(0); + + assertEquals("since", annotation.values.get(0).getMethod().getName()); + assertEquals("1.2", annotation.values.get(0).getValue()); + assertEquals("forRemoval", annotation.values.get(1).getMethod().getName()); + assertEquals("true", annotation.values.get(1).getValue()); + } } diff --git a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java index 0d8408dd0263..31ef49df68d4 100644 --- a/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java +++ b/rewrite-java-8/src/main/java/org/openrewrite/java/ReloadableJava8TypeMapping.java @@ -694,7 +694,10 @@ private void completeClassSymbol(Symbol.ClassSymbol classSymbol) { if (retention != null && retention.value() == RetentionPolicy.SOURCE) { continue; } - annotations.add(annotType); + List annotationValues = a.values.stream().map(attr -> new JavaType.AnnotationValue( + methodDeclarationType(attr.fst, annotType), attr.snd.getValue().toString())).toList(); + JavaType.Annotation annotation = new JavaType.Annotation(annotType, annotationValues); + annotations.add(annotation); } } return annotations; diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java index 112861469e84..326127a2ffa1 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaType.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.annotation.*; import lombok.AccessLevel; +import lombok.Data; import lombok.Getter; import lombok.With; import lombok.experimental.FieldDefaults; @@ -26,6 +27,7 @@ import org.openrewrite.internal.ListUtils; import org.openrewrite.java.internal.DefaultJavaTypeSignatureBuilder; +import java.lang.invoke.MethodType; import java.util.*; import java.util.function.Function; import java.util.regex.Pattern; @@ -626,6 +628,83 @@ public static ShallowClass build(String fullyQualifiedName) { } } + @Data + class AnnotationValue { + private final Method method; + private final String value; + } + + class Annotation extends FullyQualified { + + public final List values; + public final FullyQualified type; + + public Annotation(FullyQualified type, List values) { + this.type = type; + this.values = values; + } + + @Override + public String getFullyQualifiedName() { + return type.getFullyQualifiedName(); + } + + @Override + public FullyQualified withFullyQualifiedName(String fullyQualifiedName) { + return null; + } + + @Override + public List getAnnotations() { + return type.getAnnotations(); + } + + @Override + public boolean hasFlags(Flag... test) { + return false; + } + + @Override + public Set getFlags() { + return type.getFlags(); + } + + @Override + public List getInterfaces() { + return type.getInterfaces(); + } + + @Override + public Kind getKind() { + return type.getKind(); + } + + @Override + public List getMembers() { + return type.getMembers(); + } + + @Override + public List getMethods() { + return type.getMethods(); + } + + @Override + public List getTypeParameters() { + return type.getTypeParameters(); + } + + @Override + public @Nullable FullyQualified getOwningClass() { + return type.getOwningClass(); + } + + @Override + public @Nullable FullyQualified getSupertype() { + return type.getSupertype(); + } + } + @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) class Parameterized extends FullyQualified { @Getter