1 /*
   2  * Copyright (c) 2014, 2015, 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 8042947
  27  * @summary Checking AnnotationDefault attribute.
  28  * @library /tools/lib /tools/javac/lib ../lib
  29  * @modules jdk.compiler/com.sun.tools.classfile
  30  *          jdk.compiler/com.sun.tools.javac.api
  31  *          jdk.compiler/com.sun.tools.javac.file
  32  *          jdk.compiler/com.sun.tools.javac.main
  33  * @build AnnotationDefaultTest TestBase TestResult InMemoryFileManager ToolBox AnnotationDefaultVerifier
  34  * @run main AnnotationDefaultTest
  35  */
  36 
  37 import com.sun.tools.classfile.*;
  38 
  39 import java.io.File;
  40 import java.io.IOException;
  41 import java.lang.annotation.RetentionPolicy;
  42 import java.nio.file.Files;
  43 import java.util.HashMap;
  44 import java.util.Map;
  45 import java.util.Objects;
  46 import java.util.function.Function;
  47 import java.util.stream.Collectors;
  48 import java.util.stream.Stream;
  49 
  50 public class AnnotationDefaultTest extends TestResult {
  51 
  52     private final static String templateFileName = "AnnotationDefault.java.template";
  53 
  54     private final AnnotationDefaultVerifier verifier;
  55 
  56     public AnnotationDefaultTest() {
  57         verifier = new AnnotationDefaultVerifier();
  58     }
  59 
  60     private void test(String template, Map<String, String> replacements, boolean hasDefault) {
  61         String source = replace(template, replacements);
  62         addTestCase(source);
  63         try {
  64             printf("Testing source:\n%s\n", source);
  65             String className = "AnnotationDefault";
  66             InMemoryFileManager fileManager = compile(source);
  67 
  68             // Map <method-name, expected-annotation-default-values>
  69             Map<String, ExpectedValues> expectedValues =
  70                     getExpectedValues(forName(className, fileManager));
  71             ClassFile classFile = readClassFile(fileManager.getClasses().get(className));
  72 
  73             for (Method method : classFile.methods) {
  74                 String methodName = method.getName(classFile.constant_pool);
  75                 printf("Testing method : %s\n", methodName);
  76                 AnnotationDefault_attribute attr =
  77                         (AnnotationDefault_attribute) method.attributes
  78                                 .get(Attribute.AnnotationDefault);
  79 
  80                 if (hasDefault && !checkNotNull(attr, "Attribute is not null")
  81                         || !hasDefault && checkNull(attr, "Attribute is null")) {
  82                     // stop checking, attr is null
  83                     continue;
  84                 }
  85 
  86                 checkEquals(countNumberOfAttributes(method.attributes.attrs),
  87                         1l,
  88                         "Number of AnnotationDefault attribute");
  89                 checkEquals(classFile.constant_pool
  90                         .getUTF8Value(attr.attribute_name_index),
  91                         "AnnotationDefault", "attribute_name_index");
  92 
  93                 ExpectedValues expectedValue = expectedValues.get(methodName);
  94                 checkEquals((char) attr.default_value.tag, expectedValue.tag(),
  95                         String.format("check tag : %c %s", expectedValue.tag(), expectedValue.name()));
  96                 verifier.testElementValue(attr.default_value.tag,
  97                         this, classFile, attr.default_value,
  98                         expectedValue.values());
  99                 verifier.testLength(attr.default_value.tag, this, attr);
 100             }
 101         } catch (Exception e) {
 102             addFailure(e);
 103         }
 104     }
 105 
 106     private Class<?> forName(String className, InMemoryFileManager fileManager) throws ClassNotFoundException {
 107         return fileManager.getClassLoader(null).loadClass(className);
 108     }
 109 
 110     private Map<String, ExpectedValues> getExpectedValues(Class<?> clazz) {
 111         return Stream.of(clazz.getMethods())
 112                 .map(method -> method.getAnnotation(ExpectedValues.class))
 113                 .filter(Objects::nonNull)
 114                 .collect(Collectors.toMap(
 115                         ExpectedValues::name,
 116                         Function.identity()));
 117     }
 118 
 119     private String replace(String template, Map<String, String> replacements) {
 120         String ans = template;
 121         for (Map.Entry<String, String> replace : replacements.entrySet()) {
 122             ans = ans.replaceAll(replace.getKey(), replace.getValue());
 123         }
 124         return ans;
 125     }
 126 
 127     private long countNumberOfAttributes(Attribute[] attrs) {
 128         return Stream.of(attrs)
 129                 .filter(x -> x instanceof AnnotationDefault_attribute)
 130                 .count();
 131     }
 132 
 133     public String getSource(File templateFileName) throws IOException {
 134         return Files.lines(templateFileName.toPath())
 135                 .filter(str -> !str.startsWith("/*") && !str.startsWith(" *"))
 136                 .collect(Collectors.joining("\n"));
 137     }
 138 
 139     public void test() throws TestFailedException {
 140         try {
 141             String template = getSource(getSourceFile(templateFileName));
 142             for (int i = 0; i < 2; ++i) {
 143                 for (String repeatable : new String[] {"", "@Repeatable(Container.class)"}) {
 144                     for (RetentionPolicy policy : RetentionPolicy.values()) {
 145                         final int finalI = i;
 146                         Map<String, String> replacements = new HashMap<String, String>(){{
 147                             put("%POLICY%", policy.toString());
 148                             if (finalI != 0) {
 149                                 put("default.*\n", ";\n");
 150                             }
 151                             put("%REPEATABLE%", repeatable);
 152                         }};
 153                         test(template, replacements, i == 0);
 154                     }
 155                 }
 156             }
 157         } catch (Throwable e) {
 158             addFailure(e);
 159         } finally {
 160             checkStatus();
 161         }
 162     }
 163 
 164     public static void main(String[] args) throws TestFailedException {
 165         new AnnotationDefaultTest().test();
 166     }
 167 }