1 /*
   2  * Copyright (c) 2013, 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  * @test 
  25  * @bug 8013497
  26  * @summary test for API: Class.getAnnotationsByType()
  27  * @author Charlie Wang
  28  * @library ../../../
  29  * @build AnnotationTest TestCaseGenerator DeclarationGenerator Helper
  30  * @run main ClassGetAnnotationsByTypeTest
  31  */
  32 import java.lang.annotation.Annotation;
  33 import java.util.LinkedHashMap;
  34 import java.util.Map;
  35 
  36 /*
  37  * This file is intended to test API: Class.getAnnotationsByType(). 
  38  * It can be run directly by java command or by jtreg.
  39  * By setting Helper.DEBUG = true/false, one can display/hide the test code
  40  * on the command line output, which is constructed for the annotation test.
  41  * Here's more details about test code generation:
  42  * Construct the test code in a structure specified in TestCase.
  43  * In each of the following cases, different combinations of annotation 
  44  * specified in AnnotationTest.annotationCombinations are tested. The output
  45  * annotations must be the same as input both in value and order.
  46  * 1. Single interface
  47  * 2. Class extends class
  48  * 3. Class implements interface
  49  * The program test all the cases in TestCase by looping over each one of it.
  50  * Test cases are constructed with small code snippet from Helper.SrcType
  51  * using changable annotations, type and name. After these values are specified,
  52  * the method GenTestCode() generates corresponding java code, encapsulate them
  53  * with a class. Then this class is compiled by Helper.compileCode() into
  54  * classes which is later loaded into memory by Helper.loadClass().
  55  * The test fails if any of the cases fail.
  56  */
  57 public class ClassGetAnnotationsByTypeTest extends AnnotationTest {
  58 
  59     enum TestCase implements TestCaseGenerator {
  60         TESTBASECLS() {
  61             /**
  62              * generate test base, which is the class name used to compile the code: 
  63              * import java.io.*; 
  64              * import java.util.*; 
  65              * import java.lang.*; 
  66              * import java.lang.reflect.*;
  67              * import java.lang.annotation.*; 
  68              * class testBaseClsName { }
  69              */
  70             public String genTestCase(String str) {
  71                 if (0 == testInput.size()) {
  72                     testInput.put(null, null);
  73                     return AnnotationTest.genBaseClass(testBaseClsName);
  74                 } else {
  75                     return "";
  76                 }
  77             }
  78         },
  79         SINGLECLS() {
  80             /**
  81              * generate single class: 
  82              * [#ANNO] class TypeAnnoCls1 { } 
  83              * then append annotations on [#ANNO]
  84              *
  85              * input should be like [@anno]
  86              */
  87             public String genTestCase(String str) {
  88                 if (null == str) {
  89                     throw new RuntimeException("bad test case.");
  90                 }
  91                 String testCode = "";
  92                 int clsIdx = testInput.size();
  93                 TestCodeGenerator tcg = new TestCodeGenerator();
  94                 tcg.put(Helper.Declaration.CLASS, 
  95                         new String[]{str + " " + typeAnnoClsName + clsIdx});
  96                 tcg.put(Helper.Declaration.CLASS_BODY_START, "");
  97                 tcg.put(Helper.Declaration.CLASS_BODY_END, "");
  98                 testCode += tcg.genTestCode();
  99                 testInput.put(typeAnnoClsName + clsIdx, str);
 100                 return testCode;
 101             }
 102         },
 103         CLSEXTCLS() {
 104             /**
 105              * generate cls extends cls: 
 106              * [#ANNO] class TypeAnnoCls2 extends [#ANNO] Object {} 
 107              * then append annotations on [#ANNO]
 108              *
 109              * input should be like [@anno]
 110              */
 111             public String genTestCase(String str) {
 112                 if (null == str) {
 113                     throw new RuntimeException("bad test case.");
 114                 }
 115                 String testCode = "";
 116                 int clsIdx = testInput.size();
 117                 TestCodeGenerator tcg = new TestCodeGenerator();
 118                 tcg.put(Helper.Declaration.CLASS, new String[]{
 119                     str + " " + typeAnnoClsName + clsIdx});
 120                 tcg.put(Helper.Declaration.EXTENDS, new String[]{
 121                     str + " Object"});
 122                 tcg.put(Helper.Declaration.CLASS_BODY_START, "");
 123                 tcg.put(Helper.Declaration.CLASS_BODY_END, "");
 124                 testCode += tcg.genTestCode();
 125                 testInput.put(typeAnnoClsName + clsIdx, str);
 126                 return testCode;
 127             }
 128         },
 129         CLSEXTCLSIMPINT() {
 130             /**
 131              * generate cls implements interface: 
 132              * [#ANNO] class TypeAnnoCls3 extends 
 133              * [#ANNO] Object implements [#ANNO] Serializable {} 
 134              * then append annotations on [#ANNO]
 135              *
 136              * input should be like [@anno]
 137              */
 138             public String genTestCase(String str) {
 139                 if (null == str) {
 140                     throw new RuntimeException("bad test case.");
 141                 }
 142                 String testCode = "";
 143                 int clsIdx = testInput.size();
 144                 TestCodeGenerator tcg = new TestCodeGenerator();
 145                 tcg.put(Helper.Declaration.CLASS, new String[]{
 146                     str + " " + typeAnnoClsName + clsIdx});
 147                 tcg.put(Helper.Declaration.EXTENDS, new String[]{
 148                     str + " Object"});
 149                 tcg.put(Helper.Declaration.IMPLEMENTS, new String[]{
 150                     str + " Serializable"});
 151                 tcg.put(Helper.Declaration.CLASS_BODY_START, "");
 152                 tcg.put(Helper.Declaration.CLASS_BODY_END, "");
 153                 testCode += tcg.genTestCode();
 154                 testInput.put(typeAnnoClsName + clsIdx, str);
 155                 return testCode;
 156             }
 157         };
 158         
 159         // a place to hold class name -- annotation correspondence
 160         public static Map<String, String> testInput = new LinkedHashMap<>();
 161 
 162         // generate test class of a specific case
 163         public String genTestCase(String str) {
 164             return "";
 165         }
 166     }
 167 
 168     // compare input with result
 169     protected boolean checkResult() throws Exception {
 170         boolean ret = true;
 171         compileCode(TestCase.class);
 172         for (String clsName : TestCase.testInput.keySet()) {
 173             if (null == clsName) {
 174                 continue;
 175             }
 176             Class cls = loadClass(clsName);
 177             Class argCls = Helper.loadClass(TestCaseGenerator.argClsName);
 178             Annotation[] as = cls.getAnnotationsByType(argCls);
 179             String result = Helper.getAnno(as);
 180             if (null == result || 0 == result.length()) {
 181                 if (-1 != TestCase.testInput.get(clsName)
 182                         .indexOf(TestCaseGenerator.argClsName)) {
 183                     // should be empty output
 184                     ret = false;
 185                     Helper.debugPrint(clsName.toString() 
 186                             + " failed without empty output.");
 187                 }
 188             } else {
 189                 if (-1 == TestCase.testInput.get(clsName)
 190                         .indexOf(TestCaseGenerator.argClsName)) {
 191                     // should not be empty output
 192                     ret = false;
 193                     Helper.debugPrint(clsName.toString()
 194                             + " failed with faulty annotations.");
 195                 }
 196             }
 197         }
 198         return ret;
 199     }
 200 
 201     public static void main(String[] args) throws Exception {
 202         new ClassGetAnnotationsByTypeTest().test();
 203     }
 204 }