--- old/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java 2017-01-17 14:37:10.399603358 +0100 +++ new/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java 2017-01-17 14:37:10.296602684 +0100 @@ -182,77 +182,38 @@ * (container), cast it to an array of annotations and return the result. */ private static A[] getValueArray(Annotation container) { - try { - // According to JLS the container must have an array-valued value - // method. Get the AnnotationType, get the "value" method and invoke - // it to get the content. - - Class containerClass = container.annotationType(); - AnnotationType annoType = AnnotationType.getInstance(containerClass); - if (annoType == null) - throw invalidContainerException(container, null); - Method m = annoType.members().get("value"); + // According to JLS the container must have an array-valued value + // method. Usually the annotation will be implemented as a dynamic Proxy + // with AnnotationInvocationHandler as the invocation handler... + AnnotationInvocationHandler oneOfUs = AnnotationInvocationHandler.asOneOfUs(container); + if (oneOfUs != null) { + try { + // This will erase to (Annotation[]) but we do a runtime cast on the + // return-value in the method that call this method. + @SuppressWarnings("unchecked") + A[] values = (A[]) oneOfUs.getValue(/* interned */ "value"); + return values; + } catch (Throwable t) { + throw invalidContainerException(container, t); + } + } else { + // In theory there might be instances of Annotations that are not + // implemented using Proxies. Try to invoke the "value" element with + // reflection using accessible Method object. + Method m = AnnotationType.getInstance(container.annotationType()) + .accessibleMembers().get("value"); if (m == null) throw invalidContainerException(container, null); - if (Proxy.isProxyClass(container.getClass())) { - // Invoke by invocation handler - InvocationHandler handler = Proxy.getInvocationHandler(container); - - try { - // This will erase to (Annotation[]) but we do a runtime cast on the - // return-value in the method that call this method. - @SuppressWarnings("unchecked") - A[] values = (A[]) handler.invoke(container, m, null); - return values; - } catch (Throwable t) { // from InvocationHandler::invoke - throw invalidContainerException(container, t); - } - } else { - // In theory there might be instances of Annotations that are not - // implemented using Proxies. Try to invoke the "value" element with - // reflection. - - // Declaring class should be an annotation type - Class iface = m.getDeclaringClass(); - if (!iface.isAnnotation()) - throw new UnsupportedOperationException("Unsupported container annotation type."); - // Method must be public - if (!Modifier.isPublic(m.getModifiers())) - throw new UnsupportedOperationException("Unsupported value member."); - - // Interface might not be public though - final Method toInvoke; - if (!Modifier.isPublic(iface.getModifiers())) { - if (System.getSecurityManager() != null) { - toInvoke = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Method run() { - Method res = ReflectionFactory.getReflectionFactory().leafCopyMethod(m); - res.setAccessible(true); - return res; - } - }); - } else { - toInvoke = ReflectionFactory.getReflectionFactory().leafCopyMethod(m); - toInvoke.setAccessible(true); - } - } else { - toInvoke = m; - } - + try { // This will erase to (Annotation[]) but we do a runtime cast on the // return-value in the method that call this method. @SuppressWarnings("unchecked") - A[] values = (A[]) toInvoke.invoke(container); - + A[] values = (A[]) m.invoke(container); return values; + } catch (Throwable t) { + throw invalidContainerException(container, t); } - } catch (IllegalAccessException | // couldn't loosen security - IllegalArgumentException | // parameters doesn't match - InvocationTargetException | // the value method threw an exception - ClassCastException e) { - throw invalidContainerException(container, e); } }