1 /*
   2  * Copyright (c) 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 package org.graalvm.util;
  26 
  27 import java.lang.annotation.Annotation;
  28 import java.lang.reflect.AnnotatedElement;
  29 
  30 /**
  31  * Wrapper class for annotation access that defends against
  32  * https://bugs.openjdk.java.net/browse/JDK-7183985: when an annotation declares a Class<?> array
  33  * parameter and one of the referenced classes is not present on the classpath parsing the
  34  * annotations will result in an ArrayStoreException instead of caching of a
  35  * TypeNotPresentExceptionProxy. This is a problem in JDK8 but was fixed in JDK11+. This wrapper
  36  * class also defends against incomplete class path issues. If the element for which annotations are
  37  * queried is a JMVCI value, i.e., a HotSpotResolvedJavaField, or HotSpotResolvedJavaMethod, the
  38  * annotations are read via HotSpotJDKReflection using the
  39  * getFieldAnnotation()/getMethodAnnotation() methods which first construct the field/method object
  40  * via CompilerToVM.asReflectionField()/CompilerToVM.asReflectionExecutable() which eagerly try to
  41  * resolve the types referenced in the element signature. If a field declared type or a method
  42  * return type is missing then JVMCI throws a NoClassDefFoundError.
  43  */
  44 public final class GuardedAnnotationAccess {
  45 
  46     public static boolean isAnnotationPresent(AnnotatedElement element, Class<? extends Annotation> annotationClass) {
  47         return getAnnotation(element, annotationClass) != null;
  48     }
  49 
  50     public static <T extends Annotation> T getAnnotation(AnnotatedElement element, Class<T> annotationType) {
  51         try {
  52             return element.getAnnotation(annotationType);
  53         } catch (ArrayStoreException | NoClassDefFoundError e) {
  54             /*
  55              * Returning null essentially means that the element doesn't declare the annotationType,
  56              * but we cannot know that since the annotation parsing failed. However, this allows us
  57              * to defend against crashing the image builder if the above JDK bug is encountered in
  58              * user code or if the user code references types missing from the classpath.
  59              */
  60             return null;
  61         }
  62     }
  63 
  64     public static Annotation[] getAnnotations(AnnotatedElement element) {
  65         try {
  66             return element.getAnnotations();
  67         } catch (ArrayStoreException | NoClassDefFoundError e) {
  68             /*
  69              * Returning an empty array essentially means that the element doesn't declare any
  70              * annotations, but we know that it is not true since the reason the annotation parsing
  71              * failed is because some annotation referenced a missing class. However, this allows us
  72              * to defend against crashing the image builder if the above JDK bug is encountered in
  73              * user code or if the user code references types missing from the classpath.
  74              */
  75             return new Annotation[0];
  76         }
  77     }
  78 
  79     public static <T extends Annotation> T getDeclaredAnnotation(AnnotatedElement element, Class<T> annotationType) {
  80         try {
  81             return element.getDeclaredAnnotation(annotationType);
  82         } catch (ArrayStoreException | NoClassDefFoundError e) {
  83             /*
  84              * Returning null essentially means that the element doesn't declare the annotationType,
  85              * but we cannot know that since the annotation parsing failed. However, this allows us
  86              * to defend against crashing the image builder if the above JDK bug is encountered in
  87              * user code or if the user code references types missing from the classpath.
  88              */
  89             return null;
  90         }
  91     }
  92 
  93     public static Annotation[] getDeclaredAnnotations(AnnotatedElement element) {
  94         try {
  95             return element.getDeclaredAnnotations();
  96         } catch (ArrayStoreException | NoClassDefFoundError e) {
  97             /*
  98              * Returning an empty array essentially means that the element doesn't declare any
  99              * annotations, but we know that it is not true since the reason the annotation parsing
 100              * failed is because it at least one annotation referenced a missing class. However,
 101              * this allows us to defend against crashing the image builder if the above JDK bug is
 102              * encountered in user code or if the user code references types missing from the
 103              * classpath.
 104              */
 105             return new Annotation[0];
 106         }
 107     }
 108 }