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 TestConstructorParameterAnnotations.java 29 * @run main TestConstructorParameterAnnotations 30 * @compile -parameters TestConstructorParameterAnnotations.java 31 * @run main TestConstructorParameterAnnotations 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 TestConstructorParameterAnnotations { 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 StaticNestedClass3.class, 69 StaticNestedClass4.class, 70 EnumClass.class}; 71 72 for (Class<?> clazz : classes) { 73 for (Constructor<?> ctor : clazz.getConstructors()) { 74 System.out.println(ctor); 75 errors += checkGetParameterAnnotations(clazz, ctor); 76 errors += checkGetParametersGetAnnotation(clazz, ctor); 77 } 78 } 79 80 if (errors > 0) 81 throw new RuntimeException(errors + " errors."); 82 return; 83 } 84 85 private static int checkGetParameterAnnotations(Class<?> clazz, 86 Constructor<?> ctor) { 87 String annotationString = 88 Arrays.deepToString(ctor.getParameterAnnotations()); 89 String expectedString = 90 clazz.getAnnotation(ExpectedGetParameterAnnotations.class).value(); 91 92 if (!Objects.equals(annotationString, expectedString)) { 93 System.err.println("Annotation mismatch on " + ctor + 94 "\n\tExpected:" + expectedString + 95 "\n\tActual: " + annotationString); 96 return 1; 97 } 98 return 0; 99 } 100 101 private static int checkGetParametersGetAnnotation(Class<?> clazz, 102 Constructor<?> ctor) { 103 int errors = 0; 104 int i = 0; 105 ExpectedParameterAnnotations epa = 106 clazz.getAnnotation(ExpectedParameterAnnotations.class); 107 108 for (Parameter param : ctor.getParameters() ) { 109 String annotationString = 110 Objects.toString(param.getAnnotation(MarkerAnnotation.class)); 111 String expectedString = epa.value()[i]; 112 113 if (!Objects.equals(annotationString, expectedString)) { 114 System.err.println("Annotation mismatch on " + ctor + 115 " on param " + param + 116 "\n\tExpected:" + expectedString + 117 "\n\tActual: " + annotationString); 118 errors++; 119 } 120 i++; 121 } 122 return errors; 123 } 124 125 @ExpectedGetParameterAnnotations("[[]]") 126 @ExpectedParameterAnnotations({"null"}) 127 public class NestedClass0 { 128 public NestedClass0() {} 129 } 130 131 @ExpectedGetParameterAnnotations( 132 "[[], " + 133 "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)]]") 134 @ExpectedParameterAnnotations({ 135 "null", 136 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)"}) 137 public class NestedClass1 { 138 public NestedClass1(@MarkerAnnotation(1) int parameter) {} 139 } 140 141 @ExpectedGetParameterAnnotations( 142 "[[], " + 143 "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)], " + 144 "[]]") 145 @ExpectedParameterAnnotations({ 146 "null", 147 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)", 148 "null"}) 149 public class NestedClass2 { 150 public NestedClass2(@MarkerAnnotation(2) int parameter1, 151 int parameter2) {} 152 } 153 154 @ExpectedGetParameterAnnotations( 155 "[[], " + 156 "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)], " + 157 "[]]") 158 @ExpectedParameterAnnotations({ 159 "null", 160 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)", 161 "null"}) 162 public class NestedClass3 { 163 public <P> NestedClass3(@MarkerAnnotation(3) P parameter1, 164 int parameter2) {} 165 } 166 167 @ExpectedGetParameterAnnotations( 168 "[[], " + 169 "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)], " + 170 "[]]") 171 @ExpectedParameterAnnotations({ 172 "null", 173 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)", 174 "null"}) 175 public class NestedClass4 { 176 public <P, Q> NestedClass4(@MarkerAnnotation(4) P parameter1, 177 Q parameter2) {} 178 } 179 180 @ExpectedGetParameterAnnotations("[]") 181 @ExpectedParameterAnnotations({"null"}) 182 public static class StaticNestedClass0 { 183 public StaticNestedClass0() {} 184 } 185 186 @ExpectedGetParameterAnnotations( 187 "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)]]") 188 @ExpectedParameterAnnotations({ 189 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)"}) 190 public static class StaticNestedClass1 { 191 public StaticNestedClass1(@MarkerAnnotation(1) int parameter) {} 192 } 193 194 @ExpectedGetParameterAnnotations( 195 "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)], " + 196 "[]]") 197 @ExpectedParameterAnnotations({ 198 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=2)", 199 "null"}) 200 public static class StaticNestedClass2 { 201 public StaticNestedClass2(@MarkerAnnotation(2) int parameter1, 202 int parameter2) {} 203 } 204 205 @ExpectedGetParameterAnnotations( 206 "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)], " + 207 "[]]") 208 @ExpectedParameterAnnotations({ 209 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=3)", 210 "null"}) 211 public static class StaticNestedClass3 { 212 public <P> StaticNestedClass3(@MarkerAnnotation(3) P parameter1, 213 int parameter2) {} 214 } 215 216 @ExpectedGetParameterAnnotations( 217 "[[@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)], " + 218 "[]]") 219 @ExpectedParameterAnnotations({ 220 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=4)", 221 "null"}) 222 public static class StaticNestedClass4 { 223 public <P, Q> StaticNestedClass4(@MarkerAnnotation(4) P parameter1, 224 Q parameter2) {} 225 } 226 227 @ExpectedGetParameterAnnotations( 228 "[[], [], " + 229 "[@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)]]") 230 @ExpectedParameterAnnotations({ 231 "null", 232 "null", 233 "@TestConstructorParameterAnnotations$MarkerAnnotation(value=1)"}) 234 public enum EnumClass { 235 CONSTANT1; 236 EnumClass(@MarkerAnnotation(1) int parameter1) {} 237 } 238 239 @Target(ElementType.PARAMETER) 240 @Retention(RetentionPolicy.RUNTIME) 241 @interface MarkerAnnotation { 242 int value(); 243 } 244 245 /** 246 * String form of expected value of calling 247 * getParameterAnnotations on a constructor. 248 */ 249 @Target(ElementType.TYPE) 250 @Retention(RetentionPolicy.RUNTIME) 251 @interface ExpectedGetParameterAnnotations { 252 String value(); 253 } 254 255 /** 256 * String form of expected value of calling 257 * getAnnotation(MarkerAnnotation.class) on each element of the 258 * result of getParameters() on a constructor. 259 */ 260 @Target(ElementType.TYPE) 261 @Retention(RetentionPolicy.RUNTIME) 262 @interface ExpectedParameterAnnotations { 263 String[] value(); 264 } 265 }