提交 6f3e485f 编写于 作者: J jfranck

8004698: Implement Core Reflection for Type Annotations

Reviewed-by: darcy
上级 6a3cc7d7
...@@ -29,12 +29,14 @@ import java.lang.reflect.Array; ...@@ -29,12 +29,14 @@ import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Executable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable; import java.lang.reflect.TypeVariable;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.AnnotatedType;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectStreamField; import java.io.ObjectStreamField;
...@@ -2325,6 +2327,11 @@ public final ...@@ -2325,6 +2327,11 @@ public final
// Annotations handling // Annotations handling
private native byte[] getRawAnnotations(); private native byte[] getRawAnnotations();
// Since 1.8
native byte[] getRawTypeAnnotations();
static byte[] getExecutableTypeAnnotationBytes(Executable ex) {
return getReflectionFactory().getExecutableTypeAnnotationBytes(ex);
}
native ConstantPool getConstantPool(); native ConstantPool getConstantPool();
...@@ -3196,4 +3203,53 @@ public final ...@@ -3196,4 +3203,53 @@ public final
* Maintained by the ClassValue class. * Maintained by the ClassValue class.
*/ */
transient ClassValue.ClassValueMap classValueMap; 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);
}
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,6 +26,7 @@ package java.lang; ...@@ -26,6 +26,7 @@ package java.lang;
import java.io.*; import java.io.*;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import java.util.Properties; import java.util.Properties;
import java.util.PropertyPermission; import java.util.PropertyPermission;
import java.util.StringTokenizer; import java.util.StringTokenizer;
...@@ -1199,6 +1200,12 @@ public final class System { ...@@ -1199,6 +1200,12 @@ public final class System {
public <A extends Annotation> A getDirectDeclaredAnnotation(Class<?> klass, Class<A> anno) { public <A extends Annotation> A getDirectDeclaredAnnotation(Class<?> klass, Class<A> anno) {
return klass.getDirectDeclaredAnnotation(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>> public <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) { E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared(); return klass.getEnumConstantsShared();
......
/*
* 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();
}
/*
* 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();
}
/*
* 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();
}
/*
* 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();
}
/*
* 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 { ...@@ -154,6 +154,10 @@ public final class Constructor<T> extends Executable {
byte[] getAnnotationBytes() { byte[] getAnnotationBytes() {
return annotations; return annotations;
} }
@Override
byte[] getTypeAnnotationBytes() {
return typeAnnotations;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
...@@ -523,4 +527,12 @@ public final class Constructor<T> extends Executable { ...@@ -523,4 +527,12 @@ public final class Constructor<T> extends Executable {
} }
} }
} }
/**
* {@inheritDoc}
* @since 1.8
*/
public AnnotatedType getAnnotatedReturnType() {
return getAnnotatedReturnType0(getDeclaringClass());
}
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -31,6 +31,8 @@ import java.util.Map; ...@@ -31,6 +31,8 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import sun.reflect.annotation.AnnotationParser; import sun.reflect.annotation.AnnotationParser;
import sun.reflect.annotation.AnnotationSupport; import sun.reflect.annotation.AnnotationSupport;
import sun.reflect.annotation.TypeAnnotationParser;
import sun.reflect.annotation.TypeAnnotation;
import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.repository.ConstructorRepository;
/** /**
...@@ -50,6 +52,7 @@ public abstract class Executable extends AccessibleObject ...@@ -50,6 +52,7 @@ public abstract class Executable extends AccessibleObject
* Accessor method to allow code sharing * Accessor method to allow code sharing
*/ */
abstract byte[] getAnnotationBytes(); abstract byte[] getAnnotationBytes();
abstract byte[] getTypeAnnotationBytes();
/** /**
* Does the Executable have generic information. * Does the Executable have generic information.
...@@ -470,4 +473,86 @@ public abstract class Executable extends AccessibleObject ...@@ -470,4 +473,86 @@ public abstract class Executable extends AccessibleObject
return declaredAnnotations; 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);
}
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -36,7 +36,8 @@ import java.util.Map; ...@@ -36,7 +36,8 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import sun.reflect.annotation.AnnotationParser; import sun.reflect.annotation.AnnotationParser;
import sun.reflect.annotation.AnnotationSupport; 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 * A {@code Field} provides information about, and dynamic access to, a
...@@ -1053,4 +1054,20 @@ class Field extends AccessibleObject implements Member { ...@@ -1053,4 +1054,20 @@ class Field extends AccessibleObject implements Member {
} }
return declaredAnnotations; 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 { ...@@ -165,6 +165,10 @@ public final class Method extends Executable {
byte[] getAnnotationBytes() { byte[] getAnnotationBytes() {
return annotations; return annotations;
} }
@Override
byte[] getTypeAnnotationBytes() {
return typeAnnotations;
}
/** /**
* {@inheritDoc} * {@inheritDoc}
...@@ -621,6 +625,14 @@ public final class Method extends Executable { ...@@ -621,6 +625,14 @@ public final class Method extends Executable {
return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations); return sharedGetParameterAnnotations(parameterTypes, parameterAnnotations);
} }
/**
* {@inheritDoc}
* @since 1.8
*/
public AnnotatedType getAnnotatedReturnType() {
return getAnnotatedReturnType0(getGenericReturnType());
}
@Override @Override
void handleParameterNumberMismatch(int resultLength, int numParameters) { void handleParameterNumberMismatch(int resultLength, int numParameters) {
throw new AnnotationFormatError("Parameter annotations don't match number of parameters"); throw new AnnotationFormatError("Parameter annotations don't match number of parameters");
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -128,6 +128,10 @@ class ReflectAccess implements sun.reflect.LangReflectAccess { ...@@ -128,6 +128,10 @@ class ReflectAccess implements sun.reflect.LangReflectAccess {
return c.getRawParameterAnnotations(); return c.getRawParameterAnnotations();
} }
public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
return ex.getTypeAnnotationBytes();
}
// //
// Copying routines, needed to quickly fabricate new Field, // Copying routines, needed to quickly fabricate new Field,
// Method, and Constructor objects from templates // Method, and Constructor objects from templates
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 ...@@ -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 * @return the name of this type variable, as it appears in the source code
*/ */
String getName(); 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();
} }
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
package sun.misc; package sun.misc;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Executable;
import sun.reflect.ConstantPool; import sun.reflect.ConstantPool;
import sun.reflect.annotation.AnnotationType; import sun.reflect.annotation.AnnotationType;
import sun.nio.ch.Interruptible; import sun.nio.ch.Interruptible;
...@@ -46,6 +47,18 @@ public interface JavaLangAccess { ...@@ -46,6 +47,18 @@ public interface JavaLangAccess {
*/ */
AnnotationType getAnnotationType(Class<?> klass); 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 * Returns the elements of an enum class or null if the
* Class object does not represent an enum type; * Class object does not represent an enum type;
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -81,6 +81,9 @@ public interface LangReflectAccess { ...@@ -81,6 +81,9 @@ public interface LangReflectAccess {
public void setConstructorAccessor(Constructor<?> c, public void setConstructorAccessor(Constructor<?> c,
ConstructorAccessor accessor); 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) */ /** Gets the "slot" field from a Constructor (used for serialization) */
public int getConstructorSlot(Constructor<?> c); public int getConstructorSlot(Constructor<?> c);
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
package sun.reflect; package sun.reflect;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Executable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
...@@ -314,6 +315,12 @@ public class ReflectionFactory { ...@@ -314,6 +315,12 @@ public class ReflectionFactory {
return langReflectAccess().copyConstructor(arg); 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 // Routines used by serialization
......
/*
* 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;
}
}
}
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -188,7 +188,7 @@ public class AnnotationParser { ...@@ -188,7 +188,7 @@ public class AnnotationParser {
* available at runtime * available at runtime
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static Annotation parseAnnotation(ByteBuffer buf, static Annotation parseAnnotation(ByteBuffer buf,
ConstantPool constPool, ConstantPool constPool,
Class<?> container, Class<?> container,
boolean exceptionOnMissingAnnotationClass) { boolean exceptionOnMissingAnnotationClass) {
......
/*
* 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();
}
}
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -25,13 +25,18 @@ ...@@ -25,13 +25,18 @@
package sun.reflect.generics.reflectiveObjects; 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.Array;
import java.lang.reflect.GenericDeclaration; import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable; import java.lang.reflect.TypeVariable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects; 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.factory.GenericsFactory;
import sun.reflect.generics.tree.FieldTypeSignature; import sun.reflect.generics.tree.FieldTypeSignature;
import sun.reflect.generics.visitor.Reifier; import sun.reflect.generics.visitor.Reifier;
...@@ -182,45 +187,75 @@ public class TypeVariableImpl<D extends GenericDeclaration> ...@@ -182,45 +187,75 @@ public class TypeVariableImpl<D extends GenericDeclaration>
return genericDeclaration.hashCode() ^ name.hashCode(); return genericDeclaration.hashCode() ^ name.hashCode();
} }
// Currently vacuous implementations of AnnotatedElement methods. // Implementations of AnnotatedElement methods.
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) { public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
Objects.requireNonNull(annotationClass); Objects.requireNonNull(annotationClass);
return false; return false;
} }
@SuppressWarnings("unchecked")
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(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) { public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass); Objects.requireNonNull(annotationClass);
return null; return getAnnotation(annotationClass);
} }
@SuppressWarnings("unchecked")
public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) { public <T extends Annotation> T[] getAnnotations(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass); Objects.requireNonNull(annotationClass);
// safe because annotationClass is the class for T return AnnotationSupport.getMultipleAnnotations(mapAnnotations(getAnnotations()), annotationClass);
return (T[])Array.newInstance(annotationClass, 0);
} }
@SuppressWarnings("unchecked")
public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass) { public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotationClass) {
Objects.requireNonNull(annotationClass); Objects.requireNonNull(annotationClass);
// safe because annotationClass is the class for T return getAnnotations(annotationClass);
return (T[])Array.newInstance(annotationClass, 0);
} }
public Annotation[] getAnnotations() { public Annotation[] getAnnotations() {
// Since zero-length, don't need defensive clone int myIndex = typeVarIndex();
return EMPTY_ANNOTATION_ARRAY; if (myIndex < 0)
throw new AssertionError("Index must be non-negative.");
return TypeAnnotationParser.parseTypeVariableAnnotations(getGenericDeclaration(), myIndex);
} }
public Annotation[] getDeclaredAnnotations() { public Annotation[] getDeclaredAnnotations() {
// Since zero-length, don't need defensive clone return getAnnotations();
return EMPTY_ANNOTATION_ARRAY; }
public AnnotatedType[] getAnnotatedBounds() {
return TypeAnnotationParser.parseAnnotatedBounds(getBounds(),
getGenericDeclaration(),
typeVarIndex());
} }
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; 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); ...@@ -465,6 +465,12 @@ JVM_GetClassSignature(JNIEnv *env, jclass cls);
JNIEXPORT jbyteArray JNICALL JNIEXPORT jbyteArray JNICALL
JVM_GetClassAnnotations(JNIEnv *env, jclass cls); 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 * New (JDK 1.4) reflection implementation
*/ */
......
/* /*
* 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -75,7 +75,8 @@ static JNINativeMethod methods[] = { ...@@ -75,7 +75,8 @@ static JNINativeMethod methods[] = {
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations}, {"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool}, {"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},
{"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus}, {"desiredAssertionStatus0","("CLS")Z",(void *)&JVM_DesiredAssertionStatus},
{"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo} {"getEnclosingMethod0", "()[" OBJ, (void *)&JVM_GetEnclosingMethodInfo},
{"getRawTypeAnnotations", "()" BA, (void *)&JVM_GetClassTypeAnnotations},
}; };
#undef OBJ #undef OBJ
......
/*
* 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();
}
/*
* 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();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册