Skip to content

Commit 4c870fa

Browse files
Added additional tests for nested annotations, and a fix to break out of the J.Assignment for finding an annotation parent that is more significant when the nearest desired parent is a not a J.ClassDeclaration (#5724)
1 parent 4157f40 commit 4c870fa

2 files changed

Lines changed: 310 additions & 50 deletions

File tree

rewrite-java-test/src/test/java/org/openrewrite/java/JavaTemplateAnnotationTest.java

Lines changed: 309 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@
1616
package org.openrewrite.java;
1717

1818
import org.intellij.lang.annotations.Language;
19+
import org.junit.jupiter.api.Nested;
1920
import org.junit.jupiter.api.Test;
2021
import org.openrewrite.DocumentExample;
2122
import org.openrewrite.ExecutionContext;
2223
import org.openrewrite.Issue;
24+
import org.openrewrite.Recipe;
2325
import org.openrewrite.java.tree.J;
2426
import org.openrewrite.test.RewriteTest;
2527

@@ -161,10 +163,10 @@ public record Person(
161163
}
162164

163165
@Issue("https://github.com/openrewrite/rewrite/issues/5712")
164-
@Test
165-
void replaceArgumentsInNestedAnnotation() {
166+
@Nested
167+
class NestedAnnotations {
166168
@Language("java")
167-
String annotations = """
169+
private final String annotations = """
168170
package foo;
169171
170172
import java.lang.annotation.*;
@@ -179,55 +181,313 @@ void replaceArgumentsInNestedAnnotation() {
179181
NestedAnnotation[] value();
180182
}
181183
""";
182-
rewriteRun(
183-
spec -> spec
184-
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
185-
.recipe(toRecipe(() -> new JavaIsoVisitor<>() {
186-
@Override
187-
public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) {
188-
if (annotation.getSimpleName().equals("NestedAnnotation") &&
189-
!annotation.getArguments().isEmpty()) {
190-
// Check if this annotation still has the 'a' attribute that needs to be replaced
191-
J.Assignment arg = (J.Assignment) annotation.getArguments().get(0);
192-
if (arg.getVariable() instanceof J.Identifier &&
193-
((J.Identifier) arg.getVariable()).getSimpleName().equals("a")) {
194-
// Only apply the template if we haven't already transformed this annotation
195-
J.Literal value = (J.Literal) arg.getAssignment();
196-
197-
// Replace 'a' with 'b' in the annotation
198-
return JavaTemplate.builder("@NestedAnnotation(b = #{any(java.lang.String)})")
199-
.javaParser(JavaParser.fromJavaVersion().dependsOn(annotations))
200-
.imports("foo.*")
201-
.build()
202-
.apply(getCursor(), annotation.getCoordinates().replace(), value);
203-
}
184+
185+
private final Recipe recipe = toRecipe(() -> new JavaIsoVisitor<>() {
186+
@Override
187+
public J.Annotation visitAnnotation(J.Annotation annotation, ExecutionContext ctx) {
188+
if (annotation.getSimpleName().equals("NestedAnnotation") &&
189+
!annotation.getArguments().isEmpty()) {
190+
// Check if this annotation still has the 'a' attribute that needs to be replaced
191+
J.Assignment arg = (J.Assignment) annotation.getArguments().get(0);
192+
if (arg.getVariable() instanceof J.Identifier &&
193+
((J.Identifier) arg.getVariable()).getSimpleName().equals("a")) {
194+
// Only apply the template if we haven't already transformed this annotation
195+
J.Literal value = (J.Literal) arg.getAssignment();
196+
197+
// Replace 'a' with 'b' in the annotation
198+
return JavaTemplate.builder("@NestedAnnotation(b = #{any(java.lang.String)})")
199+
.javaParser(JavaParser.fromJavaVersion().dependsOn(annotations))
200+
.imports("foo.*")
201+
.build()
202+
.apply(getCursor(), annotation.getCoordinates().replace(), value);
204203
}
205-
return super.visitAnnotation(annotation, ctx);
206204
}
207-
})),
208-
java(
209-
"""
210-
import foo.*;
205+
return super.visitAnnotation(annotation, ctx);
206+
}
207+
});
211208

212-
@NestedAnnotations({
213-
@NestedAnnotation(a = "1"),
214-
@NestedAnnotation(a = "2")
215-
})
216-
class Test {
217-
}
218-
""",
219-
"""
220-
import foo.*;
209+
@Test
210+
void replaceWhenFieldAnnotatedNoIdentifier() {
211+
rewriteRun(
212+
spec -> spec
213+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
214+
.recipe(recipe),
215+
//language=java
216+
java(
217+
"""
218+
import foo.*;
219+
220+
class A {
221+
@NestedAnnotations({
222+
@NestedAnnotation(a = "first"),
223+
@NestedAnnotation(a = "second")
224+
})
225+
String field;
226+
void method() {}
227+
}
228+
""",
229+
"""
230+
import foo.*;
231+
232+
class A {
233+
@NestedAnnotations({
234+
@NestedAnnotation(b = "first"),
235+
@NestedAnnotation(b = "second")
236+
})
237+
String field;
238+
void method() {}
239+
}
240+
"""
241+
)
242+
);
243+
}
221244

222-
@NestedAnnotations({
223-
@NestedAnnotation(b = "1"),
224-
@NestedAnnotation(b = "2")
225-
})
226-
class Test {
227-
}
228-
"""
229-
)
230-
);
231-
}
245+
@Test
246+
void replaceWhenFieldAnnotatedWithIdentifier() {
247+
rewriteRun(
248+
spec -> spec
249+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
250+
.recipe(recipe),
251+
//language=java
252+
java(
253+
"""
254+
import foo.*;
255+
256+
class A {
257+
@NestedAnnotations(value = {
258+
@NestedAnnotation(a = "first"),
259+
@NestedAnnotation(a = "second")
260+
})
261+
String field;
262+
void method() {}
263+
}
264+
""",
265+
"""
266+
import foo.*;
267+
268+
class A {
269+
@NestedAnnotations(value = {
270+
@NestedAnnotation(b = "first"),
271+
@NestedAnnotation(b = "second")
272+
})
273+
String field;
274+
void method() {}
275+
}
276+
"""
277+
)
278+
);
279+
}
232280

281+
@Test
282+
void replaceWhenMethodAnnotatedNoIdentifier() {
283+
rewriteRun(
284+
spec -> spec
285+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
286+
.recipe(recipe),
287+
//language=java
288+
java(
289+
"""
290+
import foo.*;
291+
292+
class A {
293+
@NestedAnnotations({
294+
@NestedAnnotation(a = "first"),
295+
@NestedAnnotation(a = "second")
296+
})
297+
void method() {}
298+
}
299+
""",
300+
"""
301+
import foo.*;
302+
303+
class A {
304+
@NestedAnnotations({
305+
@NestedAnnotation(b = "first"),
306+
@NestedAnnotation(b = "second")
307+
})
308+
void method() {}
309+
}
310+
"""
311+
)
312+
);
313+
}
314+
315+
@Test
316+
void replaceWhenMethodAnnotatedWithIdentifier() {
317+
rewriteRun(
318+
spec -> spec
319+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
320+
.recipe(recipe),
321+
//language=java
322+
java(
323+
"""
324+
import foo.*;
325+
326+
class A {
327+
@NestedAnnotations(value = {
328+
@NestedAnnotation(a = "first"),
329+
@NestedAnnotation(a = "second")
330+
})
331+
void method() {}
332+
}
333+
""",
334+
"""
335+
import foo.*;
336+
337+
class A {
338+
@NestedAnnotations(value = {
339+
@NestedAnnotation(b = "first"),
340+
@NestedAnnotation(b = "second")
341+
})
342+
void method() {}
343+
}
344+
"""
345+
)
346+
);
347+
}
348+
349+
@Test
350+
void replaceWhenOuterClassAnnotatedNoIdentifier() {
351+
rewriteRun(
352+
spec -> spec
353+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
354+
.recipe(recipe),
355+
//language=java
356+
java(
357+
"""
358+
import foo.*;
359+
360+
@NestedAnnotations({
361+
@NestedAnnotation(a = "first"),
362+
@NestedAnnotation(a = "second")
363+
})
364+
class A {
365+
void method() {}
366+
}
367+
""",
368+
"""
369+
import foo.*;
370+
371+
@NestedAnnotations({
372+
@NestedAnnotation(b = "first"),
373+
@NestedAnnotation(b = "second")
374+
})
375+
class A {
376+
void method() {}
377+
}
378+
"""
379+
)
380+
);
381+
}
382+
383+
@Test
384+
void replaceWhenOuterClassAnnotatedWithIdentifier() {
385+
rewriteRun(
386+
spec -> spec
387+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
388+
.recipe(recipe),
389+
//language=java
390+
java(
391+
"""
392+
import foo.*;
393+
394+
@NestedAnnotations(value = {
395+
@NestedAnnotation(a = "first"),
396+
@NestedAnnotation(a = "second")
397+
})
398+
class A {
399+
void method() {}
400+
}
401+
""",
402+
"""
403+
import foo.*;
404+
405+
@NestedAnnotations(value = {
406+
@NestedAnnotation(b = "first"),
407+
@NestedAnnotation(b = "second")
408+
})
409+
class A {
410+
void method() {}
411+
}
412+
"""
413+
)
414+
);
415+
}
416+
417+
@Test
418+
void replaceWhenInnerClassAnnotatedNoIdentifier() {
419+
rewriteRun(
420+
spec -> spec
421+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
422+
.recipe(recipe),
423+
//language=java
424+
java(
425+
"""
426+
import foo.*;
427+
428+
class A {
429+
@NestedAnnotations({
430+
@NestedAnnotation(a = "first"),
431+
@NestedAnnotation(a = "second")
432+
})
433+
class B {
434+
void method() {}
435+
}
436+
}
437+
""",
438+
"""
439+
import foo.*;
440+
441+
class A {
442+
@NestedAnnotations({
443+
@NestedAnnotation(b = "first"),
444+
@NestedAnnotation(b = "second")
445+
})
446+
class B {
447+
void method() {}
448+
}
449+
}
450+
"""
451+
)
452+
);
453+
}
454+
455+
@Test
456+
void replaceWhenInnerClassAnnotatedWithIdentifier() {
457+
rewriteRun(
458+
spec -> spec
459+
.parser(JavaParser.fromJavaVersion().dependsOn(annotations))
460+
.recipe(recipe),
461+
//language=java
462+
java(
463+
"""
464+
import foo.*;
465+
466+
class A {
467+
@NestedAnnotations(value = {
468+
@NestedAnnotation(a = "first"),
469+
@NestedAnnotation(a = "second")
470+
})
471+
class B {
472+
void method() {}
473+
}
474+
}
475+
""",
476+
"""
477+
import foo.*;
478+
479+
class A {
480+
@NestedAnnotations(value = {
481+
@NestedAnnotation(b = "first"),
482+
@NestedAnnotation(b = "second")
483+
})
484+
class B {
485+
void method() {}
486+
}
487+
}
488+
"""
489+
)
490+
);
491+
}
492+
}
233493
}

rewrite-java/src/main/java/org/openrewrite/java/internal/template/AnnotationTemplateGenerator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public String template(Cursor cursor, String template) {
7777
J annotationParent = j instanceof J.Annotation && cursor.getParent() != null ? cursor.getParent().firstEnclosing(J.class) : null;
7878

7979
int level = 1;
80-
while (annotationParent instanceof J.NewArray || annotationParent instanceof J.Annotation) {
80+
while (annotationParent instanceof J.NewArray || annotationParent instanceof J.Assignment || annotationParent instanceof J.Annotation) {
8181
level += 1;
8282
if (cursor.getParent(level) == null) {
8383
break;

0 commit comments

Comments
 (0)