提交 3e61072f 编写于 作者: A alundblad

8027170: Annotations declared on super-super-class should be overridden by super-class.

Reviewed-by: jfranck
Contributed-by: andreas.lundblad@oracle.com, peter.levart@gmail.com
上级 0737a316
...@@ -3316,7 +3316,7 @@ public final class Class<T> implements java.io.Serializable, ...@@ -3316,7 +3316,7 @@ public final class Class<T> implements java.io.Serializable,
AnnotationData annotationData = annotationData(); AnnotationData annotationData = annotationData();
return AnnotationSupport.getAssociatedAnnotations(annotationData.declaredAnnotations, return AnnotationSupport.getAssociatedAnnotations(annotationData.declaredAnnotations,
annotationData.annotations, this,
annotationClass); annotationClass);
} }
...@@ -3442,6 +3442,10 @@ public final class Class<T> implements java.io.Serializable, ...@@ -3442,6 +3442,10 @@ public final class Class<T> implements java.io.Serializable,
return annotationType; return annotationType;
} }
Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap() {
return annotationData().declaredAnnotations;
}
/* Backing store of user-defined values pertaining to this class. /* Backing store of user-defined values pertaining to this class.
* Maintained by the ClassValue class. * Maintained by the ClassValue class.
*/ */
......
...@@ -26,10 +26,12 @@ package java.lang; ...@@ -26,10 +26,12 @@ package java.lang;
import java.io.*; import java.io.*;
import java.lang.reflect.Executable; import java.lang.reflect.Executable;
import java.lang.annotation.Annotation;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.util.Properties; import java.util.Properties;
import java.util.PropertyPermission; import java.util.PropertyPermission;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.Map;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.security.AllPermission; import java.security.AllPermission;
...@@ -1227,6 +1229,9 @@ public final class System { ...@@ -1227,6 +1229,9 @@ public final class System {
public AnnotationType getAnnotationType(Class<?> klass) { public AnnotationType getAnnotationType(Class<?> klass) {
return klass.getAnnotationType(); return klass.getAnnotationType();
} }
public Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap(Class<?> klass) {
return klass.getDeclaredAnnotationMap();
}
public byte[] getRawClassAnnotations(Class<?> klass) { public byte[] getRawClassAnnotations(Class<?> klass) {
return klass.getRawAnnotations(); return klass.getRawAnnotations();
} }
......
...@@ -28,6 +28,7 @@ package sun.misc; ...@@ -28,6 +28,7 @@ package sun.misc;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Executable; import java.lang.reflect.Executable;
import java.security.AccessControlContext; import java.security.AccessControlContext;
import java.util.Map;
import sun.reflect.ConstantPool; import sun.reflect.ConstantPool;
import sun.reflect.annotation.AnnotationType; import sun.reflect.annotation.AnnotationType;
...@@ -49,6 +50,11 @@ public interface JavaLangAccess { ...@@ -49,6 +50,11 @@ public interface JavaLangAccess {
*/ */
AnnotationType getAnnotationType(Class<?> klass); AnnotationType getAnnotationType(Class<?> klass);
/**
* Get the declared annotations for a given class, indexed by their types.
*/
Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap(Class<?> klass);
/** /**
* Get the array of bytes that is the class-file representation * Get the array of bytes that is the class-file representation
* of this Class' annotations. * of this Class' annotations.
......
...@@ -32,8 +32,12 @@ import java.util.Arrays; ...@@ -32,8 +32,12 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import sun.misc.JavaLangAccess;
public final class AnnotationSupport { public final class AnnotationSupport {
private static final JavaLangAccess LANG_ACCESS = sun.misc.SharedSecrets.getJavaLangAccess();
/** /**
* Finds and returns all annotations in {@code annotations} matching * Finds and returns all annotations in {@code annotations} matching
...@@ -51,17 +55,13 @@ public final class AnnotationSupport { ...@@ -51,17 +55,13 @@ public final class AnnotationSupport {
* *
* @param annotations the {@code Map} in which to search for annotations * @param annotations the {@code Map} in which to search for annotations
* @param annoClass the type of annotation to search for * @param annoClass the type of annotation to search for
* @param includeNonInheritedContainees if false, the annoClass must be
* inheritable for the containers to be searched
* *
* @return an array of instances of {@code annoClass} or an empty * @return an array of instances of {@code annoClass} or an empty
* array if none were found * array if none were found
*/ */
private static <A extends Annotation> A[] getDirectlyAndIndirectlyPresent( public static <A extends Annotation> A[] getDirectlyAndIndirectlyPresent(
Map<Class<? extends Annotation>, Annotation> annotations, Map<Class<? extends Annotation>, Annotation> annotations,
Class<A> annoClass, Class<A> annoClass) {
boolean includeNonInheritedContainees) {
List<A> result = new ArrayList<A>(); List<A> result = new ArrayList<A>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
...@@ -69,37 +69,19 @@ public final class AnnotationSupport { ...@@ -69,37 +69,19 @@ public final class AnnotationSupport {
if (direct != null) if (direct != null)
result.add(direct); result.add(direct);
if (includeNonInheritedContainees ||
AnnotationType.getInstance(annoClass).isInherited()) {
A[] indirect = getIndirectlyPresent(annotations, annoClass); A[] indirect = getIndirectlyPresent(annotations, annoClass);
if (indirect != null && indirect.length != 0) {
if (indirect != null) {
boolean indirectFirst = direct == null || boolean indirectFirst = direct == null ||
containerBeforeContainee(annotations, annoClass); containerBeforeContainee(annotations, annoClass);
result.addAll((indirectFirst ? 0 : 1), Arrays.asList(indirect)); result.addAll((indirectFirst ? 0 : 1), Arrays.asList(indirect));
} }
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
A[] arr = (A[]) Array.newInstance(annoClass, result.size()); A[] arr = (A[]) Array.newInstance(annoClass, result.size());
return result.toArray(arr); return result.toArray(arr);
} }
/**
* Equivalent to calling {@code getDirectlyAndIndirectlyPresentAnnotations(
* annotations, annoClass, true)}.
*/
public static <A extends Annotation> A[] getDirectlyAndIndirectlyPresent(
Map<Class<? extends Annotation>, Annotation> annotations,
Class<A> annoClass) {
return getDirectlyAndIndirectlyPresent(annotations, annoClass, true);
}
/** /**
* Finds and returns all annotations matching the given {@code annoClass} * Finds and returns all annotations matching the given {@code annoClass}
* indirectly present in {@code annotations}. * indirectly present in {@code annotations}.
...@@ -166,22 +148,28 @@ public final class AnnotationSupport { ...@@ -166,22 +148,28 @@ public final class AnnotationSupport {
* annotations in the relevant map. * annotations in the relevant map.
* *
* @param declaredAnnotations the declared annotations indexed by their types * @param declaredAnnotations the declared annotations indexed by their types
* @param allAnnotations declared and inherited annotations indexed by their types * @param decl the class declaration on which to search for annotations
* @param annoClass the type of annotation to search for * @param annoClass the type of annotation to search for
* *
* @return an array of instances of {@code annoClass} or an empty array if none were found. * @return an array of instances of {@code annoClass} or an empty array if none were found.
*/ */
public static <A extends Annotation> A[] getAssociatedAnnotations( public static <A extends Annotation> A[] getAssociatedAnnotations(
Map<Class<? extends Annotation>, Annotation> declaredAnnotations, Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
Map<Class<? extends Annotation>, Annotation> allAnnotations, Class<?> decl,
Class<A> annoClass) { Class<A> annoClass) {
Objects.requireNonNull(decl);
// Search declared // Search declared
A[] result = getDirectlyAndIndirectlyPresent(declaredAnnotations, annoClass); A[] result = getDirectlyAndIndirectlyPresent(declaredAnnotations, annoClass);
// Search inherited // Search inherited
if (result.length == 0) if(AnnotationType.getInstance(annoClass).isInherited()) {
result = getDirectlyAndIndirectlyPresent(allAnnotations, annoClass, false); Class<?> superDecl = decl.getSuperclass();
while (result.length == 0 && superDecl != null) {
result = getDirectlyAndIndirectlyPresent(LANG_ACCESS.getDeclaredAnnotationMap(superDecl), annoClass);
superDecl = superDecl.getSuperclass();
}
}
return result; return result;
} }
......
/*
* Copyright (c) 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8027170
* @summary getAnnotationsByType needs to take the class hierarchy into account
* when determining which annotations are associated with a given
* class.
* @run main InheritedAssociatedAnnotations
*/
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.Arrays;
public class InheritedAssociatedAnnotations {
public static void main(String[] args) {
checkAssociated(A3.class);
checkAssociated(B3.class);
checkAssociated(C3.class);
checkAssociated(D3.class);
}
private static void checkAssociated(AnnotatedElement ae) {
Ann[] actual = ae.getAnnotationsByType(Ann.class);
Ann[] expected = ae.getAnnotation(ExpectedAssociated.class).value();
if (!Arrays.equals(actual, expected)) {
throw new RuntimeException(String.format(
"Test failed for %s: Expected %s but got %s.",
ae,
Arrays.toString(expected),
Arrays.toString(actual)));
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface ExpectedAssociated {
Ann[] value();
}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(AnnCont.class)
@interface Ann {
int value();
}
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface AnnCont {
Ann[] value();
}
@Ann(10)
class A1 {}
@Ann(20)
class A2 extends A1 {}
@ExpectedAssociated({@Ann(20)})
class A3 extends A2 {}
@Ann(10) @Ann(11)
class B1 {}
@Ann(20)
class B2 extends B1 {}
@ExpectedAssociated({@Ann(20)})
class B3 extends B2 {}
@Ann(10)
class C1 {}
@Ann(20) @Ann(21)
class C2 extends C1 {}
@ExpectedAssociated({@Ann(20), @Ann(21)})
class C3 extends C2 {}
@Ann(10) @Ann(11)
class D1 {}
@Ann(20) @Ann(21)
class D2 extends D1 {}
@ExpectedAssociated({@Ann(20), @Ann(21)})
class D3 extends D2 {}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册