8007072: Update Core Reflection for Type Annotations to match latest spec

8022324: j.l.Class.getAnnotatedInterfaces() for array type returns wrong value
8024915: j.l.r.Executable.getAnnotatedReceiverType() should return null for static methods

Update javadoc and implementation of reflection for type annotations to match latest spec

Reviewed-by: darcy
This commit is contained in:
Joel Borggrén-Franck 2013-09-30 11:18:18 +02:00
parent 8d63f86697
commit 279576cf17
12 changed files with 311 additions and 81 deletions

View File

@ -3414,16 +3414,20 @@ public final class Class<T> implements java.io.Serializable,
transient ClassValue.ClassValueMap classValueMap;
/**
* Returns an AnnotatedType object that represents the use of a type to specify
* the superclass of the entity represented by this Class. (The <em>use</em> of type
* Foo to specify the superclass in '... extends Foo' is distinct from the
* <em>declaration</em> of type Foo.)
* Returns an {@code AnnotatedType} object that represents the use of a
* type to specify the superclass of the entity represented by this {@code
* Class} object. (The <em>use</em> of type Foo to specify the superclass
* in '... extends Foo' is distinct from the <em>declaration</em> of type
* Foo.)
*
* If this Class represents a class type whose declaration does not explicitly
* indicate an annotated superclass, the return value is null.
* <p> If this {@code Class} object represents a type whose declaration
* does not explicitly indicate an annotated superclass, then the return
* value is an {@code AnnotatedType} object representing an element with no
* annotations.
*
* If this Class represents either the Object class, an interface type, an
* array type, a primitive type, or void, the return value is null.
* <p> If this {@code Class} represents either the {@code Object} class, an
* interface type, an array type, a primitive type, or void, the return
* value is {@code null}.
*
* @return an object representing the superclass
* @since 1.8
@ -3441,30 +3445,33 @@ public final class Class<T> implements java.io.Serializable,
}
/**
* Returns an array of AnnotatedType objects that represent the use of types to
* specify superinterfaces of the entity represented by this Class. (The <em>use</em>
* of type Foo to specify a superinterface in '... implements Foo' is
* distinct from the <em>declaration</em> of type Foo.)
* Returns an array of {@code AnnotatedType} objects that represent the use
* of types to specify superinterfaces of the entity represented by this
* {@code Class} object. (The <em>use</em> of type Foo to specify a
* superinterface in '... implements Foo' is distinct from the
* <em>declaration</em> of type Foo.)
*
* If this Class represents a class, the return value is an array
* containing objects representing the uses of interface types to specify
* interfaces implemented by the class. The order of the objects in the
* array corresponds to the order of the interface types used in the
* 'implements' clause of the declaration of this Class.
*
* If this Class represents an interface, the return value is an array
* containing objects representing the uses of interface types to specify
* interfaces directly extended by the interface. The order of the objects in
* <p> If this {@code Class} object represents a class, the return value is
* an array containing objects representing the uses of interface types to
* specify interfaces implemented by the class. The order of the objects in
* the array corresponds to the order of the interface types used in the
* 'extends' clause of the declaration of this Class.
* 'implements' clause of the declaration of this {@code Class} object.
*
* If this Class represents a class or interface whose declaration does not
* explicitly indicate any annotated superinterfaces, the return value is an
* <p> If this {@code Class} object represents an interface, the return
* value is an array containing objects representing the uses of interface
* types to specify interfaces directly extended by the interface. The
* order of the objects in the array corresponds to the order of the
* interface types used in the 'extends' clause of the declaration of this
* {@code Class} object.
*
* <p> If this {@code Class} object represents a class or interface whose
* declaration does not explicitly indicate any annotated superinterfaces,
* the return value is an array of length 0.
*
* <p> If this {@code Class} object represents either the {@code Object}
* class, an array type, a primitive type, or void, the return value is an
* array of length 0.
*
* If this Class represents either the Object class, an array type, a
* primitive type, or void, the return value is an array of length 0.
*
* @return an array representing the superinterfaces
* @since 1.8
*/

View File

@ -27,17 +27,18 @@ package java.lang.reflect;
/**
* AnnotatedArrayType represents the use of an array type, whose component
* type may itself represent the annotated use of a type.
* {@code AnnotatedArrayType} represents the potentially annotated use of an
* array type, whose component type may itself represent the annotated use of a
* type.
*
* @since 1.8
*/
public interface AnnotatedArrayType extends AnnotatedType {
/**
* Returns the annotated generic component type of this array type.
* Returns the potentially annotated generic component type of this array type.
*
* @return the annotated generic component type of this array type
* @return the potentially annotated generic component type of this array type
*/
AnnotatedType getAnnotatedGenericComponentType();
}

View File

@ -26,17 +26,18 @@
package java.lang.reflect;
/**
* AnnotatedParameterizedType represents the use of a parameterized type,
* whose type arguments may themselves represent annotated uses of types.
* {@code AnnotatedParameterizedType} represents the potentially annotated use
* of a parameterized type, whose type arguments may themselves represent
* annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedParameterizedType extends AnnotatedType {
/**
* Returns the annotated actual type arguments of this parameterized type.
* Returns the potentially annotated actual type arguments of this parameterized type.
*
* @return the annotated actual type arguments of this parameterized type
* @return the potentially annotated actual type arguments of this parameterized type
*/
AnnotatedType[] getAnnotatedActualTypeArguments();
}

View File

@ -26,10 +26,10 @@
package java.lang.reflect;
/**
* AnnotatedType represents the annotated use of a type in the program
* currently running in this VM. The use may be of any type in the Java
* programming language, including an array type, a parameterized type, a type
* variable, or a wildcard type.
* {@code AnnotatedType} represents the potentially annotated use of a type in
* the program currently running in this VM. The use may be of any type in the
* Java programming language, including an array type, a parameterized type, a
* type variable, or a wildcard type.
*
* @since 1.8
*/

View File

@ -26,18 +26,18 @@
package java.lang.reflect;
/**
* AnnotatedTypeVariable represents the use of a type variable, whose
* declaration may have bounds which themselves represent annotated uses of
* types.
* {@code AnnotatedTypeVariable} represents the potentially annotated use of a
* type variable, whose declaration may have bounds which themselves represent
* annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedTypeVariable extends AnnotatedType {
/**
* Returns the annotated bounds of this type variable.
* Returns the potentially annotated bounds of this type variable.
*
* @return the annotated bounds of this type variable
* @return the potentially annotated bounds of this type variable
*/
AnnotatedType[] getAnnotatedBounds();
}

View File

@ -26,24 +26,25 @@
package java.lang.reflect;
/**
* AnnotatedWildcardType represents the use of a wildcard type argument, whose
* upper or lower bounds may themselves represent annotated uses of types.
* {@code AnnotatedWildcardType} represents the potentially annotated use of a
* wildcard type argument, whose upper or lower bounds may themselves represent
* annotated uses of types.
*
* @since 1.8
*/
public interface AnnotatedWildcardType extends AnnotatedType {
/**
* Returns the annotated lower bounds of this wildcard type.
* Returns the potentially annotated lower bounds of this wildcard type.
*
* @return the annotated lower bounds of this wildcard type
* @return the potentially annotated lower bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedLowerBounds();
/**
* Returns the annotated upper bounds of this wildcard type.
* Returns the potentially annotated upper bounds of this wildcard type.
*
* @return the annotated upper bounds of this wildcard type
* @return the potentially annotated upper bounds of this wildcard type
*/
AnnotatedType[] getAnnotatedUpperBounds();
}

View File

@ -514,18 +514,20 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an AnnotatedType object that represents the use of a type to
* Returns an {@code AnnotatedType} object that represents the use of a type to
* specify the return type of the method/constructor represented by this
* Executable.
*
* If this Executable represents a constructor, the AnnotatedType object
* represents the type of the constructed object.
* If this {@code Executable} object represents a constructor, the {@code
* AnnotatedType} object represents the type of the constructed object.
*
* If this Executable represents a method, the AnnotatedType object
* represents the use of a type to specify the return type of the method.
* If this {@code Executable} object represents a method, the {@code
* AnnotatedType} object represents the use of a type to specify the return
* type of the method.
*
* @return an object representing the return type of the method
* or constructor represented by this {@code Executable}
*
* @return an object representing the return type of this method
* or constructor
* @since 1.8
*/
public abstract AnnotatedType getAnnotatedReturnType();
@ -549,24 +551,29 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an AnnotatedType object that represents the use of a type to
* specify the receiver type of the method/constructor represented by this
* Executable. The receiver type of a method/constructor is available only
* if the method/constructor declares a formal parameter called 'this'.
* Returns an {@code AnnotatedType} object that represents the use of a
* type to specify the receiver type of the method/constructor represented
* by this Executable object. The receiver type of a method/constructor is
* available only if the method/constructor has a <em>receiver
* parameter</em> (JLS 8.4.1).
*
* Returns null if this Executable represents a constructor or instance
* method that either declares no formal parameter called 'this', or
* declares a formal parameter called 'this' with no annotations on its
* type.
* If this {@code Executable} object represents a constructor or instance
* method that does not have a receiver parameter, or has a receiver
* parameter with no annotations on its type, then the return value is an
* {@code AnnotatedType} object representing an element with no
* annotations.
*
* Returns null if this Executable represents a static method.
* If this {@code Executable} object represents a static method, then the
* return value is null.
*
* @return an object representing the receiver type of the
* method or constructor represented by this Executable
* @return an object representing the receiver type of the method or
* constructor represented by this {@code Executable}
*
* @since 1.8
*/
public AnnotatedType getAnnotatedReceiverType() {
if (Modifier.isStatic(this.getModifiers()))
return null;
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
sun.misc.SharedSecrets.getJavaLangAccess().
getConstantPool(getDeclaringClass()),
@ -577,8 +584,8 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an array of AnnotatedType objects that represent the use of
* types to specify formal parameter types of the method/constructor
* Returns an array of {@code AnnotatedType} objects that represent the use
* of types to specify formal parameter types of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the formal parameter types in the
* declaration of the method/constructor.
@ -587,7 +594,8 @@ public abstract class Executable extends AccessibleObject
* parameters.
*
* @return an array of objects representing the types of the
* formal parameters of this method or constructor
* formal parameters of the method or constructor represented by this
* {@code Executable}
*
* @since 1.8
*/
@ -602,8 +610,8 @@ public abstract class Executable extends AccessibleObject
}
/**
* Returns an array of AnnotatedType objects that represent the use of
* types to specify the declared exceptions of the method/constructor
* Returns an array of {@code AnnotatedType} objects that represent the use
* of types to specify the declared exceptions of the method/constructor
* represented by this Executable. The order of the objects in the array
* corresponds to the order of the exception types in the declaration of
* the method/constructor.
@ -612,7 +620,8 @@ public abstract class Executable extends AccessibleObject
* exceptions.
*
* @return an array of objects representing the declared
* exceptions of this method or constructor
* exceptions of the method or constructor represented by this {@code
* Executable}
*
* @since 1.8
*/

View File

@ -118,6 +118,7 @@ public class AnnotatedTypeFactory {
static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
new TypeAnnotation[0], new TypeAnnotation[0], null);
static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
private static class AnnotatedTypeBaseImpl implements AnnotatedType {
private final Type type;

View File

@ -174,6 +174,11 @@ public class TypeAnnotationParser {
public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations,
ConstantPool cp,
Class<?> decl) {
if (decl == Object.class ||
decl.isArray() ||
decl.isPrimitive() ||
decl == Void.TYPE)
return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE_ARRAY;
return buildAnnotatedTypes(rawAnnotations,
cp,
decl,

View File

@ -0,0 +1,80 @@
/*
* 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 8022324
* @summary Test Class.getAnnotatedInterfaces() returns 0-length array as
* specified.
*/
import java.lang.reflect.AnnotatedType;
import java.util.Arrays;
public class GetAnnotatedInterfaces {
private static final Class<?>[] testData = {
GetAnnotatedInterfaces.class,
(new Clz() {}).getClass(),
(new Object() {}).getClass(),
Object[].class,
Object[][].class,
Object[][][].class,
Object.class,
void.class,
int.class,
};
private static int failed = 0;
private static int tests = 0;
public static void main(String[] args) throws Exception {
testReturnsZeroLengthArray();
if (failed != 0)
throw new RuntimeException("Test failed, check log for details");
if (tests != 9)
throw new RuntimeException("Not all cases ran, failing");
}
private static void testReturnsZeroLengthArray() {
for (Class<?> toTest : testData) {
tests++;
AnnotatedType[] res = toTest.getAnnotatedInterfaces();
if (res == null) {
failed++;
System.out.println(toTest + ".class.getAnnotatedInterface() returns" +
"'null' should zero length array");
} else if (res.length != 0) {
failed++;
System.out.println(toTest + ".class.getAnnotatedInterfaces() returns: "
+ Arrays.asList(res) + ", should be a zero length array of AnnotatedType");
}
}
}
interface If {}
static abstract class Clz {}
}

View File

@ -0,0 +1,83 @@
/*
* 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 8024915
*/
import java.lang.reflect.AnnotatedType;
import java.util.Arrays;
public class GetAnnotatedReceiverType {
public void method() {}
public void method0(GetAnnotatedReceiverType this) {}
public static void method4() {}
class Inner0 {
public Inner0() {}
}
class Inner1 {
public Inner1(GetAnnotatedReceiverType GetAnnotatedReceiverType.this) {}
}
private static int failures = 0;
private static int tests = 0;
public static void main(String[] args) throws NoSuchMethodException {
checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method").getAnnotatedReceiverType(),
"getAnnotatedReceiverType for \"method\" should return an empty AnnotatedType");
checkEmptyAT(Inner0.class.getConstructor(GetAnnotatedReceiverType.class).getAnnotatedReceiverType(),
"getAnnotatedReceiverType for a ctor without a \"this\" should return an empty AnnotatedType");
checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method0").getAnnotatedReceiverType(),
"getAnnotatedReceiverType for \"method0\" should return an empty AnnotatedType");
checkEmptyAT(Inner1.class.getConstructor(GetAnnotatedReceiverType.class).getAnnotatedReceiverType(),
"getAnnotatedReceiverType for a ctor with a \"this\" should return an empty AnnotatedType");
checkNull(GetAnnotatedReceiverType.class.getMethod("method4").getAnnotatedReceiverType(),
"getAnnotatedReceiverType() on a static method should return null");
if (failures != 0)
throw new RuntimeException("Test failed, see log for details");
else if (tests != 5)
throw new RuntimeException("Not all cases ran, failing");
}
private static void checkNull(Object o, String msg) {
if (o != null) {
failures++;
System.err.println(msg);
}
tests++;
}
private static void checkEmptyAT(AnnotatedType a, String msg) {
if (a.getAnnotations().length != 0) {
failures++;
System.err.print(msg);
}
tests++;
}
}

View File

@ -23,12 +23,16 @@
/*
* @test
* @bug 8022343
* @summary make sure Class.getAnnotatedSuperclass() returns null when specified to do so
* @bug 8022343 8007072
* @summary Test Class.getAnnotatedSuperclass() returns null/non-null
* AnnotatedType as specified
*/
import java.lang.reflect.AnnotatedType;
import java.util.Arrays;
public class GetAnnotatedSuperclass {
private static final Class<?>[] testData = {
private static final Class<?>[] nullTestData = {
Object.class,
If.class,
Object[].class,
@ -36,9 +40,31 @@ public class GetAnnotatedSuperclass {
int.class,
};
private static final Class<?>[] nonNullTestData = {
Class.class,
GetAnnotatedSuperclass.class,
(new If() {}).getClass(),
(new Clz() {}).getClass(),
(new Object() {}).getClass(),
};
private static int failed = 0;
private static int tests = 0;
public static void main(String[] args) throws Exception {
int failed = 0;
for (Class<?> toTest : testData) {
testReturnsNull();
testReturnsEmptyAT();
if (failed != 0)
throw new RuntimeException("Test failed, check log for details");
if (tests != 10)
throw new RuntimeException("Not all cases ran, failing");
}
private static void testReturnsNull() {
for (Class<?> toTest : nullTestData) {
tests++;
Object res = toTest.getAnnotatedSuperclass();
if (res != null) {
@ -47,10 +73,26 @@ public class GetAnnotatedSuperclass {
+ res + ", should be null");
}
}
}
if (failed != 0)
throw new RuntimeException("Test failed, check log for details");
private static void testReturnsEmptyAT() {
for (Class<?> toTest : nonNullTestData) {
tests++;
AnnotatedType res = toTest.getAnnotatedSuperclass();
if (res == null) {
failed++;
System.out.println(toTest + ".getAnnotatedSuperclass() returns 'null' should be non-null");
} else if (res.getAnnotations().length != 0) {
failed++;
System.out.println(toTest + ".getAnnotatedSuperclass() returns: "
+ Arrays.asList(res.getAnnotations()) + ", should be an empty AnnotatedType");
}
}
}
interface If {}
static abstract class Clz {}
}