test/langtools/tools/javac/processing/model/element/AnnotationToStringTest.java
changeset 55387 761b86d5563d
equal deleted inserted replaced
55386:2f4e214781a1 55387:761b86d5563d
       
     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 }