OpenJDK / jdk / hs
changeset 21358:d41ff832d4f6
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
author | alundblad |
---|---|
date | Thu, 24 Oct 2013 18:52:13 +0200 |
parents | eb15eae19cd9 |
children | 2d32ce9ea2b4 |
files | jdk/src/share/classes/java/lang/Class.java jdk/src/share/classes/java/lang/System.java jdk/src/share/classes/sun/misc/JavaLangAccess.java jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java jdk/test/java/lang/annotation/repeatingAnnotations/InheritedAssociatedAnnotations.java |
diffstat | 5 files changed, 157 insertions(+), 34 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/share/classes/java/lang/Class.java Wed Oct 23 15:37:40 2013 +0400 +++ b/jdk/src/share/classes/java/lang/Class.java Thu Oct 24 18:52:13 2013 +0200 @@ -3316,7 +3316,7 @@ AnnotationData annotationData = annotationData(); return AnnotationSupport.getAssociatedAnnotations(annotationData.declaredAnnotations, - annotationData.annotations, + this, annotationClass); } @@ -3442,6 +3442,10 @@ return annotationType; } + Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap() { + return annotationData().declaredAnnotations; + } + /* Backing store of user-defined values pertaining to this class. * Maintained by the ClassValue class. */
--- a/jdk/src/share/classes/java/lang/System.java Wed Oct 23 15:37:40 2013 +0400 +++ b/jdk/src/share/classes/java/lang/System.java Thu Oct 24 18:52:13 2013 +0200 @@ -26,10 +26,12 @@ import java.io.*; import java.lang.reflect.Executable; +import java.lang.annotation.Annotation; import java.security.AccessControlContext; import java.util.Properties; import java.util.PropertyPermission; import java.util.StringTokenizer; +import java.util.Map; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.AllPermission; @@ -1227,6 +1229,9 @@ public AnnotationType getAnnotationType(Class<?> klass) { return klass.getAnnotationType(); } + public Map<Class<? extends Annotation>, Annotation> getDeclaredAnnotationMap(Class<?> klass) { + return klass.getDeclaredAnnotationMap(); + } public byte[] getRawClassAnnotations(Class<?> klass) { return klass.getRawAnnotations(); }
--- a/jdk/src/share/classes/sun/misc/JavaLangAccess.java Wed Oct 23 15:37:40 2013 +0400 +++ b/jdk/src/share/classes/sun/misc/JavaLangAccess.java Thu Oct 24 18:52:13 2013 +0200 @@ -28,6 +28,7 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Executable; import java.security.AccessControlContext; +import java.util.Map; import sun.reflect.ConstantPool; import sun.reflect.annotation.AnnotationType; @@ -50,6 +51,11 @@ 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 * of this Class' annotations. */
--- a/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java Wed Oct 23 15:37:40 2013 +0400 +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotationSupport.java Thu Oct 24 18:52:13 2013 +0200 @@ -32,8 +32,12 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; + +import sun.misc.JavaLangAccess; public final class AnnotationSupport { + private static final JavaLangAccess LANG_ACCESS = sun.misc.SharedSecrets.getJavaLangAccess(); /** * Finds and returns all annotations in {@code annotations} matching @@ -51,17 +55,13 @@ * * @param annotations the {@code Map} in which to search for annotations * @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 * 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, - Class<A> annoClass, - boolean includeNonInheritedContainees) { - + Class<A> annoClass) { List<A> result = new ArrayList<A>(); @SuppressWarnings("unchecked") @@ -69,17 +69,12 @@ if (direct != null) 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) { + boolean indirectFirst = direct == null || + containerBeforeContainee(annotations, annoClass); - if (indirect != null) { - - boolean indirectFirst = direct == null || - containerBeforeContainee(annotations, annoClass); - - result.addAll((indirectFirst ? 0 : 1), Arrays.asList(indirect)); - } + result.addAll((indirectFirst ? 0 : 1), Arrays.asList(indirect)); } @SuppressWarnings("unchecked") @@ -87,19 +82,6 @@ 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} * indirectly present in {@code annotations}. @@ -166,22 +148,28 @@ * annotations in the relevant map. * * @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 * * @return an array of instances of {@code annoClass} or an empty array if none were found. */ public static <A extends Annotation> A[] getAssociatedAnnotations( Map<Class<? extends Annotation>, Annotation> declaredAnnotations, - Map<Class<? extends Annotation>, Annotation> allAnnotations, + Class<?> decl, Class<A> annoClass) { + Objects.requireNonNull(decl); // Search declared A[] result = getDirectlyAndIndirectlyPresent(declaredAnnotations, annoClass); // Search inherited - if (result.length == 0) - result = getDirectlyAndIndirectlyPresent(allAnnotations, annoClass, false); + if(AnnotationType.getInstance(annoClass).isInherited()) { + Class<?> superDecl = decl.getSuperclass(); + while (result.length == 0 && superDecl != null) { + result = getDirectlyAndIndirectlyPresent(LANG_ACCESS.getDeclaredAnnotationMap(superDecl), annoClass); + superDecl = superDecl.getSuperclass(); + } + } return result; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/annotation/repeatingAnnotations/InheritedAssociatedAnnotations.java Thu Oct 24 18:52:13 2013 +0200 @@ -0,0 +1,120 @@ +/* + * 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 {}