提交 5b5bfe29 编写于 作者: J jfranck

8005712: Simplify support for repeating annotations in j.l.r.AnnotatedElement

8004919: AnnotationSupport uses possibly half-constructed AnnotationType instances
Summary: Implements the simplified semantics for repeating annotations and removes the incorrect obtaining of an AnnotationType
Reviewed-by: darcy, abuckley
上级 6f3e485f
......@@ -3075,11 +3075,12 @@ public final
* @throws NullPointerException {@inheritDoc}
* @since 1.5
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
initAnnotationsIfNecessary();
return AnnotationSupport.getOneAnnotation(annotations, annotationClass);
return (A) annotations.get(annotationClass);
}
/**
......@@ -3108,18 +3109,19 @@ public final
*/
public Annotation[] getAnnotations() {
initAnnotationsIfNecessary();
return AnnotationSupport.unpackToArray(annotations);
return AnnotationParser.toArray(annotations);
}
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.8
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
initAnnotationsIfNecessary();
return AnnotationSupport.getOneAnnotation(declaredAnnotations, annotationClass);
return (A) declaredAnnotations.get(annotationClass);
}
/**
......@@ -3138,17 +3140,7 @@ public final
*/
public Annotation[] getDeclaredAnnotations() {
initAnnotationsIfNecessary();
return AnnotationSupport.unpackToArray(declaredAnnotations);
}
/** Returns one "directly" present annotation or null */
<A extends Annotation> A getDirectDeclaredAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
initAnnotationsIfNecessary();
@SuppressWarnings("unchecked") // TODO check safe
A ret = (A)declaredAnnotations.get(annotationClass);
return ret;
return AnnotationParser.toArray(declaredAnnotations);
}
// Annotations cache
......
......@@ -25,7 +25,6 @@
package java.lang;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.util.Properties;
import java.util.PropertyPermission;
......@@ -1197,9 +1196,6 @@ public final class System {
public AnnotationType getAnnotationType(Class<?> klass) {
return klass.getAnnotationType();
}
public <A extends Annotation> A getDirectDeclaredAnnotation(Class<?> klass, Class<A> anno) {
return klass.getDirectDeclaredAnnotation(anno);
}
public byte[] getRawClassTypeAnnotations(Class<?> klass) {
return klass.getRawTypeAnnotations();
}
......
/*
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -35,6 +35,24 @@ import java.lang.annotation.Annotation;
* arrays returned by accessors for array-valued enum members; it will
* have no affect on the arrays returned to other callers.
*
* <p>An annotation A is <em>directly present</em> on an element E if the
* RuntimeVisibleAnnotations or RuntimeVisibleParameterAnnotations attribute
* associated with E either:
* <ul>
* <li>contains A; or
* <li>for invocations of get[Declared]Annotations(Class<T>),
* contains A or exactly one annotation C whose type is the containing
* annotation type of A's type (JLS 9.6) and whose value element contains A
* </ul>
*
* <p>An annotation A is <em>present</em> on an element E if either:
* <ul>
* <li>A is <em>directly present</em> on E; or
* <li>There are no annotations of A's type which are <em>directly present</em>
* on E, and E is a class, and A's type is inheritable (JLS 9.6.3.3), and A is
* present on the superclass of E
* </ul>
*
* <p>If an annotation returned by a method in this interface contains
* (directly or indirectly) a {@link Class}-valued member referring to
* a class that is not accessible in this VM, attempting to read the class
......@@ -50,7 +68,7 @@ import java.lang.annotation.Annotation;
* containing annotation type of T will result in an
* InvalidContainerAnnotationError.
*
* <p>Finally, Attempting to read a member whose definition has evolved
* <p>Finally, attempting to read a member whose definition has evolved
* incompatibly will result in a {@link
* java.lang.annotation.AnnotationTypeMismatchException} or an
* {@link java.lang.annotation.IncompleteAnnotationException}.
......@@ -70,6 +88,9 @@ public interface AnnotatedElement {
* is present on this element, else false. This method
* is designed primarily for convenient access to marker annotations.
*
* <p>The truth value returned by this method is equivalent to:
* {@code getAnnotation(annotationClass) != null}
*
* @param annotationClass the Class object corresponding to the
* annotation type
* @return true if an annotation for the specified annotation
......@@ -110,12 +131,15 @@ public interface AnnotatedElement {
<T extends Annotation> T[] getAnnotations(Class<T> annotationClass);
/**
* Returns all annotations present on this element. (Returns an array
* of length zero if this element has no annotations.) The caller of
* this method is free to modify the returned array; it will have no
* effect on the arrays returned to other callers.
* Returns annotations that are <em>present</em> on this element.
*
* @return all annotations present on this element
* If there are no annotations <em>present</em> on this element, the return
* value is an array of length 0.
*
* The caller of this method is free to modify the returned array; it will
* have no effect on the arrays returned to other callers.
*
* @return annotations present on this element
* @since 1.5
*/
Annotation[] getAnnotations();
......@@ -157,14 +181,16 @@ public interface AnnotatedElement {
<T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass);
/**
* Returns all annotations that are directly present on this
* element. This method ignores inherited annotations. (Returns
* an array of length zero if no annotations are directly present
* on this element.) The caller of this method is free to modify
* the returned array; it will have no effect on the arrays
* returned to other callers.
* Returns annotations that are <em>directly present</em> on this element.
* This method ignores inherited annotations.
*
* If there are no annotations <em>directly present</em> on this element,
* the return value is an array of length 0.
*
* The caller of this method is free to modify the returned array; it will
* have no effect on the arrays returned to other callers.
*
* @return All annotations directly present on this element
* @return annotations directly present on this element
* @since 1.5
*/
Annotation[] getDeclaredAnnotations();
......
......@@ -26,7 +26,6 @@
package java.lang.reflect;
import java.lang.annotation.*;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import sun.reflect.annotation.AnnotationParser;
......@@ -438,8 +437,7 @@ public abstract class Executable extends AccessibleObject
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
return AnnotationSupport.getOneAnnotation(declaredAnnotations(), annotationClass);
return annotationClass.cast(declaredAnnotations().get(annotationClass));
}
/**
......@@ -457,7 +455,7 @@ public abstract class Executable extends AccessibleObject
* {@inheritDoc}
*/
public Annotation[] getDeclaredAnnotations() {
return AnnotationSupport.unpackToArray(declaredAnnotations());
return AnnotationParser.toArray(declaredAnnotations());
}
private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
......
......@@ -1021,8 +1021,7 @@ class Field extends AccessibleObject implements Member {
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
return AnnotationSupport.getOneAnnotation(declaredAnnotations(), annotationClass);
return annotationClass.cast(declaredAnnotations().get(annotationClass));
}
/**
......@@ -1040,7 +1039,7 @@ class Field extends AccessibleObject implements Member {
* {@inheritDoc}
*/
public Annotation[] getDeclaredAnnotations() {
return AnnotationSupport.unpackToArray(declaredAnnotations());
return AnnotationParser.toArray(declaredAnnotations());
}
private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
......
......@@ -233,8 +233,7 @@ public final class Parameter implements AnnotatedElement {
*/
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass);
return AnnotationSupport.getOneAnnotation(declaredAnnotations(), annotationClass);
return annotationClass.cast(declaredAnnotations().get(annotationClass));
}
/**
......
......@@ -97,9 +97,4 @@ public interface JavaLangAccess {
* Returns the ith StackTraceElement for the given throwable.
*/
StackTraceElement getStackTraceElement(Throwable t, int i);
/**
* Returns a directly present annotation.
*/
public <A extends Annotation> A getDirectDeclaredAnnotation(Class<?> klass, Class<A> anno);
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -27,63 +27,29 @@ package sun.reflect.annotation;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import sun.reflect.Reflection;
import sun.misc.JavaLangAccess;
public final class AnnotationSupport {
private static final JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess();
/**
* Finds and returns _one_ annotation of the type indicated by
* {@code annotationClass} from the {@code Map} {@code
* annotationMap}. Looks into containers of the {@code
* annotationClass} (as specified by an the {@code
* annotationClass} type being meta-annotated with an {@code
* ContainedBy} annotation).
*
* @param annotationMap the {@code Map} used to store annotations and indexed by their type
* @param annotationClass the type of annotation to search for
*
* @return in instance of {@code annotationClass} or {@code null} if none were found
*/
public static <A extends Annotation> A getOneAnnotation(final Map<Class<? extends Annotation>, Annotation> annotationMap,
final Class<A> annotationClass) {
@SuppressWarnings("unchecked")
final A candidate = (A)annotationMap.get(annotationClass);
if (candidate != null) {
return candidate;
}
final Class<? extends Annotation> containerClass = getContainer(annotationClass);
if (containerClass != null) {
return unpackOne(annotationMap.get(containerClass), annotationClass);
}
return null; // found none
}
/**
* Finds and returns all annotation of the type indicated by
* {@code annotationClass} from the {@code Map} {@code
* annotationMap}. Looks into containers of the {@code
* annotationClass} (as specified by an the {@code
* annotationClass} type being meta-annotated with an {@code
* ContainedBy} annotation).
* Repeatable} annotation).
*
* @param annotationMap the {@code Map} used to store annotations indexed by their type
* @param annotationClass the type of annotation to search for
*
* @return an array of instances of {@code annotationClass} or an empty array if none were found
*/
public static <A extends Annotation> A[] getMultipleAnnotations(final Map<Class<? extends Annotation>, Annotation> annotationMap,
final Class<A> annotationClass) {
final ArrayList<A> res = new ArrayList<A>();
public static <A extends Annotation> A[] getMultipleAnnotations(
final Map<Class<? extends Annotation>, Annotation> annotationMap,
final Class<A> annotationClass) {
final List<A> res = new ArrayList<A>();
@SuppressWarnings("unchecked")
final A candidate = (A)annotationMap.get(annotationClass);
......@@ -101,49 +67,10 @@ public final class AnnotationSupport {
return res.isEmpty() ? emptyTemplateArray : res.toArray(emptyTemplateArray);
}
/**
* Unpacks the {@code annotationMap} parameter into an array of
* {@code Annotation}s. This method will unpack all repeating
* annotations containers (once). An annotation type is marked as a
* container by meta-annotating it the with the {@code
* ContainerFor} annotation.
*
* @param annotationMap the {@code Map} from where the annotations are unpacked
*
* @return an array of Annotation
*/
public static Annotation[] unpackToArray(Map<Class<? extends Annotation>, Annotation> annotationMap) {
List<Annotation> res = new ArrayList<>();
for (Map.Entry<Class<? extends Annotation>, Annotation> e : annotationMap.entrySet()) {
Class<? extends Annotation> annotationClass = e.getKey();
Annotation annotationInstance = e.getValue();
Class<? extends Annotation> containee = getContainee(e.getKey());
boolean isContainer = javaLangAccess.getDirectDeclaredAnnotation(annotationClass, ContainerFor.class) != null;
if (isContainer) {
res.addAll(unpackAll(annotationInstance, containee));
} else {
res.add(annotationInstance);
}
}
return res.isEmpty()
? AnnotationParser.getEmptyAnnotationArray()
: res.toArray(AnnotationParser.getEmptyAnnotationArray());
}
/** Helper to get the container, or null if none, of an annotation. */
private static <A extends Annotation> Class<? extends Annotation> getContainer(Class<A> annotationClass) {
ContainedBy containerAnnotation =
javaLangAccess.getDirectDeclaredAnnotation(annotationClass, ContainedBy.class);
return (containerAnnotation == null) ? null : containerAnnotation.value();
}
/** Helper to get the containee, or null if this isn't a container, of a possible container annotation. */
private static <A extends Annotation> Class<? extends Annotation> getContainee(Class<A> annotationClass) {
ContainerFor containerAnnotation =
javaLangAccess.getDirectDeclaredAnnotation(annotationClass, ContainerFor.class);
return (containerAnnotation == null) ? null : containerAnnotation.value();
Repeatable containingAnnotation = annotationClass.getDeclaredAnnotation(Repeatable.class);
return (containingAnnotation == null) ? null : containingAnnotation.value();
}
/** Reflectively look up and get the returned array from the the
......@@ -156,14 +83,15 @@ public final class AnnotationSupport {
// value element. Get the AnnotationType, get the "value" element
// and invoke it to get the contents.
Class<?> containerClass = containerInstance.annotationType();
AnnotationType annoType = javaLangAccess.getAnnotationType(containerClass);
Class<? extends Annotation> containerClass = containerInstance.annotationType();
AnnotationType annoType = AnnotationType.getInstance(containerClass);
if (annoType == null)
throw new InvalidContainerAnnotationError(containerInstance + " is an invalid container for repeating annotations");
Method m = annoType.members().get("value");
if (m == null)
throw new InvalidContainerAnnotationError(containerInstance + " is an invalid container for repeating annotations");
throw new InvalidContainerAnnotationError(containerInstance +
" is an invalid container for repeating annotations");
m.setAccessible(true);
@SuppressWarnings("unchecked") // not provably safe, but we catch the ClassCastException
......@@ -175,32 +103,11 @@ public final class AnnotationSupport {
IllegalArgumentException | // parameters doesn't match
InvocationTargetException | // the value method threw an exception
ClassCastException e) { // well, a cast failed ...
throw new InvalidContainerAnnotationError(containerInstance + " is an invalid container for repeating annotations",
e,
containerInstance,
null);
}
}
/* Sanity check type of and return the first annotation instance
* of type {@code annotationClass} from {@code
* containerInstance}.
*/
private static <A extends Annotation> A unpackOne(Annotation containerInstance, Class<A> annotationClass) {
if (containerInstance == null) {
return null;
}
try {
return annotationClass.cast(getValueArray(containerInstance)[0]);
} catch (ArrayIndexOutOfBoundsException | // empty array
ClassCastException | // well, a cast failed ...
NullPointerException e) { // can this NP? for good meassure
throw new InvalidContainerAnnotationError(String.format("%s is an invalid container for repeating annotations of type: %s",
containerInstance, annotationClass),
e,
containerInstance,
annotationClass);
throw new InvalidContainerAnnotationError(
containerInstance + " is an invalid container for repeating annotations",
e,
containerInstance,
null);
}
}
......@@ -208,24 +115,26 @@ public final class AnnotationSupport {
* instances of type {@code annotationClass} from {@code
* containerInstance}.
*/
private static <A extends Annotation> List<A> unpackAll(Annotation containerInstance, Class<A> annotationClass) {
private static <A extends Annotation> List<A> unpackAll(Annotation containerInstance,
Class<A> annotationClass) {
if (containerInstance == null) {
return Collections.emptyList(); // container not present
}
try {
A[] a = getValueArray(containerInstance);
ArrayList<A> l = new ArrayList<>(a.length);
List<A> l = new ArrayList<>(a.length);
for (int i = 0; i < a.length; i++)
l.add(annotationClass.cast(a[i]));
return l;
} catch (ClassCastException |
NullPointerException e) {
throw new InvalidContainerAnnotationError(String.format("%s is an invalid container for repeating annotations of type: %s",
containerInstance, annotationClass),
e,
containerInstance,
annotationClass);
throw new InvalidContainerAnnotationError(
String.format("%s is an invalid container for repeating annotations of type: %s",
containerInstance, annotationClass),
e,
containerInstance,
annotationClass);
}
}
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -23,7 +23,7 @@
/*
* @test
* @bug 7154390
* @bug 7154390 8005712
* @summary Unit test for repeated annotation reflection
*
* @compile RepeatedUnitTest.java subpackage/package-info.java subpackage/Container.java subpackage/Containee.java subpackage/NonRepeated.java subpackage/InheritedContainee.java subpackage/InheritedContainer.java subpackage/InheritedNonRepeated.java
......@@ -58,7 +58,7 @@ public class RepeatedUnitTest {
checkMultiplier(Me1.class.getField("foo"), 1);
// METHOD
checkMultiplier(Me1.class.getDeclaredMethod("mee", null), 100);
checkMultiplier(Me1.class.getDeclaredMethod("mee", (Class<?>[])null), 100);
// INNER CLASS
checkMultiplier(Me1.MiniMee.class, 1000);
......@@ -84,8 +84,7 @@ public class RepeatedUnitTest {
static void packageRepeated(AnnotatedElement e) {
Containee c = e.getAnnotation(Containee.class);
check(c.value() == 1);
check(c == null);
check(2 == countAnnotation(e, Containee.class));
c = e.getAnnotations(Containee.class)[0];
......@@ -93,7 +92,7 @@ public class RepeatedUnitTest {
c = e.getAnnotations(Containee.class)[1];
check(c.value() == 2);
check(2 == containsAnnotationOfType(e.getAnnotations(), Containee.class));
check(0 == containsAnnotationOfType(e.getAnnotations(), Containee.class));
}
static void packageContainer(AnnotatedElement e) {
......@@ -161,14 +160,26 @@ public class RepeatedUnitTest {
}
static void checkMultiplier(AnnotatedElement e, int m) {
// Basic sanity of non-repeating getAnnotation(Class)
check(e.getAnnotation(NonRepeated.class).value() == 5 * m);
// Check count of annotations returned from getAnnotations(Class)
check(4 == countAnnotation(e, Containee.class));
check(1 == countAnnotation(e, Container.class));
check(1 == countAnnotation(e, NonRepeated.class));
// Check contents of array returned from getAnnotations(Class)
check(e.getAnnotations(Containee.class)[2].value() == 3 * m);
check(e.getAnnotations(NonRepeated.class)[0].value() == 5 * m);
// Check getAnnotation(Class)
check(e.getAnnotation(Containee.class) == null);
check(e.getAnnotation(Container.class) != null);
// Check count of annotations returned from getAnnotations()
check(0 == containsAnnotationOfType(e.getAnnotations(), Containee.class));
check(1 == containsAnnotationOfType(e.getAnnotations(), Container.class));
check(1 == containsAnnotationOfType(e.getAnnotations(), NonRepeated.class));
}
static void check(Boolean b) {
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -26,7 +26,6 @@ package subpackage;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@ContainedBy(Container.class)
@Repeatable(Container.class)
public @interface Containee {
int value();
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -26,7 +26,6 @@ package subpackage;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@ContainerFor(Containee.class)
public @interface Container {
Containee[] value();
}
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -27,7 +27,6 @@ import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@ContainedBy(InheritedContainer.class)
@Repeatable(InheritedContainer.class)
public @interface InheritedContainee {
int value();
......
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
......@@ -27,7 +27,6 @@ import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@ContainerFor(InheritedContainee.class)
public @interface InheritedContainer {
InheritedContainee[] value();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册