| /* | |
| * Copyright (c) 2017, 2022, 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 <em>mandated</em>; 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(1)]]") | |
| @ExpectedParameterAnnotations({ | |
| "null", | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(1)"}) | |
| public class NestedClass1 { | |
| public NestedClass1(@MarkerAnnotation(1) int parameter) {} | |
| } | |
| @ExpectedGetParameterAnnotations( | |
| "[[], " + | |
| "[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " + | |
| "[]]") | |
| @ExpectedParameterAnnotations({ | |
| "null", | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(2)", | |
| "null"}) | |
| public class NestedClass2 { | |
| public NestedClass2(@MarkerAnnotation(2) int parameter1, | |
| int parameter2) {} | |
| } | |
| @ExpectedGetParameterAnnotations( | |
| "[[], " + | |
| "[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " + | |
| "[]]") | |
| @ExpectedParameterAnnotations({ | |
| "null", | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(3)", | |
| "null"}) | |
| public class NestedClass3 { | |
| public <P> NestedClass3(@MarkerAnnotation(3) P parameter1, | |
| int parameter2) {} | |
| } | |
| @ExpectedGetParameterAnnotations( | |
| "[[], " + | |
| "[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " + | |
| "[]]") | |
| @ExpectedParameterAnnotations({ | |
| "null", | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(4)", | |
| "null"}) | |
| public class NestedClass4 { | |
| public <P, Q> NestedClass4(@MarkerAnnotation(4) P parameter1, | |
| Q parameter2) {} | |
| } | |
| @ExpectedGetParameterAnnotations("[]") | |
| @ExpectedParameterAnnotations({"null"}) | |
| public static class StaticNestedClass0 { | |
| public StaticNestedClass0() {} | |
| } | |
| @ExpectedGetParameterAnnotations( | |
| "[[@TestConstructorParameterAnnotations.MarkerAnnotation(1)]]") | |
| @ExpectedParameterAnnotations({ | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(1)"}) | |
| public static class StaticNestedClass1 { | |
| public StaticNestedClass1(@MarkerAnnotation(1) int parameter) {} | |
| } | |
| @ExpectedGetParameterAnnotations( | |
| "[[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " + | |
| "[]]") | |
| @ExpectedParameterAnnotations({ | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(2)", | |
| "null"}) | |
| public static class StaticNestedClass2 { | |
| public StaticNestedClass2(@MarkerAnnotation(2) int parameter1, | |
| int parameter2) {} | |
| } | |
| @ExpectedGetParameterAnnotations( | |
| "[[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " + | |
| "[]]") | |
| @ExpectedParameterAnnotations({ | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(3)", | |
| "null"}) | |
| public static class StaticNestedClass3 { | |
| public <P> StaticNestedClass3(@MarkerAnnotation(3) P parameter1, | |
| int parameter2) {} | |
| } | |
| @ExpectedGetParameterAnnotations( | |
| "[[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " + | |
| "[]]") | |
| @ExpectedParameterAnnotations({ | |
| "@TestConstructorParameterAnnotations.MarkerAnnotation(4)", | |
| "null"}) | |
| public static class StaticNestedClass4 { | |
| public <P, Q> 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(); | |
| } | |
| } |