8057804: AnnotatedType interfaces provide no way to get annotations on owner type
Reviewed-by: darcy, redestad
This commit is contained in:
parent
570ebc4176
commit
5c29ca104e
@ -42,4 +42,19 @@ public interface AnnotatedArrayType extends AnnotatedType {
|
||||
* @see GenericArrayType#getGenericComponentType()
|
||||
*/
|
||||
AnnotatedType getAnnotatedGenericComponentType();
|
||||
|
||||
/**
|
||||
* Returns the potentially annotated type that this type is a member of, if
|
||||
* this type represents a nested type. For example, if this type is
|
||||
* {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
|
||||
*
|
||||
* <p>Returns {@code null} for an {@code AnnotatedType} that is an instance
|
||||
* of {@code AnnotatedArrayType}.
|
||||
*
|
||||
* @return {@code null}
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
@Override
|
||||
AnnotatedType getAnnotatedOwnerType();
|
||||
}
|
||||
|
@ -41,4 +41,26 @@ public interface AnnotatedParameterizedType extends AnnotatedType {
|
||||
* @see ParameterizedType#getActualTypeArguments()
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedActualTypeArguments();
|
||||
|
||||
/**
|
||||
* Returns the potentially annotated type that this type is a member of, if
|
||||
* this type represents a nested type. For example, if this type is
|
||||
* {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
|
||||
*
|
||||
* <p>Returns {@code null} if this {@code AnnotatedType} represents a
|
||||
* top-level type, or a local or anonymous class, or a primitive type, or
|
||||
* void.
|
||||
*
|
||||
* @return an {@code AnnotatedType} object representing the potentially
|
||||
* annotated type that this type is a member of, or {@code null}
|
||||
* @throws TypeNotPresentException if the owner type
|
||||
* refers to a non-existent type declaration
|
||||
* @throws MalformedParameterizedTypeException if the owner type
|
||||
* refers to a parameterized type that cannot be instantiated
|
||||
* for any reason
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
@Override
|
||||
AnnotatedType getAnnotatedOwnerType();
|
||||
}
|
||||
|
@ -35,6 +35,37 @@ package java.lang.reflect;
|
||||
*/
|
||||
public interface AnnotatedType extends AnnotatedElement {
|
||||
|
||||
/**
|
||||
* Returns the potentially annotated type that this type is a member of, if
|
||||
* this type represents a nested type. For example, if this type is
|
||||
* {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
|
||||
*
|
||||
* <p>Returns {@code null} if this {@code AnnotatedType} represents a
|
||||
* top-level type, or a local or anonymous class, or a primitive type, or
|
||||
* void.
|
||||
*
|
||||
* <p>Returns {@code null} if this {@code AnnotatedType} is an instance of
|
||||
* {@code AnnotatedArrayType}, {@code AnnotatedTypeVariable}, or
|
||||
* {@code AnnotatedWildcardType}.
|
||||
*
|
||||
* @implSpec
|
||||
* This default implementation returns {@code null} and performs no other
|
||||
* action.
|
||||
*
|
||||
* @return an {@code AnnotatedType} object representing the potentially
|
||||
* annotated type that this type is a member of, or {@code null}
|
||||
* @throws TypeNotPresentException if the owner type
|
||||
* refers to a non-existent type declaration
|
||||
* @throws MalformedParameterizedTypeException if the owner type
|
||||
* refers to a parameterized type that cannot be instantiated
|
||||
* for any reason
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
default AnnotatedType getAnnotatedOwnerType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the underlying type that this annotated type represents.
|
||||
*
|
||||
|
@ -43,4 +43,19 @@ public interface AnnotatedTypeVariable extends AnnotatedType {
|
||||
* @see TypeVariable#getBounds()
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedBounds();
|
||||
|
||||
/**
|
||||
* Returns the potentially annotated type that this type is a member of, if
|
||||
* this type represents a nested type. For example, if this type is
|
||||
* {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
|
||||
*
|
||||
* <p>Returns {@code null} for an {@code AnnotatedType} that is an instance
|
||||
* of {@code AnnotatedTypeVariable}.
|
||||
*
|
||||
* @return {@code null}
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
@Override
|
||||
AnnotatedType getAnnotatedOwnerType();
|
||||
}
|
||||
|
@ -54,4 +54,19 @@ public interface AnnotatedWildcardType extends AnnotatedType {
|
||||
* @see WildcardType#getUpperBounds()
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedUpperBounds();
|
||||
|
||||
/**
|
||||
* Returns the potentially annotated type that this type is a member of, if
|
||||
* this type represents a nested type. For example, if this type is
|
||||
* {@code @TA O<T>.I<S>}, return a representation of {@code @TA O<T>}.
|
||||
*
|
||||
* <p>Returns {@code null} for an {@code AnnotatedType} that is an instance
|
||||
* of {@code AnnotatedWildcardType}.
|
||||
*
|
||||
* @return {@code null}
|
||||
*
|
||||
* @since 1.9
|
||||
*/
|
||||
@Override
|
||||
AnnotatedType getAnnotatedOwnerType();
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public final class AnnotatedTypeFactory {
|
||||
decl);
|
||||
if (type instanceof Class) {
|
||||
return new AnnotatedTypeBaseImpl(type,
|
||||
addNesting(type, currentLoc),
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
@ -74,7 +74,7 @@ public final class AnnotatedTypeFactory {
|
||||
decl);
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
|
||||
addNesting(type, currentLoc),
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
@ -88,7 +88,7 @@ public final class AnnotatedTypeFactory {
|
||||
throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen.");
|
||||
}
|
||||
|
||||
private static LocationInfo addNesting(Type type, LocationInfo addTo) {
|
||||
public static LocationInfo nestingForType(Type type, LocationInfo addTo) {
|
||||
if (isArray(type))
|
||||
return addTo;
|
||||
if (type instanceof Class) {
|
||||
@ -96,13 +96,13 @@ public final class AnnotatedTypeFactory {
|
||||
if (clz.getEnclosingClass() == null)
|
||||
return addTo;
|
||||
if (Modifier.isStatic(clz.getModifiers()))
|
||||
return addNesting(clz.getEnclosingClass(), addTo);
|
||||
return addNesting(clz.getEnclosingClass(), addTo.pushInner());
|
||||
return nestingForType(clz.getEnclosingClass(), addTo);
|
||||
return nestingForType(clz.getEnclosingClass(), addTo.pushInner());
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
ParameterizedType t = (ParameterizedType)type;
|
||||
if (t.getOwnerType() == null)
|
||||
return addTo;
|
||||
return addNesting(t.getOwnerType(), addTo.pushInner());
|
||||
return nestingForType(t.getOwnerType(), addTo.pushInner());
|
||||
}
|
||||
return addTo;
|
||||
}
|
||||
@ -118,8 +118,9 @@ public final class AnnotatedTypeFactory {
|
||||
return false;
|
||||
}
|
||||
|
||||
static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0];
|
||||
static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
|
||||
new TypeAnnotation[0], new TypeAnnotation[0], null);
|
||||
EMPTY_TYPE_ANNOTATION_ARRAY, EMPTY_TYPE_ANNOTATION_ARRAY, null);
|
||||
static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
|
||||
|
||||
private static class AnnotatedTypeBaseImpl implements AnnotatedType {
|
||||
@ -177,6 +178,30 @@ public final class AnnotatedTypeFactory {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedOwnerType() {
|
||||
if (!(type instanceof Class<?>))
|
||||
throw new IllegalStateException("Can't compute owner");
|
||||
|
||||
Class<?> inner = (Class<?>)type;
|
||||
Class<?> owner = inner.getDeclaringClass();
|
||||
if (owner == null) // top-level, local or anonymous
|
||||
return null;
|
||||
if (inner.isPrimitive() || inner == Void.TYPE)
|
||||
return null;
|
||||
|
||||
LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1));
|
||||
TypeAnnotation[]all = getTypeAnnotations();
|
||||
List<TypeAnnotation> l = new ArrayList<>(all.length);
|
||||
|
||||
for (TypeAnnotation t : all)
|
||||
if (t.getLocationInfo().isSameLocationInfo(outerLoc))
|
||||
l.add(t);
|
||||
|
||||
return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
|
||||
|
||||
}
|
||||
|
||||
// Implementation details
|
||||
final LocationInfo getLocation() {
|
||||
return location;
|
||||
@ -198,11 +223,17 @@ public final class AnnotatedTypeFactory {
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedGenericComponentType() {
|
||||
return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(),
|
||||
getLocation().pushArray(),
|
||||
getTypeAnnotations(),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
Type t = getComponentType();
|
||||
return AnnotatedTypeFactory.buildAnnotatedType(t,
|
||||
nestingForType(t, getLocation().pushArray()),
|
||||
getTypeAnnotations(),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedOwnerType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Type getComponentType() {
|
||||
@ -227,6 +258,11 @@ public final class AnnotatedTypeFactory {
|
||||
return getTypeVariable().getAnnotatedBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedOwnerType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private TypeVariable<?> getTypeVariable() {
|
||||
return (TypeVariable)getType();
|
||||
}
|
||||
@ -248,19 +284,35 @@ public final class AnnotatedTypeFactory {
|
||||
int initialCapacity = getTypeAnnotations().length;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
|
||||
LocationInfo newLoc = getLocation().pushTypeArg((byte)i);
|
||||
LocationInfo newLoc = nestingForType(arguments[i], getLocation().pushTypeArg((byte)i));
|
||||
for (TypeAnnotation t : getTypeAnnotations())
|
||||
if (t.getLocationInfo().isSameLocationInfo(newLoc))
|
||||
l.add(t);
|
||||
res[i] = buildAnnotatedType(arguments[i],
|
||||
newLoc,
|
||||
l.toArray(new TypeAnnotation[0]),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
newLoc,
|
||||
l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedOwnerType() {
|
||||
Type owner = getParameterizedType().getOwnerType();
|
||||
if (owner == null)
|
||||
return null;
|
||||
LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1));
|
||||
TypeAnnotation[]all = getTypeAnnotations();
|
||||
List<TypeAnnotation> l = new ArrayList<>(all.length);
|
||||
|
||||
for (TypeAnnotation t : all)
|
||||
if (t.getLocationInfo().isSameLocationInfo(outerLoc))
|
||||
l.add(t);
|
||||
|
||||
return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
|
||||
}
|
||||
|
||||
private ParameterizedType getParameterizedType() {
|
||||
return (ParameterizedType)getType();
|
||||
}
|
||||
@ -279,11 +331,11 @@ public final class AnnotatedTypeFactory {
|
||||
public AnnotatedType[] getAnnotatedUpperBounds() {
|
||||
if (!hasUpperBounds()) {
|
||||
return new AnnotatedType[] { buildAnnotatedType(Object.class,
|
||||
LocationInfo.BASE_LOCATION,
|
||||
new TypeAnnotation[0],
|
||||
new TypeAnnotation[0],
|
||||
null)
|
||||
};
|
||||
LocationInfo.BASE_LOCATION,
|
||||
EMPTY_TYPE_ANNOTATION_ARRAY,
|
||||
EMPTY_TYPE_ANNOTATION_ARRAY,
|
||||
null)
|
||||
};
|
||||
}
|
||||
return getAnnotatedBounds(getWildcardType().getUpperBounds());
|
||||
}
|
||||
@ -295,21 +347,26 @@ public final class AnnotatedTypeFactory {
|
||||
return getAnnotatedBounds(getWildcardType().getLowerBounds());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedOwnerType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
|
||||
AnnotatedType[] res = new AnnotatedType[bounds.length];
|
||||
Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
|
||||
LocationInfo newLoc = getLocation().pushWildcard();
|
||||
int initialCapacity = getTypeAnnotations().length;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
LocationInfo newLoc = nestingForType(bounds[i], getLocation().pushWildcard());
|
||||
List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
|
||||
for (TypeAnnotation t : getTypeAnnotations())
|
||||
if (t.getLocationInfo().isSameLocationInfo(newLoc))
|
||||
l.add(t);
|
||||
res[i] = buildAnnotatedType(bounds[i],
|
||||
newLoc,
|
||||
l.toArray(new TypeAnnotation[0]),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
newLoc,
|
||||
l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2015, 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
|
||||
@ -187,13 +187,28 @@ public final class TypeAnnotation {
|
||||
return new LocationInfo(newDepth, res);
|
||||
}
|
||||
|
||||
/** Pop a series of locations matching {@code tag}. Stop poping as soon as a non-matching tag is found. */
|
||||
public LocationInfo popAllLocations(byte tag) {
|
||||
LocationInfo l = this;
|
||||
int newDepth = l.depth;
|
||||
while(newDepth > 0 && l.locations[newDepth - 1].tag == tag) {
|
||||
newDepth--;
|
||||
}
|
||||
if (newDepth != l.depth) {
|
||||
Location[] res = new Location[newDepth];
|
||||
System.arraycopy(this.locations, 0, res, 0, newDepth);
|
||||
return new LocationInfo(newDepth, res);
|
||||
} else
|
||||
return l;
|
||||
}
|
||||
|
||||
public TypeAnnotation[] filter(TypeAnnotation[] ta) {
|
||||
ArrayList<TypeAnnotation> l = new ArrayList<>(ta.length);
|
||||
for (TypeAnnotation t : ta) {
|
||||
if (isSameLocationInfo(t.getLocationInfo()))
|
||||
l.add(t);
|
||||
}
|
||||
return l.toArray(new TypeAnnotation[0]);
|
||||
return l.toArray(AnnotatedTypeFactory.EMPTY_TYPE_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
boolean isSameLocationInfo(LocationInfo other) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2015, 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
|
||||
@ -32,7 +32,6 @@ import java.nio.BufferUnderflowException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import jdk.internal.misc.SharedSecrets;
|
||||
@ -67,9 +66,8 @@ public final class TypeAnnotationParser {
|
||||
Type type,
|
||||
TypeAnnotationTarget filter) {
|
||||
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
container);
|
||||
cp, decl, container);
|
||||
|
||||
List<TypeAnnotation> l = new ArrayList<>(tas.length);
|
||||
for (TypeAnnotation t : tas) {
|
||||
TypeAnnotationTargetInfo ti = t.getTargetInfo();
|
||||
@ -78,10 +76,10 @@ public final class TypeAnnotationParser {
|
||||
}
|
||||
TypeAnnotation[] typeAnnotations = l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY);
|
||||
return AnnotatedTypeFactory.buildAnnotatedType(type,
|
||||
LocationInfo.BASE_LOCATION,
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
AnnotatedTypeFactory.nestingForType(type, LocationInfo.BASE_LOCATION),
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -110,9 +108,8 @@ public final class TypeAnnotationParser {
|
||||
ArrayList[] l = new ArrayList[size]; // array of ArrayList<TypeAnnotation>
|
||||
|
||||
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
container);
|
||||
cp, decl, container);
|
||||
|
||||
for (TypeAnnotation t : tas) {
|
||||
TypeAnnotationTargetInfo ti = t.getTargetInfo();
|
||||
if (ti.getTarget() == filter) {
|
||||
@ -136,10 +133,10 @@ public final class TypeAnnotationParser {
|
||||
typeAnnotations = EMPTY_TYPE_ANNOTATION_ARRAY;
|
||||
}
|
||||
result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i],
|
||||
LocationInfo.BASE_LOCATION,
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
AnnotatedTypeFactory.nestingForType(types[i], LocationInfo.BASE_LOCATION),
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
|
||||
}
|
||||
return result;
|
||||
@ -278,7 +275,7 @@ public final class TypeAnnotationParser {
|
||||
}
|
||||
}
|
||||
res[i] = AnnotatedTypeFactory.buildAnnotatedType(bounds[i],
|
||||
loc,
|
||||
AnnotatedTypeFactory.nestingForType(bounds[i], loc),
|
||||
l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
|
||||
candidates.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
|
||||
(AnnotatedElement)decl);
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8004698 8007073 8022343 8054304 8058595
|
||||
* @bug 8004698 8007073 8022343 8054304 8057804 8058595
|
||||
* @summary Unit test for type annotations
|
||||
*/
|
||||
|
||||
@ -358,6 +358,31 @@ public class TypeAnnotationReflection {
|
||||
check(annos.length == 2);
|
||||
check(((TypeAnno)annos[0]).value().equals("I1"));
|
||||
check(args[0].getAnnotation(TypeAnno2.class).value().equals("I2"));
|
||||
|
||||
// check type args
|
||||
Field f = TestParameterizedType.class.getDeclaredField("theField");
|
||||
AnnotatedParameterizedType fType = (AnnotatedParameterizedType)f.getAnnotatedType();
|
||||
args = fType.getAnnotatedActualTypeArguments();
|
||||
check(args.length == 1);
|
||||
annos = args[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno2)annos[0]).value().equals("Map Arg"));
|
||||
check(args[0].getAnnotation(TypeAnno2.class).value().equals("Map Arg"));
|
||||
|
||||
// check outer type type args
|
||||
fType = (AnnotatedParameterizedType)fType.getAnnotatedOwnerType();
|
||||
args = fType.getAnnotatedActualTypeArguments();
|
||||
check(args.length == 1);
|
||||
annos = args[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno2)annos[0]).value().equals("String Arg"));
|
||||
check(args[0].getAnnotation(TypeAnno2.class).value().equals("String Arg"));
|
||||
|
||||
// check outer type normal type annotations
|
||||
annos = fType.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno)annos[0]).value().equals("FieldOuter"));
|
||||
check(fType.getAnnotation(TypeAnno.class).value().equals("FieldOuter"));
|
||||
}
|
||||
|
||||
private static void testWildcardType() throws Exception {
|
||||
@ -563,9 +588,12 @@ abstract class TestWildcardType {
|
||||
abstract class TestParameterizedType implements @TypeAnno("M") Map<@TypeAnno("S")String, @TypeAnno("I") @TypeAnno2("I2")Integer> {
|
||||
public ParameterizedOuter<String>.ParameterizedInner<Integer> foo() {return null;}
|
||||
public @TypeAnno("O") ParameterizedOuter<@TypeAnno("S1") @TypeAnno2("S2") String>.
|
||||
@TypeAnno("I") ParameterizedInner<@TypeAnno("I1") @TypeAnno2("I2")Integer> foo2() {
|
||||
@TypeAnno("I") ParameterizedInner<@TypeAnno("I1") @TypeAnno2("I2")Integer> foo2() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public @TypeAnno("FieldOuter") ParameterizedOuter<@TypeAnno2("String Arg") String>.
|
||||
@TypeAnno("FieldInner")ParameterizedInner<@TypeAnno2("Map Arg")Map> theField;
|
||||
}
|
||||
|
||||
class ParameterizedOuter <T> {
|
||||
|
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 8058595
|
||||
* @summary Test that AnnotatedType.getAnnotatedOwnerType() works as expected
|
||||
*
|
||||
* @library /lib/testlibrary
|
||||
* @build jdk.testlibrary.Asserts
|
||||
* @run main GetAnnotatedOwnerType
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import jdk.testlibrary.Asserts;
|
||||
|
||||
public class GetAnnotatedOwnerType<Dummy> {
|
||||
public @TA("generic") GetAnnotatedOwnerType<String> . @TB("generic") Nested<Integer> genericField;
|
||||
public @TA("raw") GetAnnotatedOwnerType . @TB("raw") Nested rawField;
|
||||
public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("non-generic") Inner nonGeneric;
|
||||
public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("generic") InnerGeneric<String> innerGeneric;
|
||||
public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("raw") InnerGeneric innerRaw;
|
||||
public Object anonymous = new Object() {};
|
||||
public @TA("array") Dummy[] dummy;
|
||||
public @TA("wildcard") GetAnnotatedOwnerType<?> wildcard;
|
||||
public @TA("typevariable") Dummy tv;
|
||||
public @TA("bad") GetAnnotatedOwnerType<@TA("good") GetAnnotatedOwnerType<String> . @TB("tb") Nested<Integer> > typeArgument;
|
||||
public GetAnnotatedOwnerType< GetAnnotatedOwnerType<String> .
|
||||
B .
|
||||
C<Class<?>, ? extends @TA("complicated") Exception> .
|
||||
D<Number> > [] complicated;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testGeneric();
|
||||
testRaw();
|
||||
testNonGeneric();
|
||||
testInnerGeneric();
|
||||
testInnerRaw();
|
||||
|
||||
testLocalClass();
|
||||
testAnonymousClass();
|
||||
|
||||
testArray();
|
||||
testWildcard();
|
||||
testTypeParameter();
|
||||
|
||||
testTypeArgument();
|
||||
testComplicated();
|
||||
}
|
||||
|
||||
public static void testGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("genericField");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testRaw() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("rawField");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "raw");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testNonGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("nonGeneric");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "non-generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testInnerGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("innerGeneric");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testInnerRaw() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("innerRaw");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testLocalClass() throws Exception {
|
||||
class ALocalClass {}
|
||||
class OneMore {
|
||||
public @TA("null") ALocalClass c;
|
||||
}
|
||||
testNegative(OneMore.class.getField("c").getAnnotatedType(), "Local class should return null");
|
||||
}
|
||||
|
||||
public static void testAnonymousClass() throws Exception {
|
||||
testNegative(GetAnnotatedOwnerType.class.getField("anonymous").getAnnotatedType(),
|
||||
"Anonymous class should return null");
|
||||
}
|
||||
|
||||
public static void testArray() throws Exception {
|
||||
AnnotatedType t = GetAnnotatedOwnerType.class.getField("dummy").getAnnotatedType();
|
||||
Asserts.assertTrue((t instanceof AnnotatedArrayType),
|
||||
"Was expecting an AnnotatedArrayType " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
}
|
||||
|
||||
public static void testWildcard() throws Exception {
|
||||
AnnotatedType tt = GetAnnotatedOwnerType.class.getField("wildcard").getAnnotatedType();
|
||||
AnnotatedType t = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
|
||||
Asserts.assertTrue((t instanceof AnnotatedWildcardType),
|
||||
"Was expecting an AnnotatedWildcardType " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
}
|
||||
|
||||
public static void testTypeParameter() throws Exception {
|
||||
AnnotatedType t = GetAnnotatedOwnerType.class.getField("tv").getAnnotatedType();
|
||||
Asserts.assertTrue((t instanceof AnnotatedTypeVariable),
|
||||
"Was expecting an AnnotatedTypeVariable " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
}
|
||||
|
||||
public static void testTypeArgument() throws Exception {
|
||||
AnnotatedType tt = GetAnnotatedOwnerType.class.getField("typeArgument").getAnnotatedType();
|
||||
Asserts.assertEquals(tt.getAnnotation(TA.class).value(), "bad");
|
||||
Asserts.assertTrue(tt.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ tt.getAnnotations().length);
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "tb");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "good");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testComplicated() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("complicated");
|
||||
|
||||
// Outermost level
|
||||
AnnotatedType t = f.getAnnotatedType();
|
||||
Asserts.assertTrue((t instanceof AnnotatedArrayType),
|
||||
"Was expecting an AnnotatedArrayType " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// Component type
|
||||
t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType();
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// Type arg GetAnnotatedOwnerType<String>...D<Number>
|
||||
t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[0];
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// C<Class<?>, ? extends ...>
|
||||
t = t.getAnnotatedOwnerType();
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// ? extends
|
||||
t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[1];
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// @TA("complicated") Exception
|
||||
t = ((AnnotatedWildcardType)t).getAnnotatedUpperBounds()[0];
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertEquals(t.getAnnotation(TA.class).value(), "complicated");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
}
|
||||
|
||||
private static void testNegative(AnnotatedType t, String msg) {
|
||||
Asserts.assertNull(t.getAnnotatedOwnerType(), msg);
|
||||
}
|
||||
|
||||
public class Nested<AlsoDummy> {}
|
||||
public class B {
|
||||
public class C<R, S> {
|
||||
public class D<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TA {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TB {
|
||||
String value();
|
||||
}
|
||||
}
|
||||
|
||||
class GetAnnotatedOwnerTypeAuxilliary {
|
||||
class Inner {}
|
||||
|
||||
class InnerGeneric<Dummy> {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user