8004698: Implement Core Reflection for Type Annotations
Reviewed-by: darcy
This commit is contained in:
parent
c2419823c8
commit
b29b479461
jdk
src/share
test/java/lang/annotation
@ -29,12 +29,14 @@ import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.Member;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectStreamField;
|
||||
@ -2325,6 +2327,11 @@ public final
|
||||
|
||||
// Annotations handling
|
||||
private native byte[] getRawAnnotations();
|
||||
// Since 1.8
|
||||
native byte[] getRawTypeAnnotations();
|
||||
static byte[] getExecutableTypeAnnotationBytes(Executable ex) {
|
||||
return getReflectionFactory().getExecutableTypeAnnotationBytes(ex);
|
||||
}
|
||||
|
||||
native ConstantPool getConstantPool();
|
||||
|
||||
@ -3196,4 +3203,53 @@ public final
|
||||
* Maintained by the ClassValue class.
|
||||
*/
|
||||
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.)
|
||||
*
|
||||
* If this Class represents a class type whose declaration does not explicitly
|
||||
* indicate an annotated superclass, the return value is null.
|
||||
*
|
||||
* If this Class represents either the Object class, an interface type, an
|
||||
* array type, a primitive type, or void, the return value is null.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType getAnnotatedSuperclass() {
|
||||
return TypeAnnotationParser.buildAnnotatedSuperclass(getRawTypeAnnotations(), getConstantPool(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.)
|
||||
*
|
||||
* 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
|
||||
* the array corresponds to the order of the interface types used in the
|
||||
* 'extends' clause of the declaration of this Class.
|
||||
*
|
||||
* If this Class represents a class or interface whose declaration does not
|
||||
* explicitly indicate any annotated superinterfaces, 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.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType[] getAnnotatedInterfaces() {
|
||||
return TypeAnnotationParser.buildAnnotatedInterfaces(getRawTypeAnnotations(), getConstantPool(), this);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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
|
||||
@ -26,6 +26,7 @@ package java.lang;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.util.Properties;
|
||||
import java.util.PropertyPermission;
|
||||
import java.util.StringTokenizer;
|
||||
@ -1199,6 +1200,12 @@ public final class System {
|
||||
public <A extends Annotation> A getDirectDeclaredAnnotation(Class<?> klass, Class<A> anno) {
|
||||
return klass.getDirectDeclaredAnnotation(anno);
|
||||
}
|
||||
public byte[] getRawClassTypeAnnotations(Class<?> klass) {
|
||||
return klass.getRawTypeAnnotations();
|
||||
}
|
||||
public byte[] getRawExecutableTypeAnnotations(Executable executable) {
|
||||
return Class.getExecutableTypeAnnotationBytes(executable);
|
||||
}
|
||||
public <E extends Enum<E>>
|
||||
E[] getEnumConstantsShared(Class<E> klass) {
|
||||
return klass.getEnumConstantsShared();
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
|
||||
/**
|
||||
* AnnotatedArrayType represents the 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.
|
||||
*
|
||||
* @return the annotated generic component type of this array type
|
||||
*/
|
||||
AnnotatedType getAnnotatedGenericComponentType();
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
/**
|
||||
* AnnotatedParameterizedType represents the 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.
|
||||
*
|
||||
* @return the annotated actual type arguments of this parameterized type
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedActualTypeArguments();
|
||||
}
|
44
jdk/src/share/classes/java/lang/reflect/AnnotatedType.java
Normal file
44
jdk/src/share/classes/java/lang/reflect/AnnotatedType.java
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface AnnotatedType extends AnnotatedElement {
|
||||
|
||||
/**
|
||||
* Returns the underlying type that this annotated type represents.
|
||||
*
|
||||
* @return the type this annotated type represents
|
||||
*/
|
||||
public Type getType();
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package java.lang.reflect;
|
||||
|
||||
/**
|
||||
* AnnotatedTypeVariable represents the 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.
|
||||
*
|
||||
* @return the annotated bounds of this type variable
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedBounds();
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
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.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public interface AnnotatedWildcardType extends AnnotatedType {
|
||||
|
||||
/**
|
||||
* Returns the annotated lower bounds of this wildcard type.
|
||||
*
|
||||
* @return the annotated lower bounds of this wildcard type
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedLowerBounds();
|
||||
|
||||
/**
|
||||
* Returns the annotated upper bounds of this wildcard type.
|
||||
*
|
||||
* @return the annotated upper bounds of this wildcard type
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedUpperBounds();
|
||||
}
|
@ -154,6 +154,10 @@ public final class Constructor<T> extends Executable {
|
||||
byte[] getAnnotationBytes() {
|
||||
return annotations;
|
||||
}
|
||||
@Override
|
||||
byte[] getTypeAnnotationBytes() {
|
||||
return typeAnnotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -523,4 +527,12 @@ public final class Constructor<T> extends Executable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType getAnnotatedReturnType() {
|
||||
return getAnnotatedReturnType0(getDeclaringClass());
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 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
|
||||
@ -31,6 +31,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import sun.reflect.annotation.AnnotationParser;
|
||||
import sun.reflect.annotation.AnnotationSupport;
|
||||
import sun.reflect.annotation.TypeAnnotationParser;
|
||||
import sun.reflect.annotation.TypeAnnotation;
|
||||
import sun.reflect.generics.repository.ConstructorRepository;
|
||||
|
||||
/**
|
||||
@ -50,6 +52,7 @@ public abstract class Executable extends AccessibleObject
|
||||
* Accessor method to allow code sharing
|
||||
*/
|
||||
abstract byte[] getAnnotationBytes();
|
||||
abstract byte[] getTypeAnnotationBytes();
|
||||
|
||||
/**
|
||||
* Does the Executable have generic information.
|
||||
@ -470,4 +473,86 @@ public abstract class Executable extends AccessibleObject
|
||||
return declaredAnnotations;
|
||||
}
|
||||
|
||||
|
||||
/* Helper for subclasses of Executable.
|
||||
*
|
||||
* Returns an AnnotatedType object that represents the use of a type to
|
||||
* specify the return type of the method/constructor represented by this
|
||||
* Executable.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
AnnotatedType getAnnotatedReturnType0(Type returnType) {
|
||||
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
|
||||
sun.misc.SharedSecrets.getJavaLangAccess().
|
||||
getConstantPool(getDeclaringClass()),
|
||||
this,
|
||||
getDeclaringClass(),
|
||||
returnType,
|
||||
TypeAnnotation.TypeAnnotationTarget.METHOD_RETURN_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
*
|
||||
* Returns null if this Executable represents a static method.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType getAnnotatedReceiverType() {
|
||||
return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes(),
|
||||
sun.misc.SharedSecrets.getJavaLangAccess().
|
||||
getConstantPool(getDeclaringClass()),
|
||||
this,
|
||||
getDeclaringClass(),
|
||||
getDeclaringClass(),
|
||||
TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of 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.
|
||||
*
|
||||
* Returns an array of length 0 if the method/constructor declares no
|
||||
* parameters.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType[] getAnnotatedParameterTypes() {
|
||||
throw new UnsupportedOperationException("Not yet");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of 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.
|
||||
*
|
||||
* Returns an array of length 0 if the method/constructor declares no
|
||||
* exceptions.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType[] getAnnotatedExceptionTypes() {
|
||||
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes(),
|
||||
sun.misc.SharedSecrets.getJavaLangAccess().
|
||||
getConstantPool(getDeclaringClass()),
|
||||
this,
|
||||
getDeclaringClass(),
|
||||
getGenericExceptionTypes(),
|
||||
TypeAnnotation.TypeAnnotationTarget.THROWS);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 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
|
||||
@ -36,7 +36,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import sun.reflect.annotation.AnnotationParser;
|
||||
import sun.reflect.annotation.AnnotationSupport;
|
||||
|
||||
import sun.reflect.annotation.TypeAnnotation;
|
||||
import sun.reflect.annotation.TypeAnnotationParser;
|
||||
|
||||
/**
|
||||
* A {@code Field} provides information about, and dynamic access to, a
|
||||
@ -1053,4 +1054,20 @@ class Field extends AccessibleObject implements Member {
|
||||
}
|
||||
return declaredAnnotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an AnnotatedType object that represents the use of a type to specify
|
||||
* the declared type of the field represented by this Field.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType getAnnotatedType() {
|
||||
return TypeAnnotationParser.buildAnnotatedType(typeAnnotations,
|
||||
sun.misc.SharedSecrets.getJavaLangAccess().
|
||||
getConstantPool(getDeclaringClass()),
|
||||
this,
|
||||
getDeclaringClass(),
|
||||
getGenericType(),
|
||||
TypeAnnotation.TypeAnnotationTarget.FIELD_TYPE);
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,10 @@ public final class Method extends Executable {
|
||||
byte[] getAnnotationBytes() {
|
||||
return annotations;
|
||||
}
|
||||
@Override
|
||||
byte[] getTypeAnnotationBytes() {
|
||||
return typeAnnotations;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@ -621,6 +625,14 @@ public final class Method extends Executable {
|
||||
return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @since 1.8
|
||||
*/
|
||||
public AnnotatedType getAnnotatedReturnType() {
|
||||
return getAnnotatedReturnType0(getGenericReturnType());
|
||||
}
|
||||
|
||||
@Override
|
||||
void handleParameterNumberMismatch(int resultLength, int numParameters) {
|
||||
throw new AnnotationFormatError("Parameter annotations don't match number of parameters");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -128,6 +128,10 @@ class ReflectAccess implements sun.reflect.LangReflectAccess {
|
||||
return c.getRawParameterAnnotations();
|
||||
}
|
||||
|
||||
public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
|
||||
return ex.getTypeAnnotationBytes();
|
||||
}
|
||||
|
||||
//
|
||||
// Copying routines, needed to quickly fabricate new Field,
|
||||
// Method, and Constructor objects from templates
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -86,4 +86,16 @@ public interface TypeVariable<D extends GenericDeclaration> extends Type, Annota
|
||||
* @return the name of this type variable, as it appears in the source code
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns an array of AnnotatedType objects that represent the use of
|
||||
* types to denote the upper bounds of the type parameter represented by
|
||||
* this TypeVariable. The order of the objects in the array corresponds to
|
||||
* the order of the bounds in the declaration of the type parameter.
|
||||
*
|
||||
* Returns an array of length 0 if the type parameter declares no bounds.
|
||||
*
|
||||
* @since 1.8
|
||||
*/
|
||||
AnnotatedType[] getAnnotatedBounds();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -26,6 +26,7 @@
|
||||
package sun.misc;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Executable;
|
||||
import sun.reflect.ConstantPool;
|
||||
import sun.reflect.annotation.AnnotationType;
|
||||
import sun.nio.ch.Interruptible;
|
||||
@ -46,6 +47,18 @@ public interface JavaLangAccess {
|
||||
*/
|
||||
AnnotationType getAnnotationType(Class<?> klass);
|
||||
|
||||
/**
|
||||
* Get the array of bytes that is the class-file representation
|
||||
* of this Class' type annotations.
|
||||
*/
|
||||
byte[] getRawClassTypeAnnotations(Class<?> klass);
|
||||
|
||||
/**
|
||||
* Get the array of bytes that is the class-file representation
|
||||
* of this Executable's type annotations.
|
||||
*/
|
||||
byte[] getRawExecutableTypeAnnotations(Executable executable);
|
||||
|
||||
/**
|
||||
* Returns the elements of an enum class or null if the
|
||||
* Class object does not represent an enum type;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -81,6 +81,9 @@ public interface LangReflectAccess {
|
||||
public void setConstructorAccessor(Constructor<?> c,
|
||||
ConstructorAccessor accessor);
|
||||
|
||||
/** Gets the byte[] that encodes TypeAnnotations on an Executable. */
|
||||
public byte[] getExecutableTypeAnnotationBytes(Executable ex);
|
||||
|
||||
/** Gets the "slot" field from a Constructor (used for serialization) */
|
||||
public int getConstructorSlot(Constructor<?> c);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -26,6 +26,7 @@
|
||||
package sun.reflect;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
@ -314,6 +315,12 @@ public class ReflectionFactory {
|
||||
return langReflectAccess().copyConstructor(arg);
|
||||
}
|
||||
|
||||
/** Gets the byte[] that encodes TypeAnnotations on an executable.
|
||||
*/
|
||||
public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
|
||||
return langReflectAccess().getExecutableTypeAnnotationBytes(ex);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
//
|
||||
// Routines used by serialization
|
||||
|
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sun.reflect.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static sun.reflect.annotation.TypeAnnotation.*;
|
||||
|
||||
public class AnnotatedTypeFactory {
|
||||
/**
|
||||
* Create an AnnotatedType.
|
||||
*
|
||||
* @param type the type this AnnotatedType corresponds to
|
||||
* @param currentLoc the location this AnnotatedType corresponds to
|
||||
* @param actualTypeAnnos the type annotations this AnnotatedType has
|
||||
* @param allOnSameTarget all type annotation on the same TypeAnnotationTarget
|
||||
* as the AnnotatedType being built
|
||||
* @param decl the declaration having the type use this AnnotatedType
|
||||
* corresponds to
|
||||
*/
|
||||
public static AnnotatedType buildAnnotatedType(Type type,
|
||||
LocationInfo currentLoc,
|
||||
TypeAnnotation[] actualTypeAnnos,
|
||||
TypeAnnotation[] allOnSameTarget,
|
||||
AnnotatedElement decl) {
|
||||
if (type == null) {
|
||||
return EMPTY_ANNOTATED_TYPE;
|
||||
}
|
||||
if (isArray(type))
|
||||
return new AnnotatedArrayTypeImpl(type,
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
if (type instanceof Class) {
|
||||
return new AnnotatedTypeBaseImpl(type,
|
||||
addNesting(type, currentLoc),
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
} else if (type instanceof TypeVariable) {
|
||||
return new AnnotatedTypeVariableImpl((TypeVariable)type,
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
} else if (type instanceof ParameterizedType) {
|
||||
return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
|
||||
addNesting(type, currentLoc),
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
} else if (type instanceof WildcardType) {
|
||||
return new AnnotatedWildcardTypeImpl((WildcardType) type,
|
||||
currentLoc,
|
||||
actualTypeAnnos,
|
||||
allOnSameTarget,
|
||||
decl);
|
||||
}
|
||||
throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen.");
|
||||
}
|
||||
|
||||
private static LocationInfo addNesting(Type type, LocationInfo addTo) {
|
||||
if (isArray(type))
|
||||
return addTo;
|
||||
if (type instanceof Class) {
|
||||
Class<?> clz = (Class)type;
|
||||
if (clz.getEnclosingClass() == null)
|
||||
return addTo;
|
||||
return addNesting(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 addTo;
|
||||
}
|
||||
|
||||
private static boolean isArray(Type t) {
|
||||
if (t instanceof Class) {
|
||||
Class<?> c = (Class)t;
|
||||
if (c.isArray())
|
||||
return true;
|
||||
} else if (t instanceof GenericArrayType) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
|
||||
new TypeAnnotation[0], new TypeAnnotation[0], null);
|
||||
|
||||
private static class AnnotatedTypeBaseImpl implements AnnotatedType {
|
||||
private final Type type;
|
||||
private final AnnotatedElement decl;
|
||||
private final LocationInfo location;
|
||||
private final TypeAnnotation[] allOnSameTargetTypeAnnotations;
|
||||
private final Map<Class <? extends Annotation>, Annotation> annotations;
|
||||
|
||||
AnnotatedTypeBaseImpl(Type type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
this.type = type;
|
||||
this.decl = decl;
|
||||
this.location = location;
|
||||
this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations;
|
||||
this.annotations = TypeAnnotationParser.mapTypeAnnotations(location.filter(actualTypeAnnotations));
|
||||
}
|
||||
|
||||
// AnnotatedElement
|
||||
@Override
|
||||
public final boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
|
||||
return annotations.get(annotation) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Annotation[] getAnnotations() {
|
||||
return getDeclaredAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T extends Annotation> T getAnnotation(Class<T> annotation) {
|
||||
return getDeclaredAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final <T extends Annotation> T[] getAnnotations(Class<T> annotation) {
|
||||
return getDeclaredAnnotations(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
return annotations.values().toArray(new Annotation[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
|
||||
return (T)annotations.get(annotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotation) {
|
||||
return AnnotationSupport.getMultipleAnnotations(annotations, annotation);
|
||||
}
|
||||
|
||||
// AnnotatedType
|
||||
@Override
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
// Implementation details
|
||||
LocationInfo getLocation() {
|
||||
return location;
|
||||
}
|
||||
TypeAnnotation[] getTypeAnnotations() {
|
||||
return allOnSameTargetTypeAnnotations;
|
||||
}
|
||||
AnnotatedElement getDecl() {
|
||||
return decl;
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
|
||||
AnnotatedArrayTypeImpl(Type type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType getAnnotatedGenericComponentType() {
|
||||
return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(),
|
||||
getLocation().pushArray(),
|
||||
getTypeAnnotations(),
|
||||
getTypeAnnotations(),
|
||||
getDecl());
|
||||
}
|
||||
|
||||
private Type getComponentType() {
|
||||
Type t = getType();
|
||||
if (t instanceof Class) {
|
||||
Class<?> c = (Class)t;
|
||||
return c.getComponentType();
|
||||
}
|
||||
return ((GenericArrayType)t).getGenericComponentType();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
|
||||
AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedBounds() {
|
||||
return getTypeVariable().getAnnotatedBounds();
|
||||
}
|
||||
|
||||
private TypeVariable<?> getTypeVariable() {
|
||||
return (TypeVariable)getType();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedParameterizedType {
|
||||
AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedActualTypeArguments() {
|
||||
Type[] arguments = getParameterizedType().getActualTypeArguments();
|
||||
AnnotatedType[] res = new AnnotatedType[arguments.length];
|
||||
Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
|
||||
int initialCapacity = getTypeAnnotations().length;
|
||||
for (int i = 0; i < res.length; i++) {
|
||||
List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
|
||||
LocationInfo newLoc = 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());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private ParameterizedType getParameterizedType() {
|
||||
return (ParameterizedType)getType();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
|
||||
private final boolean hasUpperBounds;
|
||||
AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
|
||||
TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
|
||||
AnnotatedElement decl) {
|
||||
super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
|
||||
hasUpperBounds = (type.getLowerBounds().length == 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedUpperBounds() {
|
||||
if (!hasUpperBounds())
|
||||
return new AnnotatedType[0];
|
||||
return getAnnotatedBounds(getWildcardType().getUpperBounds());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotatedType[] getAnnotatedLowerBounds() {
|
||||
if (hasUpperBounds)
|
||||
return new AnnotatedType[0];
|
||||
return getAnnotatedBounds(getWildcardType().getLowerBounds());
|
||||
}
|
||||
|
||||
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++) {
|
||||
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());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private WildcardType getWildcardType() {
|
||||
return (WildcardType)getType();
|
||||
}
|
||||
|
||||
private boolean hasUpperBounds() {
|
||||
return hasUpperBounds;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -188,7 +188,7 @@ public class AnnotationParser {
|
||||
* available at runtime
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Annotation parseAnnotation(ByteBuffer buf,
|
||||
static Annotation parseAnnotation(ByteBuffer buf,
|
||||
ConstantPool constPool,
|
||||
Class<?> container,
|
||||
boolean exceptionOnMissingAnnotationClass) {
|
||||
|
227
jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java
Normal file
227
jdk/src/share/classes/sun/reflect/annotation/TypeAnnotation.java
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
package sun.reflect.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.AnnotationFormatError;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A TypeAnnotation contains all the information needed to transform type
|
||||
* annotations on declarations in the class file to actual Annotations in
|
||||
* AnnotatedType instances.
|
||||
*
|
||||
* TypeAnnotaions contain a base Annotation, location info (which lets you
|
||||
* distinguish between '@A Inner.@B Outer' in for example nested types),
|
||||
* target info and the declaration the TypeAnnotaiton was parsed from.
|
||||
*/
|
||||
public class TypeAnnotation {
|
||||
private final TypeAnnotationTargetInfo targetInfo;
|
||||
private final LocationInfo loc;
|
||||
private final Annotation annotation;
|
||||
private final AnnotatedElement baseDeclaration;
|
||||
|
||||
public TypeAnnotation(TypeAnnotationTargetInfo targetInfo,
|
||||
LocationInfo loc,
|
||||
Annotation annotation,
|
||||
AnnotatedElement baseDeclaration) {
|
||||
this.targetInfo = targetInfo;
|
||||
this.loc = loc;
|
||||
this.annotation = annotation;
|
||||
this.baseDeclaration = baseDeclaration;
|
||||
}
|
||||
|
||||
public TypeAnnotationTargetInfo getTargetInfo() {
|
||||
return targetInfo;
|
||||
}
|
||||
public Annotation getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
public AnnotatedElement getBaseDeclaration() {
|
||||
return baseDeclaration;
|
||||
}
|
||||
public LocationInfo getLocationInfo() {
|
||||
return loc;
|
||||
}
|
||||
|
||||
public static List<TypeAnnotation> filter(TypeAnnotation[] typeAnnotations,
|
||||
TypeAnnotationTarget predicate) {
|
||||
ArrayList<TypeAnnotation> typeAnnos = new ArrayList<>(typeAnnotations.length);
|
||||
for (TypeAnnotation t : typeAnnotations)
|
||||
if (t.getTargetInfo().getTarget() == predicate)
|
||||
typeAnnos.add(t);
|
||||
typeAnnos.trimToSize();
|
||||
return typeAnnos;
|
||||
}
|
||||
|
||||
public static enum TypeAnnotationTarget {
|
||||
CLASS_TYPE_PARAMETER,
|
||||
METHOD_TYPE_PARAMETER,
|
||||
CLASS_EXTENDS,
|
||||
CLASS_IMPLEMENTS,
|
||||
CLASS_PARAMETER_BOUND,
|
||||
METHOD_PARAMETER_BOUND,
|
||||
METHOD_RETURN_TYPE,
|
||||
METHOD_RECEIVER_TYPE,
|
||||
FIELD_TYPE,
|
||||
THROWS;
|
||||
}
|
||||
public static class TypeAnnotationTargetInfo {
|
||||
private final TypeAnnotationTarget target;
|
||||
private final int count;
|
||||
private final int secondaryIndex;
|
||||
private static final int UNUSED_INDEX = -2; // this is not a valid index in the 308 spec
|
||||
|
||||
public TypeAnnotationTargetInfo(TypeAnnotationTarget target) {
|
||||
this(target, UNUSED_INDEX, UNUSED_INDEX);
|
||||
}
|
||||
|
||||
public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
|
||||
int count) {
|
||||
this(target, count, UNUSED_INDEX);
|
||||
}
|
||||
|
||||
public TypeAnnotationTargetInfo(TypeAnnotationTarget target,
|
||||
int count,
|
||||
int secondaryIndex) {
|
||||
this.target = target;
|
||||
this.count = count;
|
||||
this.secondaryIndex = secondaryIndex;
|
||||
}
|
||||
|
||||
public TypeAnnotationTarget getTarget() {
|
||||
return target;
|
||||
}
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
public int getSecondaryIndex() {
|
||||
return secondaryIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "" + target + ": " + count + ", " + secondaryIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LocationInfo {
|
||||
private final int depth;
|
||||
private final Location[] locations;
|
||||
|
||||
private LocationInfo() {
|
||||
this(0, new Location[0]);
|
||||
}
|
||||
private LocationInfo(int depth, Location[] locations) {
|
||||
this.depth = depth;
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
public static final LocationInfo BASE_LOCATION = new LocationInfo();
|
||||
|
||||
public static LocationInfo parseLocationInfo(ByteBuffer buf) {
|
||||
int depth = buf.get();
|
||||
if (depth == 0)
|
||||
return BASE_LOCATION;
|
||||
Location[] locations = new Location[depth];
|
||||
for (int i = 0; i < depth; i++) {
|
||||
byte tag = buf.get();
|
||||
byte index = buf.get();
|
||||
if (!(tag == 0 || tag == 1 | tag == 2 || tag == 3))
|
||||
throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
|
||||
if (tag != 3 && index != 0)
|
||||
throw new AnnotationFormatError("Bad Location encoding in Type Annotation");
|
||||
locations[i] = new Location(tag, index);
|
||||
}
|
||||
return new LocationInfo(depth, locations);
|
||||
}
|
||||
|
||||
public LocationInfo pushArray() {
|
||||
return pushLocation((byte)0, (byte)0);
|
||||
}
|
||||
|
||||
public LocationInfo pushInner() {
|
||||
return pushLocation((byte)1, (byte)0);
|
||||
}
|
||||
|
||||
public LocationInfo pushWildcard() {
|
||||
return pushLocation((byte) 2, (byte) 0);
|
||||
}
|
||||
|
||||
public LocationInfo pushTypeArg(byte index) {
|
||||
return pushLocation((byte) 3, index);
|
||||
}
|
||||
|
||||
public LocationInfo pushLocation(byte tag, byte index) {
|
||||
int newDepth = this.depth + 1;
|
||||
Location[] res = new Location[newDepth];
|
||||
System.arraycopy(this.locations, 0, res, 0, depth);
|
||||
res[newDepth - 1] = new Location(tag, index);
|
||||
return new LocationInfo(newDepth, res);
|
||||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
boolean isSameLocationInfo(LocationInfo other) {
|
||||
if (depth != other.depth)
|
||||
return false;
|
||||
for (int i = 0; i < depth; i++)
|
||||
if (!locations[i].isSameLocation(other.locations[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static class Location {
|
||||
public final byte tag;
|
||||
public final byte index;
|
||||
|
||||
boolean isSameLocation(Location other) {
|
||||
return tag == other.tag && index == other.index;
|
||||
}
|
||||
|
||||
public Location(byte tag, byte index) {
|
||||
this.tag = tag;
|
||||
this.index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return annotation.toString() + " with Targetnfo: " +
|
||||
targetInfo.toString() + " on base declaration: " +
|
||||
baseDeclaration.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,491 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package sun.reflect.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.nio.ByteBuffer;
|
||||
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 sun.misc.JavaLangAccess;
|
||||
import sun.reflect.ConstantPool;
|
||||
import static sun.reflect.annotation.TypeAnnotation.*;
|
||||
|
||||
/**
|
||||
* TypeAnnotationParser implements the logic needed to parse
|
||||
* TypeAnnotations from an array of bytes.
|
||||
*/
|
||||
public class TypeAnnotationParser {
|
||||
private static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0];
|
||||
|
||||
/**
|
||||
* Build an AnnotatedType from the parameters supplied.
|
||||
*
|
||||
* This method and {@code buildAnnotatedTypes} are probably
|
||||
* the entry points you are looking for.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the dclaration this type annotation is on
|
||||
* @param container the Class this type annotation is on (may be the same as decl)
|
||||
* @param type the type the AnnotatedType corresponds to
|
||||
* @param filter the type annotation targets included in this AnnotatedType
|
||||
*/
|
||||
public static AnnotatedType buildAnnotatedType(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement decl,
|
||||
Class<?> container,
|
||||
Type type,
|
||||
TypeAnnotationTarget filter) {
|
||||
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
container);
|
||||
List<TypeAnnotation> l = new ArrayList<>(tas.length);
|
||||
for (TypeAnnotation t : tas) {
|
||||
TypeAnnotationTargetInfo ti = t.getTargetInfo();
|
||||
if (ti.getTarget() == filter)
|
||||
l.add(t);
|
||||
}
|
||||
TypeAnnotation[] typeAnnotations = l.toArray(new TypeAnnotation[0]);
|
||||
return AnnotatedTypeFactory.buildAnnotatedType(type,
|
||||
LocationInfo.BASE_LOCATION,
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an array of AnnotatedTypes from the parameters supplied.
|
||||
*
|
||||
* This method and {@code buildAnnotatedType} are probably
|
||||
* the entry points you are looking for.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the declaration this type annotation is on
|
||||
* @param container the Class this type annotation is on (may be the same as decl)
|
||||
* @param types the Types the AnnotatedTypes corresponds to
|
||||
* @param filter the type annotation targets that included in this AnnotatedType
|
||||
*/
|
||||
public static AnnotatedType[] buildAnnotatedTypes(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement decl,
|
||||
Class<?> container,
|
||||
Type[] types,
|
||||
TypeAnnotationTarget filter) {
|
||||
int size = types.length;
|
||||
AnnotatedType[] result = new AnnotatedType[size];
|
||||
Arrays.fill(result, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE);
|
||||
@SuppressWarnings("rawtypes")
|
||||
ArrayList[] l = new ArrayList[size]; // array of ArrayList<TypeAnnotation>
|
||||
|
||||
TypeAnnotation[] tas = parseTypeAnnotations(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
container);
|
||||
for (TypeAnnotation t : tas) {
|
||||
TypeAnnotationTargetInfo ti = t.getTargetInfo();
|
||||
if (ti.getTarget() == filter) {
|
||||
int pos = ti.getCount();
|
||||
if (l[pos] == null) {
|
||||
ArrayList<TypeAnnotation> tmp = new ArrayList<>(tas.length);
|
||||
l[pos] = tmp;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<TypeAnnotation> tmp = l[pos];
|
||||
tmp.add(t);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<TypeAnnotation> list = l[i];
|
||||
if (list != null) {
|
||||
TypeAnnotation[] typeAnnotations = list.toArray(new TypeAnnotation[0]);
|
||||
result[i] = AnnotatedTypeFactory.buildAnnotatedType(types[i],
|
||||
LocationInfo.BASE_LOCATION,
|
||||
typeAnnotations,
|
||||
typeAnnotations,
|
||||
decl);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Class helpers
|
||||
|
||||
/**
|
||||
* Build an AnnotatedType for the class decl's supertype.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the Class which annotated supertype is being built
|
||||
*/
|
||||
public static AnnotatedType buildAnnotatedSuperclass(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
Class<?> decl) {
|
||||
Type supertype = decl.getGenericSuperclass();
|
||||
if (supertype == null)
|
||||
return AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE;
|
||||
return buildAnnotatedType(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
decl,
|
||||
supertype,
|
||||
TypeAnnotationTarget.CLASS_EXTENDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an array of AnnotatedTypes for the class decl's implemented
|
||||
* interfaces.
|
||||
*
|
||||
* @param rawAnnotations the byte[] encoding of all type annotations on this declaration
|
||||
* @param cp the ConstantPool needed to parse the embedded Annotation
|
||||
* @param decl the Class whose annotated implemented interfaces is being built
|
||||
*/
|
||||
public static AnnotatedType[] buildAnnotatedInterfaces(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
Class<?> decl) {
|
||||
return buildAnnotatedTypes(rawAnnotations,
|
||||
cp,
|
||||
decl,
|
||||
decl,
|
||||
decl.getGenericInterfaces(),
|
||||
TypeAnnotationTarget.CLASS_IMPLEMENTS);
|
||||
}
|
||||
|
||||
// TypeVariable helpers
|
||||
|
||||
/**
|
||||
* Parse regular annotations on a TypeVariable declared on genericDecl.
|
||||
*
|
||||
* Regular Annotations on TypeVariables are stored in the type
|
||||
* annotation byte[] in the class file.
|
||||
*
|
||||
* @param genericsDecl the declaration declaring the type variable
|
||||
* @param typeVarIndex the 0-based index of this type variable in the declaration
|
||||
*/
|
||||
public static <D extends GenericDeclaration> Annotation[] parseTypeVariableAnnotations(D genericDecl,
|
||||
int typeVarIndex) {
|
||||
AnnotatedElement decl;
|
||||
TypeAnnotationTarget predicate;
|
||||
if (genericDecl instanceof Class) {
|
||||
decl = (Class<?>)genericDecl;
|
||||
predicate = TypeAnnotationTarget.CLASS_TYPE_PARAMETER;
|
||||
} else if (genericDecl instanceof Executable) {
|
||||
decl = (Executable)genericDecl;
|
||||
predicate = TypeAnnotationTarget.METHOD_TYPE_PARAMETER;
|
||||
} else {
|
||||
throw new AssertionError("Unknown GenericDeclaration " + genericDecl + "\nthis should not happen.");
|
||||
}
|
||||
List<TypeAnnotation> typeVarAnnos = TypeAnnotation.filter(parseAllTypeAnnotations(decl),
|
||||
predicate);
|
||||
List<Annotation> res = new ArrayList<>(typeVarAnnos.size());
|
||||
for (TypeAnnotation t : typeVarAnnos)
|
||||
if (t.getTargetInfo().getCount() == typeVarIndex)
|
||||
res.add(t.getAnnotation());
|
||||
return res.toArray(new Annotation[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an array of AnnotatedTypes for the declaration decl's bounds.
|
||||
*
|
||||
* @param bounds the bounds corresponding to the annotated bounds
|
||||
* @param decl the declaration whose annotated bounds is being built
|
||||
* @param typeVarIndex the index of this type variable on the decl
|
||||
*/
|
||||
public static <D extends GenericDeclaration> AnnotatedType[] parseAnnotatedBounds(Type[] bounds,
|
||||
D decl,
|
||||
int typeVarIndex) {
|
||||
return parseAnnotatedBounds(bounds, decl, typeVarIndex, LocationInfo.BASE_LOCATION);
|
||||
}
|
||||
//helper for above
|
||||
static <D extends GenericDeclaration> AnnotatedType[] parseAnnotatedBounds(Type[] bounds,
|
||||
D decl,
|
||||
int typeVarIndex,
|
||||
LocationInfo loc) {
|
||||
List<TypeAnnotation> candidates = fetchBounds(decl);
|
||||
if (bounds != null) {
|
||||
int startIndex = 0;
|
||||
AnnotatedType[] res = new AnnotatedType[bounds.length];
|
||||
Arrays.fill(res, AnnotatedTypeFactory.EMPTY_ANNOTATED_TYPE);
|
||||
|
||||
// Adjust bounds index
|
||||
//
|
||||
// Figure out if the type annotations for this bound starts with 0
|
||||
// or 1. The spec says within a bound the 0:th type annotation will
|
||||
// always be on an bound of a Class type (not Interface type). So
|
||||
// if the programmer starts with an Interface type for the first
|
||||
// (and following) bound(s) the implicit Object bound is considered
|
||||
// the first (that is 0:th) bound and type annotations start on
|
||||
// index 1.
|
||||
if (bounds.length > 0) {
|
||||
Type b0 = bounds[0];
|
||||
if (!(b0 instanceof Class<?>)) {
|
||||
startIndex = 1;
|
||||
} else {
|
||||
Class<?> c = (Class<?>)b0;
|
||||
if (c.isInterface()) {
|
||||
startIndex = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < bounds.length; i++) {
|
||||
List<TypeAnnotation> l = new ArrayList<>(candidates.size());
|
||||
for (TypeAnnotation t : candidates) {
|
||||
TypeAnnotationTargetInfo tInfo = t.getTargetInfo();
|
||||
if (tInfo.getSecondaryIndex() == i + startIndex &&
|
||||
tInfo.getCount() == typeVarIndex) {
|
||||
l.add(t);
|
||||
}
|
||||
res[i] = AnnotatedTypeFactory.buildAnnotatedType(bounds[i],
|
||||
loc,
|
||||
l.toArray(new TypeAnnotation[0]),
|
||||
candidates.toArray(new TypeAnnotation[0]),
|
||||
(AnnotatedElement)decl);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
return new AnnotatedType[0];
|
||||
}
|
||||
private static <D extends GenericDeclaration> List<TypeAnnotation> fetchBounds(D decl) {
|
||||
AnnotatedElement boundsDecl;
|
||||
TypeAnnotationTarget target;
|
||||
if (decl instanceof Class) {
|
||||
target = TypeAnnotationTarget.CLASS_PARAMETER_BOUND;
|
||||
boundsDecl = (Class)decl;
|
||||
} else {
|
||||
target = TypeAnnotationTarget.METHOD_PARAMETER_BOUND;
|
||||
boundsDecl = (Executable)decl;
|
||||
}
|
||||
return TypeAnnotation.filter(TypeAnnotationParser.parseAllTypeAnnotations(boundsDecl), target);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse all type annotations on the declaration supplied. This is needed
|
||||
* when you go from for example an annotated return type on a method that
|
||||
* is a type variable declared on the class. In this case you need to
|
||||
* 'jump' to the decl of the class and parse all type annotations there to
|
||||
* find the ones that are applicable to the type variable.
|
||||
*/
|
||||
static TypeAnnotation[] parseAllTypeAnnotations(AnnotatedElement decl) {
|
||||
Class<?> container;
|
||||
byte[] rawBytes;
|
||||
JavaLangAccess javaLangAccess = sun.misc.SharedSecrets.getJavaLangAccess();
|
||||
if (decl instanceof Class) {
|
||||
container = (Class<?>)decl;
|
||||
rawBytes = javaLangAccess.getRawClassTypeAnnotations(container);
|
||||
} else if (decl instanceof Executable) {
|
||||
container = ((Executable)decl).getDeclaringClass();
|
||||
rawBytes = javaLangAccess.getRawExecutableTypeAnnotations((Executable)decl);
|
||||
} else {
|
||||
// Should not reach here. Assert?
|
||||
return EMPTY_TYPE_ANNOTATION_ARRAY;
|
||||
}
|
||||
return parseTypeAnnotations(rawBytes, javaLangAccess.getConstantPool(container),
|
||||
decl, container);
|
||||
}
|
||||
|
||||
/* Parse type annotations encoded as an array of bytes */
|
||||
private static TypeAnnotation[] parseTypeAnnotations(byte[] rawAnnotations,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement baseDecl,
|
||||
Class<?> container) {
|
||||
if (rawAnnotations == null)
|
||||
return EMPTY_TYPE_ANNOTATION_ARRAY;
|
||||
|
||||
ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
|
||||
int annotationCount = buf.getShort() & 0xFFFF;
|
||||
List<TypeAnnotation> typeAnnotations = new ArrayList<>(annotationCount);
|
||||
|
||||
// Parse each TypeAnnotation
|
||||
for (int i = 0; i < annotationCount; i++) {
|
||||
TypeAnnotation ta = parseTypeAnnotation(buf, cp, baseDecl, container);
|
||||
if (ta != null)
|
||||
typeAnnotations.add(ta);
|
||||
}
|
||||
|
||||
return typeAnnotations.toArray(EMPTY_TYPE_ANNOTATION_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
// Helper
|
||||
static Map<Class<? extends Annotation>, Annotation> mapTypeAnnotations(TypeAnnotation[] typeAnnos) {
|
||||
Map<Class<? extends Annotation>, Annotation> result =
|
||||
new LinkedHashMap<>();
|
||||
for (TypeAnnotation t : typeAnnos) {
|
||||
Annotation a = t.getAnnotation();
|
||||
Class<? extends Annotation> klass = a.annotationType();
|
||||
AnnotationType type = AnnotationType.getInstance(klass);
|
||||
if (type.retention() == RetentionPolicy.RUNTIME)
|
||||
if (result.put(klass, a) != null)
|
||||
throw new AnnotationFormatError("Duplicate annotation for class: "+klass+": " + a);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Position codes
|
||||
// Regular type parameter annotations
|
||||
private static final byte CLASS_TYPE_PARAMETER = 0x00;
|
||||
private static final byte METHOD_TYPE_PARAMETER = 0x01;
|
||||
// Type Annotations outside method bodies
|
||||
private static final byte CLASS_EXTENDS = 0x10;
|
||||
private static final byte CLASS_TYPE_PARAMETER_BOUND = 0x11;
|
||||
private static final byte METHOD_TYPE_PARAMETER_BOUND = 0x12;
|
||||
private static final byte FIELD = 0x13;
|
||||
private static final byte METHOD_RETURN = 0x14;
|
||||
private static final byte METHOD_RECEIVER = 0x15;
|
||||
private static final byte METHOD_FORMAL_PARAMETER = 0x16;
|
||||
private static final byte THROWS = 0x17;
|
||||
// Type Annotations inside method bodies
|
||||
private static final byte LOCAL_VARIABLE = (byte)0x40;
|
||||
private static final byte RESOURCE_VARIABLE = (byte)0x41;
|
||||
private static final byte EXCEPTION_PARAMETER = (byte)0x42;
|
||||
private static final byte CAST = (byte)0x43;
|
||||
private static final byte INSTANCEOF = (byte)0x44;
|
||||
private static final byte NEW = (byte)0x45;
|
||||
private static final byte CONSTRUCTOR_REFERENCE_RECEIVER = (byte)0x46;
|
||||
private static final byte METHOD_REFERENCE_RECEIVER = (byte)0x47;
|
||||
private static final byte LAMBDA_FORMAL_PARAMETER = (byte)0x48;
|
||||
private static final byte METHOD_REFERENCE = (byte)0x49;
|
||||
private static final byte METHOD_REFERENCE_TYPE_ARGUMENT = (byte)0x50;
|
||||
|
||||
private static TypeAnnotation parseTypeAnnotation(ByteBuffer buf,
|
||||
ConstantPool cp,
|
||||
AnnotatedElement baseDecl,
|
||||
Class<?> container) {
|
||||
TypeAnnotationTargetInfo ti = parseTargetInfo(buf);
|
||||
LocationInfo locationInfo = LocationInfo.parseLocationInfo(buf);
|
||||
Annotation a = AnnotationParser.parseAnnotation(buf, cp, container, false);
|
||||
if (ti == null) // Inside a method for example
|
||||
return null;
|
||||
return new TypeAnnotation(ti, locationInfo, a, baseDecl);
|
||||
}
|
||||
|
||||
private static TypeAnnotationTargetInfo parseTargetInfo(ByteBuffer buf) {
|
||||
byte posCode = buf.get();
|
||||
switch(posCode) {
|
||||
case CLASS_TYPE_PARAMETER:
|
||||
case METHOD_TYPE_PARAMETER: {
|
||||
byte index = buf.get();
|
||||
TypeAnnotationTargetInfo res;
|
||||
if (posCode == CLASS_TYPE_PARAMETER)
|
||||
res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_TYPE_PARAMETER,
|
||||
index);
|
||||
else
|
||||
res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_TYPE_PARAMETER,
|
||||
index);
|
||||
return res;
|
||||
} // unreachable break;
|
||||
case CLASS_EXTENDS: {
|
||||
short index = buf.getShort();
|
||||
if (index == -1) {
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_EXTENDS);
|
||||
} else if (index >= 0) {
|
||||
TypeAnnotationTargetInfo res = new TypeAnnotationTargetInfo(TypeAnnotationTarget.CLASS_IMPLEMENTS,
|
||||
index);
|
||||
return res;
|
||||
}} break;
|
||||
case CLASS_TYPE_PARAMETER_BOUND:
|
||||
return parse2ByteTarget(TypeAnnotationTarget.CLASS_PARAMETER_BOUND, buf);
|
||||
case METHOD_TYPE_PARAMETER_BOUND:
|
||||
return parse2ByteTarget(TypeAnnotationTarget.METHOD_PARAMETER_BOUND, buf);
|
||||
case FIELD:
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.FIELD_TYPE);
|
||||
case METHOD_RETURN:
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RETURN_TYPE);
|
||||
case METHOD_RECEIVER:
|
||||
return new TypeAnnotationTargetInfo(TypeAnnotationTarget.METHOD_RECEIVER_TYPE);
|
||||
case METHOD_FORMAL_PARAMETER: {
|
||||
// Todo
|
||||
byte index = buf.get();
|
||||
} break;
|
||||
case THROWS:
|
||||
return parseShortTarget(TypeAnnotationTarget.THROWS, buf);
|
||||
|
||||
/*
|
||||
* The ones below are inside method bodies, we don't care about them for core reflection
|
||||
* other than adjusting for them in the byte stream.
|
||||
*/
|
||||
case LOCAL_VARIABLE:
|
||||
case RESOURCE_VARIABLE:
|
||||
short length = buf.getShort();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
short offset = buf.getShort();
|
||||
short varLength = buf.getShort();
|
||||
short index = buf.getShort();
|
||||
}
|
||||
break;
|
||||
case EXCEPTION_PARAMETER: {
|
||||
byte index = buf.get();
|
||||
} break;
|
||||
case CAST:
|
||||
case INSTANCEOF:
|
||||
case NEW: {
|
||||
short offset = buf.getShort();
|
||||
} break;
|
||||
case CONSTRUCTOR_REFERENCE_RECEIVER:
|
||||
case METHOD_REFERENCE_RECEIVER: {
|
||||
short offset = buf.getShort();
|
||||
byte index = buf.get();
|
||||
} break;
|
||||
case LAMBDA_FORMAL_PARAMETER: {
|
||||
byte index = buf.get();
|
||||
} break;
|
||||
case METHOD_REFERENCE:
|
||||
// This one isn't in the spec yet
|
||||
break;
|
||||
case METHOD_REFERENCE_TYPE_ARGUMENT: {
|
||||
short offset = buf.getShort();
|
||||
byte index = buf.get();
|
||||
} break;
|
||||
|
||||
default:
|
||||
// will throw error below
|
||||
break;
|
||||
}
|
||||
throw new AnnotationFormatError("Could not parse bytes for type annotations");
|
||||
}
|
||||
|
||||
private static TypeAnnotationTargetInfo parseShortTarget(TypeAnnotationTarget target, ByteBuffer buf) {
|
||||
short index = buf.getShort();
|
||||
return new TypeAnnotationTargetInfo(target, index);
|
||||
}
|
||||
private static TypeAnnotationTargetInfo parse2ByteTarget(TypeAnnotationTarget target, ByteBuffer buf) {
|
||||
byte count = buf.get();
|
||||
byte secondaryIndex = buf.get();
|
||||
return new TypeAnnotationTargetInfo(target,
|
||||
count,
|
||||
secondaryIndex);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 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
|
||||
@ -25,13 +25,18 @@
|
||||
|
||||
package sun.reflect.generics.reflectiveObjects;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericDeclaration;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import sun.reflect.annotation.AnnotationSupport;
|
||||
import sun.reflect.annotation.TypeAnnotationParser;
|
||||
import sun.reflect.annotation.AnnotationType;
|
||||
import sun.reflect.generics.factory.GenericsFactory;
|
||||
import sun.reflect.generics.tree.FieldTypeSignature;
|
||||
import sun.reflect.generics.visitor.Reifier;
|
||||
@ -182,45 +187,75 @@ public class TypeVariableImpl<D extends GenericDeclaration>
|
||||
return genericDeclaration.hashCode() ^ name.hashCode();
|
||||
}
|
||||
|
||||
// Currently vacuous implementations of AnnotatedElement methods.
|
||||
// Implementations of AnnotatedElement methods.
|
||||
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
|
||||
Objects.requireNonNull(annotationClass);
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
|
||||
Objects.requireNonNull(annotationClass);
|
||||
return null;
|
||||
// T is an Annotation type, the return value of get will be an annotation
|
||||
return (T)mapAnnotations(getAnnotations()).get(annotationClass);
|
||||
}
|
||||
|
||||
public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
|
||||
Objects.requireNonNull(annotationClass);
|
||||
return null;
|
||||
return getAnnotation(annotationClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) {
|
||||
Objects.requireNonNull(annotationClass);
|
||||
// safe because annotationClass is the class for T
|
||||
return (T[])Array.newInstance(annotationClass, 0);
|
||||
return AnnotationSupport.getMultipleAnnotations(mapAnnotations(getAnnotations()), annotationClass);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass) {
|
||||
Objects.requireNonNull(annotationClass);
|
||||
// safe because annotationClass is the class for T
|
||||
return (T[])Array.newInstance(annotationClass, 0);
|
||||
return getAnnotations(annotationClass);
|
||||
}
|
||||
|
||||
public Annotation[] getAnnotations() {
|
||||
// Since zero-length, don't need defensive clone
|
||||
return EMPTY_ANNOTATION_ARRAY;
|
||||
int myIndex = typeVarIndex();
|
||||
if (myIndex < 0)
|
||||
throw new AssertionError("Index must be non-negative.");
|
||||
return TypeAnnotationParser.parseTypeVariableAnnotations(getGenericDeclaration(), myIndex);
|
||||
}
|
||||
|
||||
public Annotation[] getDeclaredAnnotations() {
|
||||
// Since zero-length, don't need defensive clone
|
||||
return EMPTY_ANNOTATION_ARRAY;
|
||||
return getAnnotations();
|
||||
}
|
||||
|
||||
public AnnotatedType[] getAnnotatedBounds() {
|
||||
return TypeAnnotationParser.parseAnnotatedBounds(getBounds(),
|
||||
getGenericDeclaration(),
|
||||
typeVarIndex());
|
||||
}
|
||||
|
||||
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
|
||||
|
||||
// Helpers for annotation methods
|
||||
private int typeVarIndex() {
|
||||
TypeVariable<?>[] tVars = getGenericDeclaration().getTypeParameters();
|
||||
int i = -1;
|
||||
for (TypeVariable<?> v : tVars) {
|
||||
i++;
|
||||
if (equals(v))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static Map<Class<? extends Annotation>, Annotation> mapAnnotations(Annotation[] annos) {
|
||||
Map<Class<? extends Annotation>, Annotation> result =
|
||||
new LinkedHashMap<>();
|
||||
for (Annotation a : annos) {
|
||||
Class<? extends Annotation> klass = a.annotationType();
|
||||
AnnotationType type = AnnotationType.getInstance(klass);
|
||||
if (type.retention() == RetentionPolicy.RUNTIME)
|
||||
if (result.put(klass, a) != null)
|
||||
throw new AnnotationFormatError("Duplicate annotation for class: "+klass+": " + a);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -465,6 +465,12 @@ JVM_GetClassSignature(JNIEnv *env, jclass cls);
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
JVM_GetClassAnnotations(JNIEnv *env, jclass cls);
|
||||
|
||||
/* Type use annotations support (JDK 1.8) */
|
||||
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
JVM_GetClassTypeAnnotations(JNIEnv *env, jclass cls);
|
||||
|
||||
|
||||
/*
|
||||
* New (JDK 1.4) reflection implementation
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1994, 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
|
||||
@ -75,7 +75,8 @@ static JNINativeMethod methods[] = {
|
||||
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
|
||||
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
|
||||
{"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus},
|
||||
{"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo}
|
||||
{"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo},
|
||||
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
|
||||
};
|
||||
|
||||
#undef OBJ
|
||||
|
428
jdk/test/java/lang/annotation/TypeAnnotationReflection.java
Normal file
428
jdk/test/java/lang/annotation/TypeAnnotationReflection.java
Normal file
@ -0,0 +1,428 @@
|
||||
/*
|
||||
* 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 8004698
|
||||
* @summary Unit test for type annotations
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class TypeAnnotationReflection {
|
||||
public static void main(String[] args) throws Exception {
|
||||
testSuper();
|
||||
testInterfaces();
|
||||
testReturnType();
|
||||
testNested();
|
||||
testArray();
|
||||
testRunException();
|
||||
testClassTypeVarBounds();
|
||||
testMethodTypeVarBounds();
|
||||
testFields();
|
||||
testClassTypeVar();
|
||||
testMethodTypeVar();
|
||||
testParameterizedType();
|
||||
testNestedParameterizedType();
|
||||
testWildcardType();
|
||||
}
|
||||
|
||||
private static void check(boolean b) {
|
||||
if (!b)
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
private static void testSuper() throws Exception {
|
||||
check(Object.class.getAnnotatedSuperclass().getAnnotations().length == 0);
|
||||
check(Class.class.getAnnotatedSuperclass().getAnnotations().length == 0);
|
||||
|
||||
AnnotatedType a;
|
||||
a = TestClassArray.class.getAnnotatedSuperclass();
|
||||
Annotation[] annos = a.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("extends"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("extends2"));
|
||||
}
|
||||
|
||||
private static void testInterfaces() throws Exception {
|
||||
AnnotatedType[] as;
|
||||
as = TestClassArray.class.getAnnotatedInterfaces();
|
||||
check(as.length == 3);
|
||||
check(as[1].getAnnotations().length == 0);
|
||||
|
||||
Annotation[] annos;
|
||||
annos = as[0].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("implements serializable"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("implements2 serializable"));
|
||||
|
||||
annos = as[2].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("implements cloneable"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("implements2 cloneable"));
|
||||
}
|
||||
|
||||
private static void testReturnType() throws Exception {
|
||||
Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
Annotation[] annos = m.getAnnotatedReturnType().getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return1"));
|
||||
}
|
||||
|
||||
private static void testNested() throws Exception {
|
||||
Method m = TestClassNested.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
Annotation[] annos = m.getAnnotatedReturnType().getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("array"));
|
||||
|
||||
AnnotatedType t = m.getAnnotatedReturnType();
|
||||
t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType();
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Inner"));
|
||||
}
|
||||
|
||||
private static void testArray() throws Exception {
|
||||
Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
AnnotatedArrayType t = (AnnotatedArrayType) m.getAnnotatedReturnType();
|
||||
Annotation[] annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return1"));
|
||||
|
||||
t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType();
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType();
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return3"));
|
||||
|
||||
AnnotatedType tt = t.getAnnotatedGenericComponentType();
|
||||
check(!(tt instanceof AnnotatedArrayType));
|
||||
annos = tt.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return4"));
|
||||
}
|
||||
|
||||
private static void testRunException() throws Exception {
|
||||
Method m = TestClassException.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
AnnotatedType[] ts = m.getAnnotatedExceptionTypes();
|
||||
check(ts.length == 3);
|
||||
|
||||
AnnotatedType t;
|
||||
Annotation[] annos;
|
||||
t = ts[0];
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("RE"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("RE2"));
|
||||
|
||||
t = ts[1];
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
t = ts[2];
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("AIOOBE"));
|
||||
}
|
||||
|
||||
private static void testClassTypeVarBounds() throws Exception {
|
||||
Method m = TestClassTypeVarAndField.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
AnnotatedType ret = m.getAnnotatedReturnType();
|
||||
Annotation[] annos = ret.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
|
||||
AnnotatedType[] annotatedBounds = ((AnnotatedTypeVariable)ret).getAnnotatedBounds();
|
||||
check(annotatedBounds.length == 2);
|
||||
|
||||
annos = annotatedBounds[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Object1"));
|
||||
|
||||
annos = annotatedBounds[1].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Runnable1"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("Runnable2"));
|
||||
}
|
||||
|
||||
private static void testMethodTypeVarBounds() throws Exception {
|
||||
Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null);
|
||||
AnnotatedType ret2 = m2.getAnnotatedReturnType();
|
||||
AnnotatedType[] annotatedBounds2 = ((AnnotatedTypeVariable)ret2).getAnnotatedBounds();
|
||||
check(annotatedBounds2.length == 1);
|
||||
|
||||
Annotation[] annos = annotatedBounds2[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("M Runnable"));
|
||||
}
|
||||
|
||||
private static void testFields() throws Exception {
|
||||
Field f1 = TestClassTypeVarAndField.class.getDeclaredField("field1");
|
||||
AnnotatedType at;
|
||||
Annotation[] annos;
|
||||
|
||||
at = f1.getAnnotatedType();
|
||||
annos = at.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("T1 field"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("T2 field"));
|
||||
|
||||
Field f2 = TestClassTypeVarAndField.class.getDeclaredField("field2");
|
||||
at = f2.getAnnotatedType();
|
||||
annos = at.getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
Field f3 = TestClassTypeVarAndField.class.getDeclaredField("field3");
|
||||
at = f3.getAnnotatedType();
|
||||
annos = at.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Object field"));
|
||||
}
|
||||
|
||||
private static void testClassTypeVar() throws Exception {
|
||||
TypeVariable[] typeVars = TestClassTypeVarAndField.class.getTypeParameters();
|
||||
Annotation[] annos;
|
||||
check(typeVars.length == 2);
|
||||
|
||||
// First TypeVar
|
||||
AnnotatedType[] annotatedBounds = typeVars[0].getAnnotatedBounds();
|
||||
check(annotatedBounds.length == 2);
|
||||
|
||||
annos = annotatedBounds[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Object1"));
|
||||
|
||||
annos = annotatedBounds[1].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Runnable1"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("Runnable2"));
|
||||
|
||||
// second TypeVar regular anno
|
||||
Annotation[] regularAnnos = typeVars[1].getAnnotations();
|
||||
check(regularAnnos.length == 1);
|
||||
check(typeVars[1].getAnnotation(TypeAnno.class).value().equals("EE"));
|
||||
|
||||
// second TypeVar
|
||||
annotatedBounds = typeVars[1].getAnnotatedBounds();
|
||||
check(annotatedBounds.length == 1);
|
||||
|
||||
annos = annotatedBounds[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno2)annos[0]).value().equals("EEBound"));
|
||||
}
|
||||
|
||||
private static void testMethodTypeVar() throws Exception {
|
||||
Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null);
|
||||
TypeVariable[] t = m2.getTypeParameters();
|
||||
check(t.length == 1);
|
||||
Annotation[] annos = t[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
AnnotatedType[] annotatedBounds2 = t[0].getAnnotatedBounds();
|
||||
check(annotatedBounds2.length == 1);
|
||||
|
||||
annos = annotatedBounds2[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("M Runnable"));
|
||||
|
||||
// Second method
|
||||
m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo3", (Class<?>[])null);
|
||||
t = m2.getTypeParameters();
|
||||
check(t.length == 1);
|
||||
annos = t[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("K"));
|
||||
|
||||
annotatedBounds2 = t[0].getAnnotatedBounds();
|
||||
check(annotatedBounds2.length == 1);
|
||||
|
||||
annos = annotatedBounds2[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
}
|
||||
|
||||
private static void testParameterizedType() {
|
||||
// Base
|
||||
AnnotatedType[] as;
|
||||
as = TestParameterizedType.class.getAnnotatedInterfaces();
|
||||
check(as.length == 1);
|
||||
check(as[0].getAnnotations().length == 1);
|
||||
check(as[0].getAnnotation(TypeAnno.class).value().equals("M"));
|
||||
|
||||
Annotation[] annos;
|
||||
as = ((AnnotatedParameterizedType)as[0]).getAnnotatedActualTypeArguments();
|
||||
check(as.length == 2);
|
||||
annos = as[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(as[0].getAnnotation(TypeAnno.class).value().equals("S"));
|
||||
check(as[0].getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
annos = as[1].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(((TypeAnno)annos[0]).value().equals("I"));
|
||||
check(as[1].getAnnotation(TypeAnno2.class).value().equals("I2"));
|
||||
}
|
||||
|
||||
private static void testNestedParameterizedType() throws Exception {
|
||||
Method m = TestParameterizedType.class.getDeclaredMethod("foo2", (Class<?>[])null);
|
||||
AnnotatedType ret = m.getAnnotatedReturnType();
|
||||
Annotation[] annos;
|
||||
annos = ret.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno)annos[0]).value().equals("I"));
|
||||
|
||||
AnnotatedType[] args = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments();
|
||||
check(args.length == 1);
|
||||
annos = args[0].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(((TypeAnno)annos[0]).value().equals("I1"));
|
||||
check(args[0].getAnnotation(TypeAnno2.class).value().equals("I2"));
|
||||
}
|
||||
|
||||
private static void testWildcardType() throws Exception {
|
||||
Method m = TestWildcardType.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
AnnotatedType ret = m.getAnnotatedReturnType();
|
||||
AnnotatedType[] t;
|
||||
t = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments();
|
||||
check(t.length == 1);
|
||||
ret = t[0];
|
||||
|
||||
Field f = TestWildcardType.class.getDeclaredField("f1");
|
||||
AnnotatedWildcardType w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f
|
||||
.getAnnotatedType()).getAnnotatedActualTypeArguments()[0];
|
||||
t = w.getAnnotatedLowerBounds();
|
||||
check(t.length == 0);
|
||||
t = w.getAnnotatedUpperBounds();
|
||||
check(t.length == 1);
|
||||
Annotation[] annos;
|
||||
annos = t[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno)annos[0]).value().equals("2"));
|
||||
|
||||
f = TestWildcardType.class.getDeclaredField("f2");
|
||||
w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f
|
||||
.getAnnotatedType()).getAnnotatedActualTypeArguments()[0];
|
||||
t = w.getAnnotatedUpperBounds();
|
||||
check(t.length == 0);
|
||||
t = w.getAnnotatedLowerBounds();
|
||||
check(t.length == 1);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TestWildcardType {
|
||||
public <T> List<? super T> foo() { return null;}
|
||||
public Class<@TypeAnno("1") ? extends @TypeAnno("2") Annotation> f1;
|
||||
public Class<@TypeAnno("3") ? super @TypeAnno("4") Annotation> f2;
|
||||
}
|
||||
|
||||
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() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class ParameterizedOuter <T> {
|
||||
class ParameterizedInner <U> {}
|
||||
}
|
||||
|
||||
abstract class TestClassArray extends @TypeAnno("extends") @TypeAnno2("extends2") Object
|
||||
implements @TypeAnno("implements serializable") @TypeAnno2("implements2 serializable") Serializable,
|
||||
Readable,
|
||||
@TypeAnno("implements cloneable") @TypeAnno2("implements2 cloneable") Cloneable {
|
||||
public @TypeAnno("return4") Object @TypeAnno("return1") [][] @TypeAnno("return3")[] foo() { return null; }
|
||||
}
|
||||
|
||||
abstract class TestClassNested {
|
||||
public @TypeAnno("Outer") Outer.@TypeAnno("Inner")Inner @TypeAnno("array")[] foo() { return null; }
|
||||
}
|
||||
|
||||
class Outer {
|
||||
class Inner {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TestClassException {
|
||||
public Object foo() throws @TypeAnno("RE") @TypeAnno2("RE2") RuntimeException,
|
||||
NullPointerException,
|
||||
@TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TestClassTypeVarAndField <T extends @TypeAnno("Object1") Object
|
||||
& @TypeAnno("Runnable1") @TypeAnno2("Runnable2") Runnable,
|
||||
@TypeAnno("EE")EE extends @TypeAnno2("EEBound") Runnable > {
|
||||
@TypeAnno("T1 field") @TypeAnno2("T2 field") T field1;
|
||||
T field2;
|
||||
@TypeAnno("Object field") Object field3;
|
||||
|
||||
public @TypeAnno("t1") @TypeAnno2("t2") T foo(){ return null; }
|
||||
public <M extends @TypeAnno("M Runnable") Runnable> M foo2() {return null;}
|
||||
public <@TypeAnno("K") K extends Cloneable> K foo3() {return null;}
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface TypeAnno {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface TypeAnno2 {
|
||||
String value();
|
||||
}
|
120
jdk/test/java/lang/annotation/TypeParamAnnotation.java
Normal file
120
jdk/test/java/lang/annotation/TypeParamAnnotation.java
Normal file
@ -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 8004698
|
||||
* @summary Unit test for annotations on TypeVariables
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class TypeParamAnnotation {
|
||||
public static void main(String[] args) throws Exception {
|
||||
testOnClass();
|
||||
testOnMethod();
|
||||
testGetAnno();
|
||||
testGetAnnos();
|
||||
}
|
||||
|
||||
private static void check(boolean b) {
|
||||
if (!b)
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
private static void testOnClass() {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getTypeParameters();
|
||||
check(ts.length == 3);
|
||||
|
||||
Annotation[] as;
|
||||
|
||||
as = ts[0].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("t"));
|
||||
check(((ParamAnno2)as[1]).value() == 1);
|
||||
|
||||
as = ts[1].getAnnotations();
|
||||
check(as.length == 0);
|
||||
|
||||
as = ts[2].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("v"));
|
||||
check(((ParamAnno2)as[1]).value() == 2);
|
||||
}
|
||||
private static void testOnMethod() throws Exception {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getDeclaredMethod("foo").getTypeParameters();
|
||||
check(ts.length == 3);
|
||||
|
||||
Annotation[] as;
|
||||
|
||||
as = ts[0].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("x"));
|
||||
check(((ParamAnno2)as[1]).value() == 3);
|
||||
|
||||
as = ts[1].getAnnotations();
|
||||
check(as.length == 0);
|
||||
|
||||
as = ts[2].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("z"));
|
||||
check(((ParamAnno2)as[1]).value() == 4);
|
||||
}
|
||||
|
||||
private static void testGetAnno() {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getTypeParameters();
|
||||
ParamAnno a;
|
||||
a = ts[0].getAnnotation(ParamAnno.class);
|
||||
check(a.value().equals("t"));
|
||||
}
|
||||
private static void testGetAnnos() throws Exception {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getDeclaredMethod("foo").getTypeParameters();
|
||||
ParamAnno2[] as;
|
||||
as = ts[0].getAnnotations(ParamAnno2.class);
|
||||
check(as.length == 1);
|
||||
check(as[0].value() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
class TypeParam <@ParamAnno("t") @ParamAnno2(1) T,
|
||||
U,
|
||||
@ParamAnno("v") @ParamAnno2(2) V extends Runnable> {
|
||||
public <@ParamAnno("x") @ParamAnno2(3) X,
|
||||
Y,
|
||||
@ParamAnno("z") @ParamAnno2(4) Z extends Cloneable> void foo() {}
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ParamAnno {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ParamAnno2 {
|
||||
int value();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user