8042981: Strip type annotations in Types' utility methods
Co-authored-by: Liam Miller-Cushon <cushon@openjdk.org> Reviewed-by: cushon, jjg, jlahoda
This commit is contained in:
parent
6d1856234f
commit
ed3272cc44
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2024, 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
|
||||
@ -35,6 +35,10 @@ import javax.lang.model.type.*;
|
||||
/**
|
||||
* Utility methods for operating on types.
|
||||
*
|
||||
* Where a method returns a type mirror or a collection of type
|
||||
* mirrors, any type mirrors represent types with no type annotations,
|
||||
* unless otherwise indicated.
|
||||
*
|
||||
* <p><b>Compatibility Note:</b> Methods may be added to this interface
|
||||
* in future releases of the platform.
|
||||
*
|
||||
@ -153,6 +157,8 @@ public interface Types {
|
||||
* the direct supertypes of a type mirror representing {@code
|
||||
* java.lang.Object}.
|
||||
*
|
||||
* Annotations on the direct super types are preserved.
|
||||
*
|
||||
* @param t the type being examined
|
||||
* @return the direct supertypes, or an empty list if none
|
||||
* @throws IllegalArgumentException if given a type for an executable, package, or module
|
||||
@ -235,6 +241,8 @@ public interface Types {
|
||||
/**
|
||||
* {@return an array type with the specified component type}
|
||||
*
|
||||
* Annotations on the component type are preserved.
|
||||
*
|
||||
* @param componentType the component type
|
||||
* @throws IllegalArgumentException if the component type is not valid for
|
||||
* an array
|
||||
@ -245,6 +253,8 @@ public interface Types {
|
||||
* {@return a new wildcard type} Either of the wildcard's
|
||||
* bounds may be specified, or neither, but not both.
|
||||
*
|
||||
* Annotations on the bounds are preserved.
|
||||
*
|
||||
* @param extendsBound the extends (upper) bound, or {@code null} if none
|
||||
* @param superBound the super (lower) bound, or {@code null} if none
|
||||
* @throws IllegalArgumentException if bounds are not valid
|
||||
@ -260,6 +270,8 @@ public interface Types {
|
||||
* for example, this method may be used to get the
|
||||
* parameterized type {@code Set<String>}.
|
||||
*
|
||||
* Annotations on the type arguments are preserved.
|
||||
*
|
||||
* <p> The number of type arguments must either equal the
|
||||
* number of the type element's formal type parameters, or must be
|
||||
* zero. If zero, and if the type element is generic,
|
||||
@ -291,6 +303,8 @@ public interface Types {
|
||||
* to get the type {@code Outer<String>}, and then invoking
|
||||
* this method.
|
||||
*
|
||||
* Annotations on the type arguments are preserved.
|
||||
*
|
||||
* <p> If the containing type is a parameterized type,
|
||||
* the number of type arguments must equal the
|
||||
* number of {@code typeElem}'s formal type parameters.
|
||||
@ -324,4 +338,29 @@ public interface Types {
|
||||
* for the given type
|
||||
*/
|
||||
TypeMirror asMemberOf(DeclaredType containing, Element element);
|
||||
|
||||
/**
|
||||
* {@return a type mirror equivalent to the argument, but with no annotations}
|
||||
* If the type mirror is a composite type, such as an array type
|
||||
* or a wildcard type, any constitute types, such as the
|
||||
* component type of an array and the type of the bounds of a
|
||||
* wildcard type, also have no annotations, recursively.
|
||||
*
|
||||
* <p>For most kinds of type mirrors, the result of
|
||||
* {@snippet lang="java" :
|
||||
* types.isSameType(typeMirror, types.stripAnnotations(typeMirror))
|
||||
* }
|
||||
* is {@code true}. The predicate is {@code false} on wildcard
|
||||
* types for {@linkplain #isSameType(TypeMirror, TypeMirror)
|
||||
* reasons discussed elsewhere}.
|
||||
*
|
||||
* @param t the type mirror
|
||||
* @param <T> the specific type of type mirror
|
||||
* @implSpec
|
||||
* The default implementation throws {@code UnsupportedOperationException}.
|
||||
* @since 23
|
||||
*/
|
||||
default <T extends TypeMirror> T stripAnnotations(T t) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -340,7 +340,7 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
|
||||
* it should not be used outside this class.
|
||||
*/
|
||||
protected Type typeNoMetadata() {
|
||||
return metadata.isEmpty() ? this : baseType();
|
||||
return metadata.isEmpty() ? this : stripMetadata();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -426,25 +426,42 @@ public abstract class Type extends AnnoConstruct implements TypeMirror, PoolCons
|
||||
return accept(stripMetadata, null);
|
||||
}
|
||||
//where
|
||||
/**
|
||||
* Note: this visitor only needs to handle cases where
|
||||
* 'contained' types can be annotated. These cases are
|
||||
* described in JVMS 4.7.20.2 and are : classes (for type
|
||||
* parameters and enclosing types), wildcards, and arrays.
|
||||
*/
|
||||
private static final TypeMapping<Void> stripMetadata = new StructuralTypeMapping<Void>() {
|
||||
@Override
|
||||
public Type visitClassType(ClassType t, Void aVoid) {
|
||||
return super.visitClassType((ClassType)t.typeNoMetadata(), aVoid);
|
||||
return super.visitClassType((ClassType) dropMetadata(t), aVoid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitArrayType(ArrayType t, Void aVoid) {
|
||||
return super.visitArrayType((ArrayType)t.typeNoMetadata(), aVoid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitTypeVar(TypeVar t, Void aVoid) {
|
||||
return super.visitTypeVar((TypeVar)t.typeNoMetadata(), aVoid);
|
||||
return super.visitArrayType((ArrayType) dropMetadata(t), aVoid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitWildcardType(WildcardType wt, Void aVoid) {
|
||||
return super.visitWildcardType((WildcardType)wt.typeNoMetadata(), aVoid);
|
||||
return super.visitWildcardType((WildcardType) dropMetadata(wt), aVoid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type visitType(Type t, Void aVoid) {
|
||||
return dropMetadata(t);
|
||||
}
|
||||
|
||||
private static Type dropMetadata(Type t) {
|
||||
if (t.getMetadata().isEmpty()) {
|
||||
return t;
|
||||
}
|
||||
Type baseType = t.baseType();
|
||||
if (baseType.getMetadata().isEmpty()) {
|
||||
return baseType;
|
||||
}
|
||||
return baseType.cloneWithMetadata(List.nil());
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -134,7 +134,7 @@ public class JavacTypes implements javax.lang.model.util.Types {
|
||||
TypeKind kind = t.getKind();
|
||||
if (kind == TypeKind.PACKAGE || kind == TypeKind.MODULE)
|
||||
throw new IllegalArgumentException(t.toString());
|
||||
return types.erasure((Type)t).stripMetadataIfNeeded();
|
||||
return types.erasure((Type)t).stripMetadata();
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@ -155,7 +155,7 @@ public class JavacTypes implements javax.lang.model.util.Types {
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
public TypeMirror capture(TypeMirror t) {
|
||||
validateTypeNotIn(t, EXEC_OR_PKG_OR_MOD);
|
||||
return types.capture((Type)t).stripMetadataIfNeeded();
|
||||
return types.capture((Type)t).stripMetadata();
|
||||
}
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@ -304,6 +304,13 @@ public class JavacTypes implements javax.lang.model.util.Types {
|
||||
}
|
||||
|
||||
|
||||
@DefinedBy(Api.LANGUAGE_MODEL)
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends TypeMirror> T stripAnnotations(T t) {
|
||||
return (T)((Type) t).stripMetadata();
|
||||
}
|
||||
|
||||
|
||||
private static final Set<TypeKind> EXEC_OR_PKG_OR_MOD =
|
||||
EnumSet.of(TypeKind.EXECUTABLE, TypeKind.PACKAGE, TypeKind.MODULE);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2010, 2024, 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 @@ import java.util.*;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.lang.model.util.*;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
|
||||
@ -322,4 +323,73 @@ public abstract class JavacTestingAbstractProcessor extends AbstractProcessor {
|
||||
@Override
|
||||
public boolean isFunctionalInterface(TypeElement type) {return false;}
|
||||
}
|
||||
|
||||
/**
|
||||
* Vacuous implementation of javax.lang.model.util.Types to aid
|
||||
* in test development. Methods with defaults in the interface are
|
||||
* *not* overridden to allow them to be tested.
|
||||
*/
|
||||
public static class VacuousTypes implements Types {
|
||||
public VacuousTypes() {}
|
||||
|
||||
@Override
|
||||
public Element asElement(TypeMirror t) {return null;}
|
||||
|
||||
@Override
|
||||
public boolean isSameType(TypeMirror t1, TypeMirror t2) {return false;}
|
||||
|
||||
@Override
|
||||
public boolean isSubtype(TypeMirror t1, TypeMirror t2) {return false;};
|
||||
|
||||
@Override
|
||||
public boolean isAssignable(TypeMirror t1, TypeMirror t2) {return false;};
|
||||
|
||||
@Override
|
||||
public boolean contains(TypeMirror t1, TypeMirror t2) {return false;};
|
||||
|
||||
@Override
|
||||
public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {return false;}
|
||||
|
||||
@Override
|
||||
public List<? extends TypeMirror> directSupertypes(TypeMirror t) {return null;}
|
||||
|
||||
@Override
|
||||
public TypeMirror erasure(TypeMirror t) {return null;}
|
||||
|
||||
@Override
|
||||
public TypeElement boxedClass(PrimitiveType p) {return null;}
|
||||
|
||||
@Override
|
||||
public PrimitiveType unboxedType(TypeMirror t) {return null;}
|
||||
|
||||
@Override
|
||||
public TypeMirror capture(TypeMirror t) {return null;}
|
||||
|
||||
@Override
|
||||
public PrimitiveType getPrimitiveType(TypeKind kind) {return null;}
|
||||
|
||||
@Override
|
||||
public NullType getNullType() {return null;}
|
||||
|
||||
@Override
|
||||
public NoType getNoType(TypeKind kind) {return null;}
|
||||
|
||||
@Override
|
||||
public ArrayType getArrayType(TypeMirror componentType) {return null;}
|
||||
|
||||
@Override
|
||||
public WildcardType getWildcardType(TypeMirror extendsBound,
|
||||
TypeMirror superBound) {return null;}
|
||||
|
||||
@Override
|
||||
public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {return null;}
|
||||
|
||||
|
||||
@Override
|
||||
public DeclaredType getDeclaredType(DeclaredType containing,
|
||||
TypeElement typeElem, TypeMirror... typeArgs) {return null;}
|
||||
|
||||
@Override
|
||||
public TypeMirror asMemberOf(DeclaredType containing, Element element) {return null;}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2024, 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 8042981
|
||||
* @summary Test if annotations are stripped from the results of Types' methods
|
||||
* @library /tools/javac/lib
|
||||
* @modules java.compiler
|
||||
* jdk.compiler
|
||||
* @build JavacTestingAbstractProcessor TestAnnotationStripping
|
||||
* @compile -processor TestAnnotationStripping -proc:only TestAnnotationStripping.java
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.util.*;
|
||||
import static java.util.Objects.*;
|
||||
import javax.annotation.processing.*;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import static javax.lang.model.SourceVersion.*;
|
||||
import javax.lang.model.*;
|
||||
import javax.lang.model.element.*;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.lang.model.util.*;
|
||||
import static javax.lang.model.util.ElementFilter.*;
|
||||
import static javax.tools.Diagnostic.Kind.*;
|
||||
import static javax.tools.StandardLocation.*;
|
||||
|
||||
/**
|
||||
* Test if annotations are stripped from the results of Types' methods
|
||||
*/
|
||||
public class TestAnnotationStripping extends JavacTestingAbstractProcessor {
|
||||
private Types vacuousTypes = new VacuousTypes();
|
||||
|
||||
/**
|
||||
* Check expected behavior on classes and packages.
|
||||
*/
|
||||
public boolean process(Set<? extends TypeElement> annotations,
|
||||
RoundEnvironment roundEnv) {
|
||||
if (!roundEnv.processingOver()) {
|
||||
TypeElement juSetElt = eltUtils.getTypeElement("java.util.Set");
|
||||
TypeElement testElt = elements.getTypeElement("TestAnnotationStripping");
|
||||
TypeElement boxElt = elements.getTypeElement("TestAnnotationStripping.Box");
|
||||
|
||||
TypeMirror expectedAnnotation = eltUtils.getTypeElement("TestTypeAnnotation").asType();
|
||||
|
||||
for (ExecutableElement m :
|
||||
methodsIn(eltUtils.getTypeElement("HostClass").getEnclosedElements())) {
|
||||
/*
|
||||
* The kinds of types include:
|
||||
*
|
||||
* arrays
|
||||
* declared types (classes, interfaces, etc.)
|
||||
* error types
|
||||
* executable types
|
||||
* intersection types
|
||||
* no-type
|
||||
* null type
|
||||
* primitive types
|
||||
* type variable
|
||||
* union type
|
||||
* wildcards
|
||||
*
|
||||
* A subset of these can appear at the return type of
|
||||
* a method. The general methodology is to verify that
|
||||
* types that can appear as return types when
|
||||
* annotated with type annotations appear as specified
|
||||
* as the result of type operations or when new types
|
||||
* are constructed.
|
||||
*/
|
||||
|
||||
TypeMirror returnType = m.getReturnType();
|
||||
|
||||
System.err.println("Checking " + returnType);
|
||||
|
||||
testVacuous(returnType);
|
||||
checkDeepEmptyAnnotations(typeUtils.stripAnnotations(returnType));
|
||||
|
||||
checkExpectedTypeAnnotations(returnType, expectedAnnotation);
|
||||
|
||||
// Note: the result of Types.asElement is *not*
|
||||
// checked for its annotations since the return value
|
||||
// is an Element and not a TypeMirror.
|
||||
|
||||
System.err.print("\tcapture()");
|
||||
checkDeepEmptyAnnotations(typeUtils.capture(returnType));
|
||||
|
||||
System.err.print("\terasure()");
|
||||
checkDeepEmptyAnnotations(typeUtils.erasure(returnType));
|
||||
|
||||
System.err.print("\tgetArrayType()");
|
||||
ArrayType arrayType = typeUtils.getArrayType(returnType);
|
||||
checkEmptyAnnotations(arrayType);
|
||||
/*
|
||||
* "Annotations on the component type are preserved."
|
||||
*/
|
||||
checkEqualTypeAndAnnotations(returnType, arrayType.getComponentType());
|
||||
|
||||
if (!returnType.getKind().isPrimitive()) {
|
||||
/*
|
||||
* For getWildcardType()
|
||||
* "Annotations on the bounds are preserved."
|
||||
*/
|
||||
WildcardType wcType;
|
||||
checkEmptyAnnotations(wcType = typeUtils.getWildcardType(returnType, null));
|
||||
checkEqualTypeAndAnnotations(returnType, wcType.getExtendsBound());
|
||||
|
||||
checkEmptyAnnotations(wcType = typeUtils.getWildcardType(null, returnType));
|
||||
checkEqualTypeAndAnnotations(returnType, wcType.getSuperBound());
|
||||
|
||||
/*
|
||||
* For getDeclaredType()
|
||||
* "Annotations on the type arguments are preserved."
|
||||
*/
|
||||
DeclaredType declaredType = typeUtils.getDeclaredType(juSetElt, returnType);
|
||||
checkEqualTypeAndAnnotations(returnType, declaredType.getTypeArguments().get(0));
|
||||
|
||||
// Check both overloads
|
||||
declaredType = typeUtils.getDeclaredType(typeUtils.getDeclaredType(testElt), // outer type
|
||||
boxElt,
|
||||
returnType);
|
||||
checkEqualTypeAndAnnotations(returnType, declaredType.getTypeArguments().get(0));
|
||||
}
|
||||
|
||||
System.out.println(returnType.getAnnotation(TestTypeAnnotation.class));
|
||||
System.out.println(returnType.getAnnotationsByType(TestTypeAnnotation.class).length);
|
||||
TestTypeAnnotation ta = requireNonNull(returnType.getAnnotation(TestTypeAnnotation.class),
|
||||
returnType.toString());
|
||||
|
||||
System.err.println();
|
||||
System.err.println();
|
||||
}
|
||||
|
||||
if (failures > 0)
|
||||
throw new RuntimeException(failures + " failures occured.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void testVacuous(TypeMirror tm ) {
|
||||
try {
|
||||
var result = vacuousTypes.stripAnnotations(tm);
|
||||
messager.printError("Unexpected non-exceptional result returned " + result);
|
||||
} catch(UnsupportedOperationException uoe) {
|
||||
; // Expected
|
||||
}
|
||||
}
|
||||
|
||||
private int failures = 0;
|
||||
|
||||
void checkExpectedTypeAnnotations(AnnotatedConstruct ac, TypeMirror expectedAnnotation) {
|
||||
List<? extends AnnotationMirror> annotations = ac.getAnnotationMirrors();
|
||||
if (annotations.size() != 1) {
|
||||
failures++;
|
||||
System.err.println("\t\t\tUnexpected annotations size: " + annotations.size());
|
||||
} else if (!typeUtils.isSameType(annotations.get(0).getAnnotationType(), expectedAnnotation)) {
|
||||
failures++;
|
||||
System.err.println("\t\t\tUnexpected annotations type: " + annotations);
|
||||
}
|
||||
}
|
||||
|
||||
void checkEmptyAnnotations(AnnotatedConstruct ac) {
|
||||
System.err.println("\t" + ac);
|
||||
if (ac == null)
|
||||
return;
|
||||
else {
|
||||
List<? extends AnnotationMirror> annotations = ac.getAnnotationMirrors();
|
||||
int count = annotations.size();
|
||||
if (count != 0) {
|
||||
failures++;
|
||||
System.err.println(ac.getClass());
|
||||
System.err.println("\t\t\tUnexpected nonzero annotations size: " + annotations);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void checkDeepEmptyAnnotations(TypeMirror ac) {
|
||||
System.err.println("\t" + ac);
|
||||
if (ac == null) {
|
||||
return;
|
||||
}
|
||||
new SimpleTypeVisitor14<Void, Void>() {
|
||||
@Override
|
||||
protected Void defaultAction(TypeMirror t, Void o) {
|
||||
checkEmptyAnnotations(t);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitArray(ArrayType t, Void o) {
|
||||
scan(t.getComponentType());
|
||||
return super.visitArray(t, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitDeclared(DeclaredType t, Void o) {
|
||||
scan(t.getEnclosingType());
|
||||
t.getTypeArguments().stream().forEach(this::scan);
|
||||
return super.visitDeclared(t, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitTypeVariable(TypeVariable t, Void o) {
|
||||
// the bounds correspond to the type variable declaration, not its use
|
||||
// scan(t.getUpperBound());
|
||||
// scan(t.getLowerBound());
|
||||
return super.visitTypeVariable(t, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitWildcard(WildcardType t, Void o) {
|
||||
scan(t.getExtendsBound());
|
||||
scan(t.getSuperBound());
|
||||
return super.visitWildcard(t, o);
|
||||
}
|
||||
|
||||
private void scan(TypeMirror t) {
|
||||
if (t != null) {
|
||||
visit(t);
|
||||
}
|
||||
}
|
||||
}.visit(ac);
|
||||
}
|
||||
|
||||
void checkEqualTypeAndAnnotations(TypeMirror tm1, TypeMirror tm2) {
|
||||
if (!typeUtils.isSameType(tm1, tm2)) {
|
||||
failures++;
|
||||
System.err.printf("Unequal types %s and %s.%n", tm1, tm2);
|
||||
}
|
||||
|
||||
if (!Objects.equals(tm1.getAnnotationMirrors(), tm1.getAnnotationMirrors())) {
|
||||
failures++;
|
||||
System.err.printf("Unequal annotations on and %s.%n", tm1, tm2);
|
||||
}
|
||||
}
|
||||
|
||||
// Nested class to test getDeclaredType overload.
|
||||
class Box<T> {
|
||||
private T contents;
|
||||
|
||||
public Box(T t){
|
||||
contents = t;
|
||||
}
|
||||
|
||||
T value() { return contents;};
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class to host annotations for testing
|
||||
*/
|
||||
class HostClass {
|
||||
// Declared type Integer
|
||||
public static @TestTypeAnnotation("foo") Integer foo() {return null;}
|
||||
|
||||
// Primitive type int
|
||||
public static @TestTypeAnnotation("foo2") int foo2() {return 0;}
|
||||
|
||||
public static @TestTypeAnnotation("foo3") String foo3() {return null;}
|
||||
|
||||
// Declared raw type Set
|
||||
public static java.util.@TestTypeAnnotation("foo4")Set foo4() {return null;}
|
||||
|
||||
// Array type
|
||||
public static String @TestTypeAnnotation("foo5")[] foo5() {return null;}
|
||||
|
||||
// Declared type Set with instantiated type parameter
|
||||
public static java.util. @TestTypeAnnotation("foo6") Set < @TestTypeAnnotation("foo7") String> foo6() {return null;}
|
||||
|
||||
// Type variable
|
||||
public static <@TestTypeAnnotation("foo8") T extends @TestTypeAnnotation("foo9") String> @TestTypeAnnotation("foo10") T foo7() {return null;}
|
||||
|
||||
// Declared type including wildcard
|
||||
public static java.util. @TestTypeAnnotation("foo11") Set < @TestTypeAnnotation("foo12") ? extends @TestTypeAnnotation("foo13") Number> foo8() {return null;}
|
||||
|
||||
// Type variable with intersection type
|
||||
public static <@TestTypeAnnotation("foo14") S extends Number & Runnable> @TestTypeAnnotation("foo15") S foo9() {return null;}
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TestTypeAnnotation {
|
||||
String value() default "";
|
||||
}
|
Loading…
Reference in New Issue
Block a user