TestConstructorParameterTypeAnnotations.java revision 17161:47032f7eebb1
1265694Sian/*
2265694Sian * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3265694Sian * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4265694Sian *
5265694Sian * This code is free software; you can redistribute it and/or modify it
6265694Sian * under the terms of the GNU General Public License version 2 only, as
7265694Sian * published by the Free Software Foundation.
8265694Sian *
9265694Sian * This code is distributed in the hope that it will be useful, but WITHOUT
10265694Sian * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11265694Sian * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12265694Sian * version 2 for more details (a copy is included in the LICENSE file that
13265694Sian * accompanied this code).
14265694Sian *
15265694Sian * You should have received a copy of the GNU General Public License version
16265694Sian * 2 along with this work; if not, write to the Free Software Foundation,
17265694Sian * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18265694Sian *
19265694Sian * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20265694Sian * or visit www.oracle.com if you need additional information or have any
21265694Sian * questions.
22265694Sian */
23265694Sian
24265694Sian/*
25265694Sian * @test
26265694Sian * @bug     8074977
27265694Sian * @summary Test consistency of annotations on constructor parameters
28265694Sian * @compile             TestConstructorParameterTypeAnnotations.java
29265694Sian * @run main            TestConstructorParameterTypeAnnotations
30265694Sian * @compile -parameters TestConstructorParameterTypeAnnotations.java
31265694Sian * @run main            TestConstructorParameterTypeAnnotations
32267130Szbb */
33267130Szbb
34265694Sianimport java.lang.annotation.*;
35265694Sianimport java.lang.reflect.*;
36265694Sianimport java.util.*;
37265694Sian
38265694Sian/*
39265694Sian * Some constructor parameters are <em>mandated</em>; that is, they
40265694Sian * are not explicitly present in the source code, but required to be
41265694Sian * present by the Java Language Specification. In other cases, some
42265694Sian * constructor parameters are not present in the source, but are
43265694Sian * synthesized by the compiler as an implementation artifact. There is
44265694Sian * not a reliable mechanism to consistently determine whether or not
45265694Sian * a parameter is implicit or not.
46265694Sian *
47265694Sian * (Using the "-parameters" option to javac does emit the information
48265694Sian * needed to make a reliably determination, but the information is not
49267130Szbb * present by default.)
50265694Sian *
51265694Sian * The lack of such a mechanism causes complications reading parameter
52265694Sian * annotations in some cases since annotations for parameters are
53265694Sian * written out for the parameters in the source code, but when reading
54265694Sian * annotations at runtime all the parameters, including implicit ones,
55267130Szbb * are present.
56267130Szbb */
57267130Szbbpublic class TestConstructorParameterTypeAnnotations {
58265694Sian    public static void main(String... args) {
59265694Sian        int errors = 0;
60267129Szbb        Class<?>[] classes = {NestedClass0.class,
61267129Szbb                              NestedClass1.class,
62                              NestedClass2.class,
63                              NestedClass3.class,
64                              NestedClass4.class,
65                              StaticNestedClass0.class,
66                              StaticNestedClass1.class,
67                              StaticNestedClass2.class };
68
69        for (Class<?> clazz : classes) {
70            for (Constructor<?> ctor : clazz.getConstructors()) {
71                System.out.println(ctor);
72                errors += checkGetParameterAnnotations(clazz, ctor);
73                errors += checkGetAnnotatedParametersGetAnnotation(clazz, ctor);
74            }
75        }
76
77        if (errors > 0)
78            throw new RuntimeException(errors + " errors.");
79        return;
80    }
81
82    private static int checkGetParameterAnnotations(Class<?> clazz,
83                                                    Constructor<?> ctor) {
84        String annotationString =
85            Arrays.deepToString(ctor.getParameterAnnotations());
86        String expectedString =
87            clazz.getAnnotation(ExpectedGetParameterAnnotations.class).value();
88
89        if (!Objects.equals(annotationString, expectedString)) {
90            System.err.println("Annotation mismatch on " + ctor +
91                               "\n\tExpected:" + expectedString +
92                               "\n\tActual:  " + annotationString);
93            return 1;
94        }
95        return 0;
96    }
97
98    private static int checkGetAnnotatedParametersGetAnnotation(Class<?> clazz,
99                                                       Constructor<?> ctor) {
100        int errors = 0;
101        int i = 0;
102        ExpectedParameterTypeAnnotations epa =
103            clazz.getAnnotation(ExpectedParameterTypeAnnotations.class);
104
105        for (AnnotatedType param : ctor.getAnnotatedParameterTypes() ) {
106            String annotationString =
107                Objects.toString(param.getAnnotation(MarkerTypeAnnotation.class));
108            String expectedString = epa.value()[i];
109
110            if (!Objects.equals(annotationString, expectedString)) {
111                System.err.println("Annotation mismatch on " + ctor +
112                                   " on param " + param +
113                                   "\n\tExpected:" + expectedString +
114                                   "\n\tActual:  " + annotationString);
115                errors++;
116            }
117            i++;
118        }
119        return errors;
120    }
121
122    @ExpectedGetParameterAnnotations("[[]]")
123    @ExpectedParameterTypeAnnotations({"null"})
124    public class NestedClass0 {
125        public NestedClass0() {}
126    }
127
128    @ExpectedGetParameterAnnotations("[[], []]")
129    @ExpectedParameterTypeAnnotations({
130        "null",
131        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=1)"})
132    public class NestedClass1 {
133        public NestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
134    }
135
136    @ExpectedGetParameterAnnotations("[[], [], []]")
137    @ExpectedParameterTypeAnnotations({
138        "null",
139        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=2)",
140        "null"})
141    public class NestedClass2 {
142        public NestedClass2(@MarkerTypeAnnotation(2) int parameter1,
143                            int parameter2) {}
144    }
145
146    @ExpectedGetParameterAnnotations("[[], [], []]")
147    @ExpectedParameterTypeAnnotations({
148        "null",
149        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=3)",
150        "null"})
151    public class NestedClass3 {
152        public <P> NestedClass3(@MarkerTypeAnnotation(3) P parameter1,
153                                int parameter2) {}
154    }
155
156    @ExpectedGetParameterAnnotations("[[], [], []]")
157    @ExpectedParameterTypeAnnotations({
158        "null",
159        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=4)",
160        "null"})
161    public class NestedClass4 {
162        public <P, Q> NestedClass4(@MarkerTypeAnnotation(4) P parameter1,
163                                   Q parameter2) {}
164    }
165
166    @ExpectedGetParameterAnnotations("[]")
167    @ExpectedParameterTypeAnnotations({"null"})
168    public static class StaticNestedClass0 {
169        public StaticNestedClass0() {}
170    }
171
172    @ExpectedGetParameterAnnotations("[[]]")
173    @ExpectedParameterTypeAnnotations({
174        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=1)"})
175    public static class StaticNestedClass1 {
176        public StaticNestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
177    }
178
179    @ExpectedGetParameterAnnotations("[[], []]")
180    @ExpectedParameterTypeAnnotations({
181        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=2)",
182        "null"})
183    public static class StaticNestedClass2 {
184        public StaticNestedClass2(@MarkerTypeAnnotation(2) int parameter1,
185                                  int parameter2) {}
186    }
187
188    @ExpectedGetParameterAnnotations("[[], []]")
189    @ExpectedParameterTypeAnnotations({
190        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=3)",
191        "null"})
192    public static class StaticNestedClass3 {
193         public <P> StaticNestedClass3(@MarkerTypeAnnotation(3) P parameter1,
194                                      int parameter2) {}
195    }
196
197    @ExpectedGetParameterAnnotations("[[], []]")
198    @ExpectedParameterTypeAnnotations({
199        "@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=4)",
200        "null"})
201    public static class StaticNestedClass4 {
202        public <P, Q> StaticNestedClass4(@MarkerTypeAnnotation(4) P parameter1,
203                                         Q parameter2) {}
204    }
205
206    @Target(ElementType.TYPE_USE)
207    @Retention(RetentionPolicy.RUNTIME)
208    @interface MarkerTypeAnnotation {
209        int value();
210    }
211
212    /**
213     * String form of expected value of calling
214     * getParameterAnnotations on a constructor.
215     */
216    @Target(ElementType.TYPE)
217    @Retention(RetentionPolicy.RUNTIME)
218    @interface ExpectedGetParameterAnnotations {
219        String value();
220    }
221
222    /**
223     * String form of expected value of calling
224     * getAnnotation(MarkerTypeAnnotation.class) on each element of the
225     * result of getParameters() on a constructor.
226     */
227    @Target(ElementType.TYPE)
228    @Retention(RetentionPolicy.RUNTIME)
229    @interface ExpectedParameterTypeAnnotations {
230        String[] value();
231    }
232}
233