mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-09 01:48:34 +00:00
8027170: Annotations declared on super-super-class should be overridden by super-class
Co-authored-by: Peter Levart <peter.levart@gmail.com> Reviewed-by: jfranck
This commit is contained in:
parent
f14e06950e
commit
5db9cc7bed
@ -3316,7 +3316,7 @@ public final class Class<T> implements java.io.Serializable,
|
||||
|
||||
AnnotationData annotationData = annotationData();
|
||||
return AnnotationSupport.getAssociatedAnnotations(annotationData.declaredAnnotations,
|
||||
annotationData.annotations,
|
||||
this,
|
||||
annotationClass);
|
||||
}
|
||||
|
||||
@ -3442,6 +3442,10 @@ public final class Class<T> implements java.io.Serializable,
|
||||
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.
|
||||
*/
|
||||
|
||||
@ -26,10 +26,12 @@ package java.lang;
|
||||
|
||||
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 final class System {
|
||||
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();
|
||||
}
|
||||
|
||||
@ -28,6 +28,7 @@ package sun.misc;
|
||||
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;
|
||||
@ -49,6 +50,11 @@ public interface JavaLangAccess {
|
||||
*/
|
||||
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.
|
||||
|
||||
@ -32,8 +32,12 @@ import java.util.Arrays;
|
||||
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 @@ public final class AnnotationSupport {
|
||||
*
|
||||
* @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 @@ public final class AnnotationSupport {
|
||||
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 @@ public final class AnnotationSupport {
|
||||
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 @@ public final class AnnotationSupport {
|
||||
* 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;
|
||||
}
|
||||
|
||||
@ -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 {}
|
||||
Loading…
x
Reference in New Issue
Block a user