Skip to content

Commit 66dddc6

Browse files
authored
Merge pull request #396 from guillermocalvo/expand-test-coverage-for-annotation-changes
Expand test coverage for compatibility changes related to annotations
2 parents 599da82 + 46f77ae commit 66dddc6

File tree

5 files changed

+199
-18
lines changed

5 files changed

+199
-18
lines changed

japicmp/src/test/java/japicmp/compat/CompatibilityChangesTest.java

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2615,18 +2615,22 @@ public void testAnnotationOnClassModified() throws Exception {
26152615
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
26162616
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
26172617
CtMethodBuilder.create().name("foo").returnType(CtClass.intType).publicAccess().addToClass(anAnnotation);
2618-
return Collections.singletonList(anAnnotation);
2618+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").withAnnotation("japicmp.MyAnnotation", new CtElement("foo", 1000)).addToClassPool(classPool);
2619+
return Arrays.asList(aClass, anAnnotation);
26192620
}
26202621

26212622
@Override
26222623
public List<CtClass> createNewClasses(ClassPool classPool) {
26232624
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
2624-
return Arrays.asList(anAnnotation);
2625+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").withAnnotation("japicmp.MyAnnotation", new CtElement("foo", 999)).addToClassPool(classPool);
2626+
return Arrays.asList(aClass, anAnnotation);
26252627
}
26262628
});
26272629
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.MyAnnotation");
26282630
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "foo");
26292631
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(new JApiCompatibilityChange(JApiCompatibilityChangeType.METHOD_REMOVED)));
2632+
JApiClass jApiClassWithAnnotation = getJApiClass(jApiClasses, "japicmp.Test");
2633+
assertThat(jApiClassWithAnnotation.getCompatibilityChanges(), hasItem(new JApiCompatibilityChange(JApiCompatibilityChangeType.ANNOTATION_MODIFIED)));
26302634
}
26312635

26322636
@Test
@@ -2676,4 +2680,104 @@ public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
26762680
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method");
26772681
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(new JApiCompatibilityChange(JApiCompatibilityChangeType.ANNOTATION_REMOVED)));
26782682
}
2683+
2684+
@Test
2685+
public void testAnnotationOnMethodModified() throws Exception {
2686+
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
2687+
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
2688+
@Override
2689+
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
2690+
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
2691+
CtMethodBuilder.create().name("foo").returnType(CtClass.intType).publicAccess().addToClass(anAnnotation);
2692+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2693+
CtMethodBuilder.create().publicAccess().name("method").withAnnotation("japicmp.MyAnnotation", new CtElement("foo", 1000)).addToClass(aClass);
2694+
return Arrays.asList(aClass, anAnnotation);
2695+
}
2696+
2697+
@Override
2698+
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
2699+
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
2700+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2701+
CtMethodBuilder.create().publicAccess().name("method").withAnnotation("japicmp.MyAnnotation", new CtElement("foo", 999)).addToClass(aClass);
2702+
return Arrays.asList(aClass, anAnnotation);
2703+
}
2704+
});
2705+
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
2706+
JApiMethod jApiMethod = getJApiMethod(jApiClass.getMethods(), "method");
2707+
assertThat(jApiMethod.getCompatibilityChanges(), hasItem(new JApiCompatibilityChange(JApiCompatibilityChangeType.ANNOTATION_MODIFIED)));
2708+
}
2709+
2710+
@Test
2711+
public void testAnnotationAddedToField() throws Exception {
2712+
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
2713+
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
2714+
@Override
2715+
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
2716+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2717+
CtFieldBuilder.create().name("field").addToClass(aClass);
2718+
return Collections.singletonList(aClass);
2719+
}
2720+
2721+
@Override
2722+
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
2723+
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
2724+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2725+
CtFieldBuilder.create().withAnnotation("japicmp.MyAnnotation").name("field").addToClass(aClass);
2726+
return Arrays.asList(aClass, anAnnotation);
2727+
}
2728+
});
2729+
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
2730+
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
2731+
assertThat(jApiField.getCompatibilityChanges(), hasItem(new JApiCompatibilityChange(JApiCompatibilityChangeType.ANNOTATION_ADDED)));
2732+
}
2733+
2734+
@Test
2735+
public void testAnnotationRemovedFromField() throws Exception {
2736+
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
2737+
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
2738+
@Override
2739+
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
2740+
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
2741+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2742+
CtFieldBuilder.create().name("field").withAnnotation("japicmp.MyAnnotation").addToClass(aClass);
2743+
return Arrays.asList(aClass, anAnnotation);
2744+
}
2745+
2746+
@Override
2747+
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
2748+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2749+
CtFieldBuilder.create().name("field").addToClass(aClass);
2750+
return Collections.singletonList(aClass);
2751+
}
2752+
});
2753+
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
2754+
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
2755+
assertThat(jApiField.getCompatibilityChanges(), hasItem(new JApiCompatibilityChange(JApiCompatibilityChangeType.ANNOTATION_REMOVED)));
2756+
}
2757+
2758+
@Test
2759+
public void testAnnotationOnFieldModified() throws Exception {
2760+
JarArchiveComparatorOptions options = new JarArchiveComparatorOptions();
2761+
List<JApiClass> jApiClasses = ClassesHelper.compareClasses(options, new ClassesHelper.ClassesGenerator() {
2762+
@Override
2763+
public List<CtClass> createOldClasses(ClassPool classPool) throws Exception {
2764+
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
2765+
CtMethodBuilder.create().name("foo").returnType(CtClass.intType).publicAccess().addToClass(anAnnotation);
2766+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2767+
CtFieldBuilder.create().name("field").withAnnotation("japicmp.MyAnnotation", new CtElement("foo", 1000)).addToClass(aClass);
2768+
return Arrays.asList(aClass, anAnnotation);
2769+
}
2770+
2771+
@Override
2772+
public List<CtClass> createNewClasses(ClassPool classPool) throws Exception {
2773+
CtClass anAnnotation = CtAnnotationBuilder.create().name("japicmp.MyAnnotation").addToClassPool(classPool);
2774+
CtClass aClass = CtClassBuilder.create().name("japicmp.Test").addToClassPool(classPool);
2775+
CtFieldBuilder.create().name("field").withAnnotation("japicmp.MyAnnotation", new CtElement("foo", 999)).addToClass(aClass);
2776+
return Arrays.asList(aClass, anAnnotation);
2777+
}
2778+
});
2779+
JApiClass jApiClass = getJApiClass(jApiClasses, "japicmp.Test");
2780+
JApiField jApiField = getJApiField(jApiClass.getFields(), "field");
2781+
assertThat(jApiField.getCompatibilityChanges(), hasItem(new JApiCompatibilityChange(JApiCompatibilityChangeType.ANNOTATION_MODIFIED)));
2782+
}
26792783
}

japicmp/src/test/java/japicmp/util/CtClassBuilder.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@
1010
import javassist.bytecode.annotation.Annotation;
1111

1212
import java.util.ArrayList;
13+
import java.util.HashMap;
1314
import java.util.List;
15+
import java.util.Map;
1416

1517
public class CtClassBuilder {
1618
public static final String DEFAULT_CLASS_NAME = "japicmp.Test";
1719
private String name = DEFAULT_CLASS_NAME;
1820
private int modifier = Modifier.PUBLIC;
19-
private final List<String> annotations = new ArrayList<>();
21+
private final Map<String, CtElement[]> annotations = new HashMap<>();
2022
private Optional<CtClass> superclass = Optional.absent();
2123
private final List<CtClass> interfaces = new ArrayList<>();
2224

@@ -30,8 +32,8 @@ public CtClassBuilder syntheticModifier() {
3032
return this;
3133
}
3234

33-
public CtClassBuilder withAnnotation(String annotation) {
34-
this.annotations.add(annotation);
35+
public CtClassBuilder withAnnotation(String annotation, CtElement... elements) {
36+
this.annotations.put(annotation, elements);
3537
return this;
3638
}
3739

@@ -69,11 +71,14 @@ public CtClass addToClassPool(ClassPool classPool) {
6971
ctClass = classPool.makeClass(this.name);
7072
}
7173
ctClass.setModifiers(this.modifier);
72-
for (String annotation : annotations) {
74+
for (String annotation : annotations.keySet()) {
7375
ClassFile classFile = ctClass.getClassFile();
7476
ConstPool constPool = classFile.getConstPool();
7577
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
7678
Annotation annot = new Annotation(annotation, constPool);
79+
for (CtElement element : annotations.get(annotation)) {
80+
annot.addMemberValue(element.name, element.value.apply(constPool));
81+
}
7782
attr.setAnnotation(annot);
7883
ctClass.getClassFile2().addAttribute(attr);
7984
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package japicmp.util;
2+
3+
import java.util.function.Function;
4+
import javassist.bytecode.ConstPool;
5+
import javassist.bytecode.annotation.BooleanMemberValue;
6+
import javassist.bytecode.annotation.ByteMemberValue;
7+
import javassist.bytecode.annotation.CharMemberValue;
8+
import javassist.bytecode.annotation.ClassMemberValue;
9+
import javassist.bytecode.annotation.DoubleMemberValue;
10+
import javassist.bytecode.annotation.FloatMemberValue;
11+
import javassist.bytecode.annotation.IntegerMemberValue;
12+
import javassist.bytecode.annotation.LongMemberValue;
13+
import javassist.bytecode.annotation.MemberValue;
14+
import javassist.bytecode.annotation.ShortMemberValue;
15+
import javassist.bytecode.annotation.StringMemberValue;
16+
17+
public class CtElement {
18+
19+
public final String name;
20+
public final Function<ConstPool, MemberValue> value;
21+
22+
private CtElement(String name, Function<ConstPool, MemberValue> value) {
23+
this.name = name;
24+
this.value = value;
25+
}
26+
27+
public CtElement(String name, boolean value) {
28+
this(name, cp -> new BooleanMemberValue(value, cp));
29+
}
30+
31+
public CtElement(String name, byte value) {
32+
this(name, cp -> new ByteMemberValue(value, cp));
33+
}
34+
35+
public CtElement(String name, char value) {
36+
this(name, cp -> new CharMemberValue(value, cp));
37+
}
38+
39+
public CtElement(String name, short value) {
40+
this(name, cp -> new ShortMemberValue(value, cp));
41+
}
42+
43+
public CtElement(String name, int value) {
44+
this(name, cp -> new IntegerMemberValue(cp, value));
45+
}
46+
47+
public CtElement(String name, long value) {
48+
this(name, cp -> new LongMemberValue(value, cp));
49+
}
50+
51+
public CtElement(String name, float value) {
52+
this(name, cp -> new FloatMemberValue(value, cp));
53+
}
54+
55+
public CtElement(String name, double value) {
56+
this(name, cp -> new DoubleMemberValue(value, cp));
57+
}
58+
59+
public CtElement(String name, Class<?> value) {
60+
this(name, cp -> new ClassMemberValue(value.getName(), cp));
61+
}
62+
63+
public CtElement(String name, String value) {
64+
this(name, cp -> new StringMemberValue(value, cp));
65+
}
66+
}

japicmp/src/test/java/japicmp/util/CtFieldBuilder.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
import javassist.bytecode.ConstPool;
1010
import javassist.bytecode.annotation.Annotation;
1111

12-
import java.util.ArrayList;
13-
import java.util.List;
12+
import java.util.HashMap;
13+
import java.util.Map;
1414

1515
public class CtFieldBuilder {
1616
public static final String DEFAULT_FIELD_NAME = "field";
1717
private CtClass type = CtClass.intType;
1818
private String name = DEFAULT_FIELD_NAME;
1919
private int modifier = Modifier.PUBLIC;
20-
private final List<String> annotations = new ArrayList<>();
20+
private final Map<String, CtElement[]> annotations = new HashMap<>();
2121
private Object constantValue = null;
2222

2323
public CtFieldBuilder type(CtClass ctClass) {
@@ -53,11 +53,14 @@ public CtField addToClass(CtClass ctClass) throws CannotCompileException {
5353
} else {
5454
ctClass.addField(ctField);
5555
}
56-
for (String annotation : annotations) {
56+
for (String annotation : annotations.keySet()) {
5757
ClassFile classFile = ctClass.getClassFile();
5858
ConstPool constPool = classFile.getConstPool();
5959
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
6060
Annotation annot = new Annotation(annotation, constPool);
61+
for (CtElement element : annotations.get(annotation)) {
62+
annot.addMemberValue(element.name, element.value.apply(constPool));
63+
}
6164
attr.setAnnotation(annot);
6265
ctField.getFieldInfo().addAttribute(attr);
6366
}
@@ -68,8 +71,8 @@ public static CtFieldBuilder create() {
6871
return new CtFieldBuilder();
6972
}
7073

71-
public CtFieldBuilder withAnnotation(String annotation) {
72-
this.annotations.add(annotation);
74+
public CtFieldBuilder withAnnotation(String annotation, CtElement... elements) {
75+
this.annotations.put(annotation, elements);
7376
return this;
7477
}
7578

japicmp/src/test/java/japicmp/util/CtMethodBuilder.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
import javassist.bytecode.SignatureAttribute;
1010
import javassist.bytecode.annotation.Annotation;
1111

12-
import java.util.ArrayList;
13-
import java.util.List;
12+
import java.util.HashMap;
13+
import java.util.Map;
1414

1515
public class CtMethodBuilder extends CtBehaviorBuilder {
1616
private static final String DEFAULT_METHOD_NAME = "method";
1717
private String body = "return null;";
1818
private String name = DEFAULT_METHOD_NAME;
1919
private CtClass returnType;
20-
private final List<String> annotations = new ArrayList<>();
20+
private final Map<String, CtElement[]> annotations = new HashMap<>();
2121

2222
public CtMethodBuilder name(String name) {
2323
this.name = name;
@@ -80,8 +80,8 @@ public CtMethodBuilder finalMethod() {
8080
return (CtMethodBuilder) super.finalMethod();
8181
}
8282

83-
public CtMethodBuilder withAnnotation(String annotation) {
84-
this.annotations.add(annotation);
83+
public CtMethodBuilder withAnnotation(String annotation, CtElement... elements) {
84+
this.annotations.put(annotation, elements);
8585
return this;
8686
}
8787

@@ -97,10 +97,13 @@ public CtMethod addToClass(CtClass declaringClass) throws CannotCompileException
9797
CtMethod ctMethod = CtNewMethod.make(this.modifier, this.returnType, this.name, this.parameters, this.exceptions, this.body, declaringClass);
9898
ctMethod.setModifiers(this.modifier);
9999
declaringClass.addMethod(ctMethod);
100-
for (String annotation : annotations) {
100+
for (String annotation : annotations.keySet()) {
101101
ConstPool constPool = declaringClass.getClassFile().getConstPool();
102102
AnnotationsAttribute attr = new AnnotationsAttribute(constPool, AnnotationsAttribute.visibleTag);
103103
Annotation annot = new Annotation(annotation, constPool);
104+
for (CtElement element : annotations.get(annotation)) {
105+
annot.addMemberValue(element.name, element.value.apply(constPool));
106+
}
104107
attr.setAnnotation(annot);
105108
ctMethod.getMethodInfo().addAttribute(attr);
106109
}

0 commit comments

Comments
 (0)