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.getDeclaredAnnotationsByType()
  27  * @author Charlie Wang
  28  * @library ../../../
  29  * @build AnnotationTest TestCaseGenerator DeclarationGenerator Helper
  30  * @run main ClassGetDeclaredAnnotationsByTypeTest
  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.getDeclaredAnnotationsByType(). 
  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 ClassGetDeclaredAnnotationsByTypeTest extends AnnotationTest {
  58 
  59     enum TestCase implements TestCaseGenerator {
  60 
  61         TESTBASECLS() {
  62             /**
  63              * generate test base, which is the class name used to compile the code: 
  64              * import java.io.*; 
  65              * import java.util.*; 
  66              * import java.lang.*; 
  67              * import java.lang.reflect.*;
  68              * import java.lang.annotation.*; 
  69              * class testBaseClsName { }
  70              */
  71             public String genTestCase(String str) {
  72                 if (0 == testInput.size()) {
  73                     testInput.put(null, null);
  74                     return AnnotationTest.genBaseClass(testBaseClsName);
  75                 } else {
  76                     return "";
  77                 }
  78             }
  79         },
  80         SINGLECLS() {
  81             /**
  82              * generate single class: 
  83              * [#ANNO] class TypeAnnoCls1 { } 
  84              * then append annotations on [#ANNO]
  85              *
  86              * input should be like [@anno]
  87              */
  88             public String genTestCase(String str) {
  89                 if (null == str) {
  90                     throw new RuntimeException("bad test case.");
  91                 }
  92                 String testCode = "";
  93                 int clsIdx = testInput.size();
  94                 TestCodeGenerator tcg = new TestCodeGenerator();
  95                 tcg.put(Helper.Declaration.CLASS, 
  96                         new String[]{str + " " + typeAnnoClsName + clsIdx});
  97                 tcg.put(Helper.Declaration.CLASS_BODY_START, "");
  98                 tcg.put(Helper.Declaration.CLASS_BODY_END, "");
  99                 testCode += tcg.genTestCode();
 100                 testInput.put(typeAnnoClsName + clsIdx, str);
 101                 return testCode;
 102             }
 103         },
 104         CLSEXTCLS() {
 105             /**
 106              * generate cls extends cls: 
 107              * [#ANNO] class TypeAnnoCls2 extends [#ANNO] Object {} 
 108              * then append annotations on [#ANNO]
 109              *
 110              * input should be like [class name, @anno]
 111              */
 112             public String genTestCase(String str) {
 113                 if (null == str) {
 114                     throw new RuntimeException("bad test case.");
 115                 }
 116                 String testCode = "";
 117                 int clsIdx = testInput.size();
 118                 TestCodeGenerator tcg = new TestCodeGenerator();
 119                 tcg.put(Helper.Declaration.CLASS, new String[]{
 120                     str + " " + typeAnnoClsName + clsIdx});
 121                 tcg.put(Helper.Declaration.EXTENDS, new String[]{
 122                     str + " Object"});
 123                 tcg.put(Helper.Declaration.CLASS_BODY_START, "");
 124                 tcg.put(Helper.Declaration.CLASS_BODY_END, "");
 125                 testCode += tcg.genTestCode();
 126                 testInput.put(typeAnnoClsName + clsIdx, str);
 127                 return testCode;
 128             }
 129         },
 130         CLSEXTCLSIMPINT() {
 131             /**
 132              * generate cls implements interface: 
 133              * [#ANNO] class TypeAnnoCls3 extends 
 134              * [#ANNO] Object implements [#ANNO] Serializable {} 
 135              * then append annotations on [#ANNO]
 136              *
 137              * input should be like [class name,  @anno]
 138              */
 139             public String genTestCase(String str) {
 140                 if (null == str) {
 141                     throw new RuntimeException("bad test case.");
 142                 }
 143                 String testCode = "";
 144                 int clsIdx = testInput.size();
 145                 TestCodeGenerator tcg = new TestCodeGenerator();
 146                 tcg.put(Helper.Declaration.CLASS, new String[]{
 147                     str + " " + typeAnnoClsName + clsIdx});
 148                 tcg.put(Helper.Declaration.EXTENDS, new String[]{
 149                     str + " Object"});
 150                 tcg.put(Helper.Declaration.IMPLEMENTS, new String[]{
 151                     str + " Serializable"});
 152                 tcg.put(Helper.Declaration.CLASS_BODY_START, "");
 153                 tcg.put(Helper.Declaration.CLASS_BODY_END, "");
 154                 testCode += tcg.genTestCode();
 155                 testInput.put(typeAnnoClsName + clsIdx, str);
 156                 return testCode;
 157             }
 158         };
 159         
 160         // a place to hold class name -- annotation correspondence
 161         public static Map<String, String> testInput = new LinkedHashMap<>();
 162 
 163         // generate test class of a specific case
 164         public String genTestCase(String str) {
 165             return "";
 166         }
 167     }
 168 
 169     // compare input with result
 170     protected boolean checkResult() throws Exception {
 171         boolean ret = true;
 172         compileCode(TestCase.class);
 173         for (String clsName : TestCase.testInput.keySet()) {
 174             if (null == clsName) {
 175                 continue;
 176             }
 177             Class cls = loadClass(clsName);
 178             Class argCls = Helper.loadClass(TestCaseGenerator.argClsName);
 179             Annotation[] as = cls.getAnnotationsByType(argCls);
 180             String result = Helper.getAnno(as);
 181             if (null == result || 0 == result.length()) {
 182                 if (-1 != TestCase.testInput.get(clsName).indexOf(
 183                         TestCaseGenerator.argClsName)) {
 184                     // should be empty output
 185                     ret = false;
 186                     Helper.debugPrint(clsName.toString() 
 187                             + " failed without empty output.");
 188                 }
 189             } else {
 190                 if (-1 == TestCase.testInput.get(clsName).indexOf(
 191                         TestCaseGenerator.argClsName)) {
 192                     // should not be empty output
 193                     ret = false;
 194                     Helper.debugPrint(clsName.toString() 
 195                             + " failed with faulty annotations.");
 196                 }
 197             }
 198         }
 199         return ret;
 200     }
 201 
 202     public static void main(String[] args) throws Exception {
 203         new ClassGetDeclaredAnnotationsByTypeTest().test();
 204     }
 205 }