1 /* 2 * Copyright (c) 2017, 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 8074977 27 * @summary Test consistency of annotations on constructor parameters 28 * @compile TestConstructorParameterTypeAnnotations.java 29 * @run main TestConstructorParameterTypeAnnotations 30 * @compile -parameters TestConstructorParameterTypeAnnotations.java 31 * @run main TestConstructorParameterTypeAnnotations 32 */ 33 34 import java.lang.annotation.*; 35 import java.lang.reflect.*; 36 import java.util.*; 37 38 /* 39 * Some constructor parameters are <em>mandated</em>; that is, they 40 * are not explicitly present in the source code, but required to be 41 * present by the Java Language Specification. In other cases, some 42 * constructor parameters are not present in the source, but are 43 * synthesized by the compiler as an implementation artifact. There is 44 * not a reliable mechanism to consistently determine whether or not 45 * a parameter is implicit or not. 46 * 47 * (Using the "-parameters" option to javac does emit the information 48 * needed to make a reliably determination, but the information is not 49 * present by default.) 50 * 51 * The lack of such a mechanism causes complications reading parameter 52 * annotations in some cases since annotations for parameters are 53 * written out for the parameters in the source code, but when reading 54 * annotations at runtime all the parameters, including implicit ones, 55 * are present. 56 */ 57 public class TestConstructorParameterTypeAnnotations { 58 public static void main(String... args) { 59 int errors = 0; 60 Class<?>[] classes = {NestedClass0.class, 61 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 }