What version of OpenRewrite are you using?
- OpenRewrite v8.56.1 (but really latest commit)
- rewrite-openapi v0.21.0 (but really latest commit)
How are you running OpenRewrite?
I am debugging tests within rewrite-openapi directly, but the logic issue appears to be within rewrite.
What is the smallest, simplest way to reproduce the problem?
@Test
void replaceNestedAnnotation() {
rewriteRun(
spec -> spec.recipe(toRecipe(() -> new JavaIsoVisitor<>() {
private AnnotationMatcher ANNOTATION_MATCHER = new AnnotationMatcher("@NestedAnnotation");
public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) {
J.Annotation an = super.visitAnnotation(annotation, ctx);
if (!ANNOTATION_MATCHER.matches(an) || an.getArguments().isEmpty()) {
return an;
}
J.Assignment assignment = (J.Assignment) an.getArguments().get(0);
if (assignment.getVariable() instanceof J.Identifier && ((J.Identifier) assignment.getVariable()).getSimpleName().equals("a")) {
J.Identifier id = (J.Identifier) assignment.getVariable();
return JavaTemplate.builder("#{any()}")
.build()
.apply(
getCursor(),
an.getCoordinates().replaceArguments(),
assignment.withVariable(id.withSimpleName("b"))
);
return an;
}
})).parser(JavaParser.fromJavaVersion()
.dependsOn(
"""
import java.lang.annotation.Repeatable;
@Repeatable(NestedAnnotations.class)
@interface NestedAnnotation {
String a() default "";
}
""",
"""
@interface NestedAnnotations {
NestedAnnotation[] value() default {};
}
"""
)
),
//language=java
java(
"""
class A {
@NestedAnnotations(value = {
@NestedAnnotation(a = "first"),
@NestedAnnotation(a = "second")
})
void method() {}
}
""",
"""
class A {
@NestedAnnotations(value = {
@NestedAnnotation(b = "first"),
@NestedAnnotation(b = "second")
})
void method() {}
}
"""
)
);
}
It's necessary for this issue for it to use JavaTemplate, so the existing recipe for ChangeAnnotationAttributeName will not trigger this, for example.
What is the full stack trace of any errors you encountered?
java.lang.AssertionError: Failed to run recipe at Cursor{Annotation->JRightPadded(element=@NestedAnnotation(a = "first"), after=Space(comments=<0 comments>, whitespace=<empty>))->JContainer(before=Space(comments=<0 comments>, whitespace=<empty>), elementCount=2)->NewArray->JLeftPadded(before=Space(comments=<0 comments>, whitespace='·₁'), element=J.NewArray(padding=org.openrewrite.java.tree.J$NewArray$Padding@71ea1fda, id=48b94f48-dce9-4b65-8bcb-a02db5d6502c, prefix=Space(comments=<0 comments>, whitespace='·₁'), markers=Markers(id=dbedc218-2180-4b2c-8c72-fb033783d2fc, markers=[]), typeExpression=null, dimensions=[], initializer=[@NestedAnnotation(a = "first"), @NestedAnnotation(a = "second")], type=NestedAnnotation[]))->Assignment->JRightPadded(element=value = {
@NestedAnnotation(a = "first"),
@NestedAnnotation(a = "second")
}, after=Space(comments=<0 comments>, whitespace=<empty>))->JContainer(before=Space(comments=<0 comments>, whitespace=<empty>), elementCount=1)->Annotation->MethodDeclaration->JRightPadded(element=MethodDeclaration{A{name=method,return=void,parameters=[]}}, after=Space(comments=<0 comments>, whitespace=<empty>))->Block->ClassDeclaration->CompilationUnit->root}
at org.openrewrite.test.RewriteTest.lambda$defaultExecutionContext$14(RewriteTest.java:640)
at org.openrewrite.scheduling.RecipeRunCycle.handleError(RecipeRunCycle.java:291)
at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$8(RecipeRunCycle.java:230)
at org.openrewrite.scheduling.RecipeStack.reduce(RecipeStack.java:60)
at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$9(RecipeRunCycle.java:179)
at org.openrewrite.internal.InMemoryLargeSourceSet.lambda$edit$0(InMemoryLargeSourceSet.java:83)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:244)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:267)
at org.openrewrite.internal.InMemoryLargeSourceSet.edit(InMemoryLargeSourceSet.java:82)
at org.openrewrite.scheduling.RecipeRunCycle.editSources(RecipeRunCycle.java:177)
at org.openrewrite.RecipeScheduler.runRecipeCycles(RecipeScheduler.java:84)
at org.openrewrite.RecipeScheduler.scheduleRun(RecipeScheduler.java:41)
at org.openrewrite.Recipe.run(Recipe.java:441)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:377)
at org.openrewrite.test.RewriteTest.rewriteRun(RewriteTest.java:130)
at org.openrewrite.java.JavaTemplateAnnotationTest.replaceNestedAnnotation(JavaTemplateAnnotationTest.java:125)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: org.openrewrite.internal.RecipeRunException: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:281)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:154)
at org.openrewrite.java.JavaTemplate.apply(JavaTemplate.java:120)
at org.openrewrite.java.JavaTemplateAnnotationTest$4.visitAnnotation(JavaTemplateAnnotationTest.java:135)
at org.openrewrite.java.JavaTemplateAnnotationTest$4.visitAnnotation(JavaTemplateAnnotationTest.java:126)
at org.openrewrite.java.tree.J$Annotation.acceptJava(J.java:244)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visitAndCast(TreeVisitor.java:311)
at org.openrewrite.java.JavaVisitor.visitRightPadded(JavaVisitor.java:1374)
at org.openrewrite.java.JavaVisitor.lambda$visitContainer$34(JavaVisitor.java:1424)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:244)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:267)
at org.openrewrite.java.JavaVisitor.visitContainer(JavaVisitor.java:1424)
at org.openrewrite.java.JavaVisitor.visitNewArray(JavaVisitor.java:975)
at org.openrewrite.java.JavaIsoVisitor.visitNewArray(JavaIsoVisitor.java:259)
at org.openrewrite.java.JavaIsoVisitor.visitNewArray(JavaIsoVisitor.java:30)
at org.openrewrite.java.tree.J$NewArray.acceptJava(J.java:4578)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visitAndCast(TreeVisitor.java:311)
at org.openrewrite.java.JavaVisitor.visitLeftPadded(JavaVisitor.java:1402)
at org.openrewrite.java.JavaVisitor.visitAssignment(JavaVisitor.java:343)
at org.openrewrite.java.JavaIsoVisitor.visitAssignment(JavaIsoVisitor.java:73)
at org.openrewrite.java.JavaIsoVisitor.visitAssignment(JavaIsoVisitor.java:30)
at org.openrewrite.java.tree.J$Assignment.acceptJava(J.java:509)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visitAndCast(TreeVisitor.java:311)
at org.openrewrite.java.JavaVisitor.visitRightPadded(JavaVisitor.java:1374)
at org.openrewrite.java.JavaVisitor.lambda$visitContainer$34(JavaVisitor.java:1424)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:244)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:267)
at org.openrewrite.java.JavaVisitor.visitContainer(JavaVisitor.java:1424)
at org.openrewrite.java.JavaVisitor.visitAnnotation(JavaVisitor.java:256)
at org.openrewrite.java.JavaIsoVisitor.visitAnnotation(JavaIsoVisitor.java:48)
at org.openrewrite.java.JavaTemplateAnnotationTest$4.visitAnnotation(JavaTemplateAnnotationTest.java:129)
at org.openrewrite.java.JavaTemplateAnnotationTest$4.visitAnnotation(JavaTemplateAnnotationTest.java:126)
at org.openrewrite.java.tree.J$Annotation.acceptJava(J.java:244)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visitAndCast(TreeVisitor.java:311)
at org.openrewrite.java.JavaVisitor.lambda$visitMethodDeclaration$17(JavaVisitor.java:860)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:244)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:267)
at org.openrewrite.java.JavaVisitor.visitMethodDeclaration(JavaVisitor.java:860)
at org.openrewrite.java.JavaIsoVisitor.visitMethodDeclaration(JavaIsoVisitor.java:234)
at org.openrewrite.java.JavaIsoVisitor.visitMethodDeclaration(JavaIsoVisitor.java:30)
at org.openrewrite.java.tree.J$MethodDeclaration.acceptJava(J.java:4036)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visitAndCast(TreeVisitor.java:311)
at org.openrewrite.java.JavaVisitor.visitRightPadded(JavaVisitor.java:1374)
at org.openrewrite.java.JavaVisitor.lambda$visitBlock$4(JavaVisitor.java:400)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:244)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:267)
at org.openrewrite.java.JavaVisitor.visitBlock(JavaVisitor.java:399)
at org.openrewrite.java.JavaIsoVisitor.visitBlock(JavaIsoVisitor.java:88)
at org.openrewrite.java.JavaIsoVisitor.visitBlock(JavaIsoVisitor.java:30)
at org.openrewrite.java.tree.J$Block.acceptJava(J.java:848)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visitAndCast(TreeVisitor.java:311)
at org.openrewrite.java.JavaVisitor.visitClassDeclaration(JavaVisitor.java:486)
at org.openrewrite.java.JavaIsoVisitor.visitClassDeclaration(JavaIsoVisitor.java:108)
at org.openrewrite.java.JavaIsoVisitor.visitClassDeclaration(JavaIsoVisitor.java:30)
at org.openrewrite.java.tree.J$ClassDeclaration.acceptJava(J.java:1385)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visitAndCast(TreeVisitor.java:311)
at org.openrewrite.java.JavaVisitor.lambda$visitCompilationUnit$9(JavaVisitor.java:499)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:244)
at org.openrewrite.internal.ListUtils.map(ListUtils.java:267)
at org.openrewrite.java.JavaVisitor.visitCompilationUnit(JavaVisitor.java:499)
at org.openrewrite.java.JavaIsoVisitor.visitCompilationUnit(JavaIsoVisitor.java:113)
at org.openrewrite.java.JavaIsoVisitor.visitCompilationUnit(JavaIsoVisitor.java:30)
at org.openrewrite.java.tree.J$CompilationUnit.acceptJava(J.java:1667)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:154)
at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$7(RecipeRunCycle.java:210)
at io.micrometer.core.instrument.AbstractTimer.recordCallable(AbstractTimer.java:147)
at org.openrewrite.table.RecipeRunStats.recordEdit(RecipeRunStats.java:74)
at org.openrewrite.scheduling.RecipeRunCycle.lambda$editSources$8(RecipeRunCycle.java:206)
... 16 more
Caused by: java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:100)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:106)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:302)
at java.base/java.util.Objects.checkIndex(Objects.java:385)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at org.openrewrite.java.internal.template.JavaTemplateJavaExtension$1.visitAnnotation(JavaTemplateJavaExtension.java:73)
at org.openrewrite.java.internal.template.JavaTemplateJavaExtension$1.visitAnnotation(JavaTemplateJavaExtension.java:56)
at org.openrewrite.java.tree.J$Annotation.acceptJava(J.java:244)
at org.openrewrite.java.tree.J.accept(J.java:60)
at org.openrewrite.TreeVisitor.visit(TreeVisitor.java:245)
... 99 more
In essence, what I believe is happening is that when it tries to build the template back for the annotation (around here), it isn't finding a typical annotation target (class, method, field) as a direct parent, it's skipping adding parts of the template, resulting in a class wrapping an annotation that doesn't annotate anything, at least for this example. When it later tries to parse the annotations from the substituted template (around here), it's getting back 0 annotations, and then causing an IndexOutOfBoundsException.
Uncertain at this time if this is beyond my current knowledge to fix correctly, and with it being very core to how the templating works, will likely need assistance if I do move forward with it.
What version of OpenRewrite are you using?
How are you running OpenRewrite?
I am debugging tests within
rewrite-openapidirectly, but the logic issue appears to be withinrewrite.What is the smallest, simplest way to reproduce the problem?
It's necessary for this issue for it to use
JavaTemplate, so the existing recipe forChangeAnnotationAttributeNamewill not trigger this, for example.What is the full stack trace of any errors you encountered?
In essence, what I believe is happening is that when it tries to build the template back for the annotation (around here), it isn't finding a typical annotation target (class, method, field) as a direct parent, it's skipping adding parts of the template, resulting in a class wrapping an annotation that doesn't annotate anything, at least for this example. When it later tries to parse the annotations from the substituted template (around here), it's getting back 0 annotations, and then causing an
IndexOutOfBoundsException.Are you interested in contributing a fix to OpenRewrite?
Uncertain at this time if this is beyond my current knowledge to fix correctly, and with it being very core to how the templating works, will likely need assistance if I do move forward with it.