--- /dev/null 2017-02-08 09:46:36.598049496 -0800 +++ new/test/java/lang/annotation/TestConstructorParameterAnnotations.java 2017-05-19 14:03:57.800500394 -0700 @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8074977 + * @summary Test consistency of annotations on constructor parameters + * @compile TestConstructorParameterAnnotations.java + * @run main TestConstructorParameterAnnotations + * @compile -parameters TestConstructorParameterAnnotations.java + * @run main TestConstructorParameterAnnotations + */ + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +/* + * Some constructor parameters are mandated; that is, they + * are not explicitly present in the source code, but required to be + * present by the Java Language Specification. In other cases, some + * constructor parameters are not present in the source, but are + * synthesized by the compiler as an implementation artifact. There is + * not a reliable mechanism to consistently determine whether or not + * a parameter is implicit or not. + * + * (Using the "-parameters" option to javac does emit the information + * needed to make a reliably determination, but the information is not + * present by default.) + * + * The lack of such a mechanism causes complications reading parameter + * annotations in some cases since annotations for parameters are + * written out for the parameters in the source code, but when reading + * annotations at runtime all the parameters, including implicit ones, + * are present. + */ +public class TestConstructorParameterAnnotations { + public static void main(String... args) { + int errors = 0; + Class[] classes = {NestedClass0.class, + NestedClass1.class, + NestedClass2.class, + NestedClass3.class, + NestedClass4.class, + StaticNestedClass0.class, + StaticNestedClass1.class, + StaticNestedClass2.class, + StaticNestedClass3.class, + StaticNestedClass4.class}; + + for (Class clazz : classes) { + for (Constructor ctor : clazz.getConstructors()) { + System.out.println(ctor); + errors += checkGetParameterAnnotations(clazz, ctor); + errors += checkGetParametersGetAnnotation(clazz, ctor); + } + } + + if (errors > 0) + throw new RuntimeException(errors + " errors."); + return; + } + + private static int checkGetParameterAnnotations(Class clazz, + Constructor ctor) { + String annotationString = + Arrays.deepToString(ctor.getParameterAnnotations()); + String expectedString = + clazz.getAnnotation(ExpectedGetParameterAnnotations.class).value(); + + if (!Objects.equals(annotationString, expectedString)) { + System.err.println("Annotation mismatch on " + ctor + + "\n\tExpected:" + expectedString + + "\n\tActual: " + annotationString); + return 1; + } + return 0; + } + + private static int checkGetParametersGetAnnotation(Class clazz, + Constructor ctor) { + int errors = 0; + int i = 0; + ExpectedParameterAnnotations epa = + clazz.getAnnotation(ExpectedParameterAnnotations.class); + + for (Parameter param : ctor.getParameters() ) { + String annotationString = + Objects.toString(param.getAnnotation(MarkerAnnotation.class)); + String expectedString = epa.value()[i]; + + if (!Objects.equals(annotationString, expectedString)) { + System.err.println("Annotation mismatch on " + ctor + + " on param " + param + + "\n\tExpected:" + expectedString + + "\n\tActual: " + annotationString); + errors++; + } + i++; + } + return errors; + } + + @ExpectedGetParameterAnnotations("[[]]") + @ExpectedParameterAnnotations({"null"}) + public class NestedClass0 { + public NestedClass0() {} + } + + @ExpectedGetParameterAnnotations( + "[[], " + + "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)]]") + @ExpectedParameterAnnotations({ + "null", + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)"}) + public class NestedClass1 { + public NestedClass1(@MarkerAnnotation(1) int parameter) {} + } + + @ExpectedGetParameterAnnotations( + "[[], " + + "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)], " + + "[]]") + @ExpectedParameterAnnotations({ + "null", + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)", + "null"}) + public class NestedClass2 { + public NestedClass2(@MarkerAnnotation(2) int parameter1, + int parameter2) {} + } + + @ExpectedGetParameterAnnotations( + "[[], " + + "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)], " + + "[]]") + @ExpectedParameterAnnotations({ + "null", + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)", + "null"}) + public class NestedClass3 { + public

NestedClass3(@MarkerAnnotation(3) P parameter1, + int parameter2) {} + } + + @ExpectedGetParameterAnnotations( + "[[], " + + "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)], " + + "[]]") + @ExpectedParameterAnnotations({ + "null", + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)", + "null"}) + public class NestedClass4 { + public NestedClass4(@MarkerAnnotation(4) P parameter1, + Q parameter2) {} + } + + @ExpectedGetParameterAnnotations("[]") + @ExpectedParameterAnnotations({"null"}) + public static class StaticNestedClass0 { + public StaticNestedClass0() {} + } + + @ExpectedGetParameterAnnotations( + "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)]]") + @ExpectedParameterAnnotations({ + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)"}) + public static class StaticNestedClass1 { + public StaticNestedClass1(@MarkerAnnotation(1) int parameter) {} + } + + @ExpectedGetParameterAnnotations( + "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)], " + + "[]]") + @ExpectedParameterAnnotations({ + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)", + "null"}) + public static class StaticNestedClass2 { + public StaticNestedClass2(@MarkerAnnotation(2) int parameter1, + int parameter2) {} + } + + @ExpectedGetParameterAnnotations( + "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)], " + + "[]]") + @ExpectedParameterAnnotations({ + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)", + "null"}) + public static class StaticNestedClass3 { + public

StaticNestedClass3(@MarkerAnnotation(3) P parameter1, + int parameter2) {} + } + + @ExpectedGetParameterAnnotations( + "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)], " + + "[]]") + @ExpectedParameterAnnotations({ + "@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)", + "null"}) + public static class StaticNestedClass4 { + public StaticNestedClass4(@MarkerAnnotation(4) P parameter1, + Q parameter2) {} + } + + @Target(ElementType.PARAMETER) + @Retention(RetentionPolicy.RUNTIME) + @interface MarkerAnnotation { + int value(); + } + + /** + * String form of expected value of calling + * getParameterAnnotations on a constructor. + */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @interface ExpectedGetParameterAnnotations { + String value(); + } + + /** + * String form of expected value of calling + * getAnnotation(MarkerAnnotation.class) on each element of the + * result of getParameters() on a constructor. + */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.RUNTIME) + @interface ExpectedParameterAnnotations { + String[] value(); + } +}