8202471: (ann) Cannot read type annotations on generic receiver type's type variables
Reviewed-by: jfranck
This commit is contained in:
parent
adb8561aba
commit
53a31889fe
@ -662,7 +662,7 @@ public final class Constructor<T> extends Executable {
|
||||
getConstantPool(thisDeclClass),
|
||||
this,
|
||||
thisDeclClass,
|
||||
enclosingClass,
|
||||
resolveToOwnerType(enclosingClass),
|
||||
TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER);
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import sun.reflect.annotation.AnnotationParser;
|
||||
import sun.reflect.annotation.AnnotationSupport;
|
||||
import sun.reflect.annotation.TypeAnnotationParser;
|
||||
import sun.reflect.annotation.TypeAnnotation;
|
||||
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
|
||||
import sun.reflect.generics.repository.ConstructorRepository;
|
||||
|
||||
/**
|
||||
@ -698,7 +699,7 @@ public abstract class Executable extends AccessibleObject
|
||||
getConstantPool(getDeclaringClass()),
|
||||
this,
|
||||
getDeclaringClass(),
|
||||
getDeclaringClass(),
|
||||
resolveToOwnerType(getDeclaringClass()),
|
||||
TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER);
|
||||
}
|
||||
|
||||
@ -753,4 +754,23 @@ public abstract class Executable extends AccessibleObject
|
||||
TypeAnnotation.TypeAnnotationTarget.THROWS);
|
||||
}
|
||||
|
||||
static Type resolveToOwnerType(Class<?> c) {
|
||||
TypeVariable<?>[] v = c.getTypeParameters();
|
||||
Type o = resolveOwner(c);
|
||||
Type t;
|
||||
if (o != null || v.length > 0) {
|
||||
t = ParameterizedTypeImpl.make(c, v, o);
|
||||
} else {
|
||||
t = c;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
private static Type resolveOwner(Class<?> t) {
|
||||
if (Modifier.isStatic(t.getModifiers()) || !(t.isLocalClass() || t.isMemberClass() || t.isAnonymousClass())) {
|
||||
return null;
|
||||
}
|
||||
Class<?> d = t.getDeclaringClass();
|
||||
return ParameterizedTypeImpl.make(d, d.getTypeParameters(), resolveOwner(d));
|
||||
}
|
||||
}
|
||||
|
@ -85,10 +85,16 @@ public class ConstructorReceiverTest {
|
||||
return;
|
||||
}
|
||||
|
||||
// check that getType() matches the receiver
|
||||
assertEquals(annotatedReceiverType.getType(),
|
||||
ctorParamType,
|
||||
"getType() doesn't match receiver type: " + ctorParamType);
|
||||
// check that getType() matches the receiver (which can be parameterized)
|
||||
if (annotatedReceiverType.getType() instanceof ParameterizedType) {
|
||||
assertEquals(((ParameterizedType) annotatedReceiverType.getType()).getRawType(),
|
||||
ctorParamType,
|
||||
"getType() doesn't match receiver type: " + ctorParamType);
|
||||
} else {
|
||||
assertEquals(annotatedReceiverType.getType(),
|
||||
ctorParamType,
|
||||
"getType() doesn't match receiver type: " + ctorParamType);
|
||||
}
|
||||
|
||||
Annotation[] receiverAnnotations = annotatedReceiverType.getAnnotations();
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class TestExecutableGetAnnotatedType {
|
||||
|
||||
@Test(dataProvider = "genericMethodData")
|
||||
public void testGenericReceiverType(Executable e) throws Exception {
|
||||
testReceiverType0(e);
|
||||
testParameterizedReceiverType0(e);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "methodData")
|
||||
@ -136,6 +136,15 @@ public class TestExecutableGetAnnotatedType {
|
||||
assertSame(e.getAnnotatedReceiverType().getType(), e.getDeclaringClass());
|
||||
}
|
||||
|
||||
private void testParameterizedReceiverType0(Executable e) {
|
||||
if (Modifier.isStatic(e.getModifiers()))
|
||||
assertNull(e.getAnnotatedReceiverType());
|
||||
else {
|
||||
assertTrue(e.getAnnotatedReceiverType().getType() instanceof ParameterizedType);
|
||||
assertSame(((ParameterizedType) e.getAnnotatedReceiverType().getType()).getRawType(), e.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
|
||||
private void testReturnType(Method m) {
|
||||
Type t = m.getGenericReturnType();
|
||||
AnnotatedType at = m.getAnnotatedReturnType();
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 8202471
|
||||
* @summary A nested class's owner can be type annotated if used as a receiver type
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TestReceiverTypeOwner<T> {
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
Method method = TestReceiverTypeOwner.Inner.class.getDeclaredMethod("m");
|
||||
AnnotatedType receiverType = method.getAnnotatedReceiverType();
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) receiverType;
|
||||
AnnotatedType owner = parameterizedType.getAnnotatedOwnerType();
|
||||
Annotation[] annotations = owner.getAnnotations();
|
||||
if (annotations.length != 1 || !(annotations[0] instanceof TypeAnnotation)) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
class Inner {
|
||||
void m(@TypeAnnotation TestReceiverTypeOwner<T>.Inner this) { }
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation { }
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 8202471
|
||||
* @summary A constructor's parameterized receiver type's type variables can be type annotated
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public class TestReceiverTypeParameterizedConstructor<T> {
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
doAssert(TestReceiverTypeParameterizedConstructor.Inner.class);
|
||||
doAssert(TestReceiverTypeParameterizedConstructor.Inner.Inner2.class);
|
||||
}
|
||||
|
||||
private static void doAssert(Class<?> c) throws NoSuchMethodException {
|
||||
Constructor<?> constructor = c.getDeclaredConstructor(c.getDeclaringClass());
|
||||
AnnotatedType receiverType = constructor.getAnnotatedReceiverType();
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) receiverType;
|
||||
int count = 0;
|
||||
do {
|
||||
AnnotatedType[] arguments = parameterizedType.getAnnotatedActualTypeArguments();
|
||||
Annotation[] annotations = arguments[0].getAnnotations();
|
||||
if (annotations.length != 1
|
||||
|| !(annotations[0] instanceof TypeAnnotation)
|
||||
|| ((TypeAnnotation) annotations[0]).value() != count++) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
parameterizedType = (AnnotatedParameterizedType) parameterizedType.getAnnotatedOwnerType();
|
||||
} while (parameterizedType != null);
|
||||
}
|
||||
|
||||
class Inner<S> {
|
||||
Inner(TestReceiverTypeParameterizedConstructor<@TypeAnnotation(0) T> TestReceiverTypeParameterizedConstructor.this) { }
|
||||
|
||||
class Inner2 {
|
||||
Inner2(TestReceiverTypeParameterizedConstructor<@TypeAnnotation(1) T>.Inner<@TypeAnnotation(0) S> TestReceiverTypeParameterizedConstructor.Inner.this) { }
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation {
|
||||
int value();
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2020, 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 8202471
|
||||
* @summary A method's parameterized receiver type's type variables can be type annotated
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TestReceiverTypeParameterizedMethod<T> {
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
doAssert(TestReceiverTypeParameterizedMethod.class);
|
||||
doAssert(TestReceiverTypeParameterizedMethod.Inner.class);
|
||||
}
|
||||
|
||||
private static void doAssert(Class<?> c) throws NoSuchMethodException {
|
||||
Method method = c.getDeclaredMethod("m");
|
||||
AnnotatedType receiverType = method.getAnnotatedReceiverType();
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) receiverType;
|
||||
int count = 0;
|
||||
do {
|
||||
AnnotatedType[] arguments = parameterizedType.getAnnotatedActualTypeArguments();
|
||||
Annotation[] annotations = arguments[0].getAnnotations();
|
||||
if (annotations.length != 1
|
||||
|| !(annotations[0] instanceof TypeAnnotation)
|
||||
|| ((TypeAnnotation) annotations[0]).value() != count++) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
parameterizedType = (AnnotatedParameterizedType) parameterizedType.getAnnotatedOwnerType();
|
||||
} while (parameterizedType != null);
|
||||
}
|
||||
|
||||
void m(TestReceiverTypeParameterizedMethod<@TypeAnnotation(0) T> this) { }
|
||||
|
||||
class Inner<S> {
|
||||
void m(TestReceiverTypeParameterizedMethod<@TypeAnnotation(1) T>.Inner<@TypeAnnotation(0) S> this) { }
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation {
|
||||
int value();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user