1 /* 2 * Copyright (c) 2016, 2019, 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 8164819 27 * @summary Test of toString on normal annotations 28 * @library /tools/javac/lib 29 * @build JavacTestingAbstractProcessor AnnotationToStringTest 30 * @compile -processor AnnotationToStringTest -proc:only AnnotationToStringTest.java 31 */ 32 33 // See also the sibling core reflection test 34 // test/jdk/java/lang/annotation/AnnotationToStringTest.java 35 36 import java.lang.annotation.*; 37 import java.lang.reflect.*; 38 import java.util.*; 39 import javax.annotation.processing.*; 40 import javax.lang.model.AnnotatedConstruct; 41 import javax.lang.model.element.*; 42 import javax.lang.model.util.*; 43 44 /** 45 * The expected string values are stored in @ExpectedString 46 * annotations. The essence of the test is comparing the toString() 47 * result of annotations to the corresponding ExpectedString.value(). 48 * 49 * Two flavors of comparison are made: 50 * 51 * 1) Against the AnnotationMirror value from getAnnotationMirrors() 52 * 53 * 2) Against the *Annotation* from getAnnotation(Class<A>) 54 * 55 * These have separate but related implementations. 56 */ 57 public class AnnotationToStringTest extends JavacTestingAbstractProcessor { 58 public boolean process(Set<? extends TypeElement> annotations, 59 RoundEnvironment roundEnv) { 60 if (!roundEnv.processingOver()) { 61 62 int failures = 0; 63 64 TypeElement primHostElt = 65 Objects.requireNonNull(elements.getTypeElement("AnnotationToStringTest.PrimHost")); 66 67 List<? extends AnnotationMirror> annotMirrors = primHostElt.getAnnotationMirrors(); 68 69 String expectedString = primHostElt.getAnnotation(MostlyPrimitive.class).toString(); 70 71 failures += check(expectedString, 72 primHostElt.getAnnotation(ExpectedString.class).value()); 73 74 failures += check(expectedString, 75 retrieveAnnotationMirrorAsString(primHostElt, 76 "MostlyPrimitive")); 77 failures += classyTest(); 78 failures += arrayAnnotationTest(); 79 80 if (failures > 0) 81 throw new RuntimeException(failures + " failures"); 82 } 83 return true; 84 } 85 86 /** 87 * Examine annotation mirrors, find the one that matches 88 * annotationName, and return its toString value. 89 */ 90 private String retrieveAnnotationMirrorAsString(AnnotatedConstruct annotated, 91 String annotationName) { 92 return retrieveAnnotationMirror(annotated, annotationName).toString(); 93 } 94 95 private String retrieveAnnotationMirrorValue(AnnotatedConstruct annotated, 96 String annotationName) { 97 AnnotationMirror annotationMirror = 98 retrieveAnnotationMirror(annotated, annotationName); 99 for (var entry : annotationMirror.getElementValues().entrySet()) { 100 if (entry.getKey().getSimpleName().contentEquals("value")) { 101 return entry.getValue().toString(); 102 } 103 } 104 throw new RuntimeException("Annotation value() method not found: " + 105 annotationMirror.toString()); 106 } 107 108 private AnnotationMirror retrieveAnnotationMirror(AnnotatedConstruct annotated, 109 String annotationName) { 110 for (AnnotationMirror annotationMirror : annotated.getAnnotationMirrors()) { 111 System.out.println(annotationMirror.getAnnotationType()); 112 if (annotationMirror 113 .getAnnotationType() 114 .toString() 115 .equals(annotationName) ) { 116 return annotationMirror; 117 } 118 } 119 throw new RuntimeException("Annotation " + annotationName + " not found."); 120 } 121 122 private static int check(String expected, String actual) { 123 if (!expected.equals(actual)) { 124 System.err.printf("ERROR: Expected ''%s'';%ngot ''%s''.\n", 125 expected, actual); 126 return 1; 127 } else 128 return 0; 129 } 130 131 @ExpectedString( 132 "@MostlyPrimitive(c0='a', "+ 133 "c1='\\'', " + 134 "b0=(byte)0x01, " + 135 "i0=1, " + 136 "i1=2, " + 137 "f0=1.0f, " + 138 "f1=0.0f/0.0f, " + 139 "d0=0.0, " + 140 "d1=1.0/0.0, " + 141 "l0=5L, " + 142 "l1=9223372036854775807L, " + 143 "l2=-9223372036854775808L, " + 144 "l3=-2147483648L, " + 145 "s0=\"Hello world.\", " + 146 "s1=\"a\\\"b\", " + 147 "class0=Obj[].class, " + 148 "classArray={Obj[].class})") 149 @MostlyPrimitive( 150 c0='a', 151 c1='\'', 152 b0=1, 153 i0=1, 154 i1=2, 155 f0=1.0f, 156 f1=Float.NaN, 157 d0=0.0, 158 d1=2.0/0.0, 159 l0=5, 160 l1=Long.MAX_VALUE, 161 l2=Long.MIN_VALUE, 162 l3=Integer.MIN_VALUE, 163 s0="Hello world.", 164 s1="a\"b", 165 class0=Obj[].class, 166 classArray={Obj[].class} 167 ) 168 static class PrimHost{} 169 170 private int classyTest() { 171 int failures = 0; 172 173 TypeElement annotationHostElt = 174 Objects.requireNonNull(elements.getTypeElement("AnnotationToStringTest.AnnotationHost")); 175 176 for (VariableElement f : ElementFilter.fieldsIn(annotationHostElt.getEnclosedElements())) { 177 String expected = f.getAnnotation(ExpectedString.class).value(); 178 Annotation a = f.getAnnotation(Classy.class); 179 180 System.out.println(a); 181 failures += check(expected, a.toString()); 182 183 failures += check(expected, 184 retrieveAnnotationMirrorAsString(f, "Classy") ); 185 } 186 return failures; 187 } 188 189 static class AnnotationHost { 190 @ExpectedString( 191 "@Classy(Obj.class)") 192 @Classy(Obj.class) 193 public int f0; 194 195 @ExpectedString( 196 "@Classy(Obj[].class)") 197 @Classy(Obj[].class) 198 public int f1; 199 200 @ExpectedString( 201 "@Classy(Obj[][].class)") 202 @Classy(Obj[][].class) 203 public int f2; 204 205 @ExpectedString( 206 "@Classy(Obj[][][].class)") 207 @Classy(Obj[][][].class) 208 public int f3; 209 210 @ExpectedString( 211 "@Classy(int.class)") 212 @Classy(int.class) 213 public int f4; 214 215 @ExpectedString( 216 "@Classy(int[][][].class)") 217 @Classy(int[][][].class) 218 public int f5; 219 } 220 221 /** 222 * Each field should have two annotations, the first being 223 * @ExpectedString and the second the annotation under test. 224 */ 225 private int arrayAnnotationTest() { 226 int failures = 0; 227 228 TypeElement arrayAnnotationHostElt = 229 Objects.requireNonNull(elements 230 .getTypeElement("AnnotationToStringTest.ArrayAnnotationHost")); 231 232 for (VariableElement f : 233 ElementFilter.fieldsIn(arrayAnnotationHostElt.getEnclosedElements())) { 234 var annotations = f.getAnnotationMirrors(); 235 // String expected = retrieveAnnotationMirrorValue(f, "ExpectedString"); 236 String expected = f.getAnnotation(ExpectedString.class).value(); 237 238 // Problem with 239 // Need a de-quote method... 240 // expected = expected.substring(1, expected.length() - 1); 241 242 failures += 243 check(expected, 244 annotations.get(1).toString()); 245 246 // Get the array-valued annotation as an annotation 247 failures += 248 check(expected, 249 retrieveAnnotationMirrorAsString(f, 250 annotations.get(1) 251 .getAnnotationType().toString())); 252 } 253 return failures; 254 } 255 256 static class ArrayAnnotationHost { 257 @ExpectedString( 258 "@BooleanArray({true, false, true})") 259 @BooleanArray({true, false, true}) 260 public boolean[] f0; 261 262 @ExpectedString( 263 "@FloatArray({3.0f, 4.0f, 0.0f/0.0f, -1.0f/0.0f, 1.0f/0.0f})") 264 @FloatArray({3.0f, 4.0f, Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY}) 265 public float[] f1; 266 267 @ExpectedString( 268 "@DoubleArray({1.0, 2.0, 0.0/0.0, 1.0/0.0, -1.0/0.0})") 269 @DoubleArray({1.0, 2.0, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,}) 270 public double[] f2; 271 272 273 @ExpectedString( 274 "@ByteArray({(byte)0x0a, (byte)0x0b, (byte)0x0c})") 275 @ByteArray({10, 11, 12}) 276 public byte[] f3; 277 278 @ExpectedString( 279 "@ShortArray({0, 4, 5})") 280 @ShortArray({0, 4, 5}) 281 public short[] f4; 282 283 @ExpectedString( 284 "@CharArray({'a', 'b', 'c', '\\''})") 285 @CharArray({'a', 'b', 'c', '\''}) 286 public char[] f5; 287 288 @ExpectedString( 289 "@IntArray({1})") 290 @IntArray({1}) 291 public int[] f6; 292 293 @ExpectedString( 294 "@LongArray({-9223372036854775808L, -2147483649L, -2147483648L," + 295 " -2147483647L, 2147483648L, 9223372036854775807L})") 296 @LongArray({Long.MIN_VALUE, Integer.MIN_VALUE-1L, Integer.MIN_VALUE, 297 -Integer.MAX_VALUE, Integer.MAX_VALUE+1L, Long.MAX_VALUE}) 298 public long[] f7; 299 300 @ExpectedString( 301 "@StringArray({\"A\", \"B\", \"C\", \"\\\"Quote\\\"\"})") 302 @StringArray({"A", "B", "C", "\"Quote\""}) 303 public String[] f8; 304 305 @ExpectedString( 306 "@ClassArray({int.class, Obj[].class})") 307 @ClassArray({int.class, Obj[].class}) 308 public Class<?>[] f9; 309 310 @ExpectedString( 311 "@EnumArray({SOURCE})") 312 @EnumArray({RetentionPolicy.SOURCE}) 313 public RetentionPolicy[] f10; 314 } 315 } 316 317 // ------------ Supporting types ------------ 318 319 class Obj {} 320 321 @Retention(RetentionPolicy.RUNTIME) 322 @interface ExpectedString { 323 String value(); 324 } 325 326 @Retention(RetentionPolicy.RUNTIME) 327 @interface Classy { 328 Class<?> value(); 329 } 330 331 @Retention(RetentionPolicy.RUNTIME) 332 @interface BooleanArray { 333 boolean[] value(); 334 } 335 336 @Retention(RetentionPolicy.RUNTIME) 337 @interface FloatArray { 338 float[] value(); 339 } 340 341 @Retention(RetentionPolicy.RUNTIME) 342 @interface DoubleArray { 343 double[] value(); 344 } 345 346 @Retention(RetentionPolicy.RUNTIME) 347 @interface ByteArray { 348 byte[] value(); 349 } 350 351 @Retention(RetentionPolicy.RUNTIME) 352 @interface ShortArray { 353 short[] value(); 354 } 355 356 @Retention(RetentionPolicy.RUNTIME) 357 @interface CharArray { 358 char[] value(); 359 } 360 361 @Retention(RetentionPolicy.RUNTIME) 362 @interface IntArray { 363 int[] value(); 364 } 365 366 @Retention(RetentionPolicy.RUNTIME) 367 @interface LongArray { 368 long[] value(); 369 } 370 371 @Retention(RetentionPolicy.RUNTIME) 372 @interface ClassArray { 373 Class<?>[] value() default {int.class, Obj[].class}; 374 } 375 376 @Retention(RetentionPolicy.RUNTIME) 377 @interface StringArray { 378 String[] value(); 379 } 380 381 @Retention(RetentionPolicy.RUNTIME) 382 @interface EnumArray { 383 RetentionPolicy[] value(); 384 } 385 386 @Retention(RetentionPolicy.RUNTIME) 387 @interface MostlyPrimitive { 388 char c0(); 389 char c1(); 390 byte b0(); 391 int i0(); 392 int i1(); 393 float f0(); 394 float f1(); 395 double d0(); 396 double d1(); 397 long l0(); 398 long l1(); 399 long l2(); 400 long l3(); 401 String s0(); 402 String s1(); 403 Class<?> class0(); 404 Class<?>[] classArray(); 405 }