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