1/*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 8005294
27 * @summary Check behavior of default methods of AnnotatedElement
28 * @author Joseph D. Darcy
29 */
30
31import java.lang.annotation.*;
32import java.lang.reflect.*;
33import java.util.*;
34
35/**
36 * For annotation type tokens including, null, DirectlyPresent.class,
37 * IndirectlyPresent.class, etc. the behavior of
38 * AnnotedElementDelegate.foo(arg) is compared for equality to
39 * baseAnnotatedElement.foo(arg) on various kinds of annotated
40 * elements.
41 */
42public class TestAnnotatedElementDefaults {
43    public static void main(String... args) throws SecurityException {
44        int failures = 0;
45
46        for (AnnotatedElement annotElement : elementsToTest()) {
47            System.out.println(annotElement);
48            AnnotatedElementDelegate delegate = new AnnotatedElementDelegate(annotElement);
49            failures += testNullHandling(delegate);
50            for (Class<? extends Annotation> annotType : annotationsToTest()) {
51                failures += AnnotatedElementDelegate.testDelegate(delegate, annotType);
52            }
53        }
54
55        if (failures > 0) {
56            System.err.printf("%d failures%n", failures);
57            throw new RuntimeException();
58        }
59    }
60
61    private static List<AnnotatedElement> elementsToTest() {
62        List<AnnotatedElement> annotatedElements = new ArrayList<>();
63        annotatedElements.add(TestClass1Super.class);
64        annotatedElements.add(TestClass1.class);
65        for (Method method : TestClass1.class.getDeclaredMethods()) {
66            annotatedElements.add(method);
67        }
68        return annotatedElements;
69    }
70
71    private static List<Class<? extends Annotation>> annotationsToTest() {
72        List<Class<? extends Annotation>> annotations = new ArrayList<>();
73        annotations.add(Missing.class);
74
75        annotations.add(MissingRepeatable.class);
76
77        annotations.add(DirectlyPresent.class);
78
79        annotations.add(IndirectlyPresent.class);
80        annotations.add(IndirectlyPresentContainer.class);
81
82        annotations.add(DirectlyAndIndirectlyPresent.class);
83        annotations.add(DirectlyAndIndirectlyPresentContainer.class);
84
85        annotations.add(AssociatedDirectOnSuperClass.class);
86        annotations.add(AssociatedDirectOnSuperClassContainer.class);
87
88        annotations.add(AssociatedDirectOnSuperClassIndirectOnSubclass.class);
89        annotations.add(AssociatedDirectOnSuperClassIndirectOnSubclassContainer.class);
90
91        annotations.add(AssociatedIndirectOnSuperClassDirectOnSubclass.class);
92        annotations.add(AssociatedIndirectOnSuperClassDirectOnSubclassContainer.class);
93        return annotations;
94    }
95
96    private static int testNullHandling(AnnotatedElementDelegate delegate) {
97        int failures = 0;
98        try {
99            Object result = delegate.getDeclaredAnnotationsByType(null);
100            failures++;
101        } catch (NullPointerException npe) {
102            ; // Expected
103        }
104
105        try {
106            Object result = delegate.getAnnotationsByType(null);
107            failures++;
108        } catch (NullPointerException npe) {
109            ; // Expected
110        }
111
112        try {
113            Object result = delegate.getDeclaredAnnotation(null);
114            failures++;
115        } catch (NullPointerException npe) {
116            ; // Expected
117        }
118
119        return failures;
120    }
121
122}
123
124// -----------------------------------------------------
125
126@AssociatedDirectOnSuperClass(123)
127@AssociatedIndirectOnSuperClass(234) @AssociatedIndirectOnSuperClass(345)
128@AssociatedDirectOnSuperClassIndirectOnSubclass(987)
129@AssociatedIndirectOnSuperClassDirectOnSubclass(1111) @AssociatedIndirectOnSuperClassDirectOnSubclass(2222)
130class TestClass1Super {}
131
132@DirectlyPresent(1)
133@IndirectlyPresent(10) @IndirectlyPresent(11)
134@AssociatedDirectOnSuperClassIndirectOnSubclass(876) @AssociatedDirectOnSuperClassIndirectOnSubclass(765)
135@AssociatedIndirectOnSuperClassDirectOnSubclass(3333)
136class TestClass1 extends TestClass1Super {
137
138    @DirectlyPresent(2)
139    @IndirectlyPresentContainer({@IndirectlyPresent(12)})
140    @DirectlyAndIndirectlyPresentContainer({@DirectlyAndIndirectlyPresent(84), @DirectlyAndIndirectlyPresent(96)})
141    public void foo() {return ;}
142
143    @IndirectlyPresentContainer({})
144    @DirectlyAndIndirectlyPresentContainer({@DirectlyAndIndirectlyPresent(11), @DirectlyAndIndirectlyPresent(22)})
145    @DirectlyAndIndirectlyPresent(33)
146    public void bar()  {return ;}
147}
148
149// -----------------------------------------------------
150
151@Retention(RetentionPolicy.RUNTIME)
152@interface Missing {
153    int value();
154}
155
156// -----------------------------------------------------
157
158@Retention(RetentionPolicy.RUNTIME)
159@Repeatable(MissingRepeatableContainer.class)
160@interface MissingRepeatable {
161    int value();
162}
163
164@Retention(RetentionPolicy.RUNTIME)
165@interface MissingRepeatableContainer {
166    MissingRepeatable[] value();
167}
168
169// -----------------------------------------------------
170
171@Retention(RetentionPolicy.RUNTIME)
172@interface DirectlyPresent {
173    int value();
174}
175
176// -----------------------------------------------------
177
178@Retention(RetentionPolicy.RUNTIME)
179@Repeatable(IndirectlyPresentContainer.class)
180@interface IndirectlyPresent {
181    int value();
182}
183
184@Retention(RetentionPolicy.RUNTIME)
185@interface IndirectlyPresentContainer {
186    IndirectlyPresent[] value();
187}
188
189// -----------------------------------------------------
190
191@Retention(RetentionPolicy.RUNTIME)
192@Repeatable(DirectlyAndIndirectlyPresentContainer.class)
193@interface DirectlyAndIndirectlyPresent {
194    int value();
195
196}
197
198@Retention(RetentionPolicy.RUNTIME)
199@interface DirectlyAndIndirectlyPresentContainer {
200    DirectlyAndIndirectlyPresent[] value();
201}
202
203// -----------------------------------------------------
204
205@Retention(RetentionPolicy.RUNTIME)
206@Repeatable(AssociatedDirectOnSuperClassContainer.class)
207@interface AssociatedDirectOnSuperClass {
208    int value();
209}
210
211@Retention(RetentionPolicy.RUNTIME)
212@interface AssociatedDirectOnSuperClassContainer {
213    AssociatedDirectOnSuperClass[] value();
214}
215
216// -----------------------------------------------------
217
218@Retention(RetentionPolicy.RUNTIME)
219@Repeatable(AssociatedIndirectOnSuperClassContainer.class)
220@interface AssociatedIndirectOnSuperClass {
221    int value();
222}
223
224@Retention(RetentionPolicy.RUNTIME)
225@interface AssociatedIndirectOnSuperClassContainer {
226    AssociatedIndirectOnSuperClass[] value();
227}
228
229// -----------------------------------------------------
230
231@Retention(RetentionPolicy.RUNTIME)
232@Repeatable(AssociatedDirectOnSuperClassIndirectOnSubclassContainer.class)
233@interface  AssociatedDirectOnSuperClassIndirectOnSubclass {
234    int value();
235}
236
237@Retention(RetentionPolicy.RUNTIME)
238@interface AssociatedDirectOnSuperClassIndirectOnSubclassContainer {
239    AssociatedDirectOnSuperClassIndirectOnSubclass[] value();
240}
241
242// -----------------------------------------------------
243
244@Retention(RetentionPolicy.RUNTIME)
245@Repeatable(AssociatedIndirectOnSuperClassDirectOnSubclassContainer.class)
246@interface  AssociatedIndirectOnSuperClassDirectOnSubclass {
247    int value();
248}
249
250@Retention(RetentionPolicy.RUNTIME)
251@interface AssociatedIndirectOnSuperClassDirectOnSubclassContainer {
252    AssociatedIndirectOnSuperClassDirectOnSubclass[] value();
253}
254
255// -----------------------------------------------------
256
257/**
258 * Helper class to ease calling the default methods of {@code
259 * AnnotatedElement} and comparing the results to other
260 * implementation.
261 */
262class AnnotatedElementDelegate implements AnnotatedElement {
263    private AnnotatedElement base;
264
265    public AnnotatedElementDelegate(AnnotatedElement base) {
266        Objects.requireNonNull(base);
267        this.base = base;
268    }
269
270    // Delegate to base implemenetation of AnnotatedElement methods
271    // without defaults.
272    @Override
273    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
274        return base.getAnnotation(annotationClass);
275    }
276
277    @Override
278    public Annotation[] getAnnotations() {
279        return base.getAnnotations();
280    }
281
282    @Override
283    public Annotation[] getDeclaredAnnotations() {
284        return base.getDeclaredAnnotations();
285    }
286
287    public AnnotatedElement getBase() {
288        return base;
289    }
290
291    static int testDelegate(AnnotatedElementDelegate delegate,
292                            Class<? extends Annotation> annotationClass) {
293        int failures = 0;
294        AnnotatedElement base = delegate.getBase();
295
296        // System.out.println("\tTesting " + delegate + "\ton\t" + annotationClass);
297
298        // <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
299        failures += annotationArrayCheck(delegate.getDeclaredAnnotationsByType(annotationClass),
300                                         base.getDeclaredAnnotationsByType(annotationClass),
301                                         annotationClass,
302                                         "Equality failure on getDeclaredAnnotationsByType(%s) on %s)%n");
303
304        // <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
305        failures += annotationArrayCheck(delegate.getAnnotationsByType(annotationClass),
306                                         base.getAnnotationsByType(annotationClass),
307                                         annotationClass,
308                                         "Equality failure on getAnnotationsByType(%s) on %s)%n");
309
310        // <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
311        if (!Objects.equals(delegate.getDeclaredAnnotation(annotationClass),
312                            base.getDeclaredAnnotation(annotationClass))) {
313            failures++;
314            System.err.printf("Equality failure on getDeclaredAnnotation(%s) on %s)%n",
315                              annotationClass, delegate);
316        }
317        return failures;
318    }
319    private static <T extends Annotation> int annotationArrayCheck(T[] delegate,
320                                                           T[] base,
321                                                           Class<? extends Annotation> annotationClass,
322                                                           String message) {
323        int failures = 0;
324
325        if (!Objects.deepEquals(delegate,base)) {
326            failures = 1;
327
328            System.err.printf(message,
329                              annotationClass,
330                              delegate);
331
332            System.err.println("Base result:\t" + Arrays.toString(base));
333            System.err.println("Delegate result:\t " + Arrays.toString(delegate));
334            System.err.println();
335        }
336
337        return failures;
338    }
339}
340