# HG changeset patch # User jfranck # Date 1382634267 -7200 # Node ID 6e4ef4e0097f960b57d9c51dbdb254967d638837 # Parent 2c2f062cf52fe81669a8e95d80449904f7a33592 8023651: j.l.r.Constructor.getAnnotatedReceiverType() and j.l.r.Constructor.getAnnotatedReturnType() for inner classes return incorrect result Reviewed-by: darcy diff -r 2c2f062cf52f -r 6e4ef4e0097f jdk/src/share/classes/java/lang/reflect/Constructor.java --- a/jdk/src/share/classes/java/lang/reflect/Constructor.java Thu Oct 24 13:06:05 2013 -0400 +++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java Thu Oct 24 19:04:27 2013 +0200 @@ -28,6 +28,8 @@ import sun.reflect.CallerSensitive; import sun.reflect.ConstructorAccessor; import sun.reflect.Reflection; +import sun.reflect.annotation.TypeAnnotation; +import sun.reflect.annotation.TypeAnnotationParser; import sun.reflect.generics.repository.ConstructorRepository; import sun.reflect.generics.factory.CoreReflectionFactory; import sun.reflect.generics.factory.GenericsFactory; @@ -534,4 +536,22 @@ public AnnotatedType getAnnotatedReturnType() { return getAnnotatedReturnType0(getDeclaringClass()); } + + /** + * {@inheritDoc} + * @since 1.8 + */ + @Override + public AnnotatedType getAnnotatedReceiverType() { + if (getDeclaringClass().getEnclosingClass() == null) + return super.getAnnotatedReceiverType(); + + return TypeAnnotationParser.buildAnnotatedType(getTypeAnnotationBytes0(), + sun.misc.SharedSecrets.getJavaLangAccess(). + getConstantPool(getDeclaringClass()), + this, + getDeclaringClass(), + getDeclaringClass().getEnclosingClass(), + TypeAnnotation.TypeAnnotationTarget.METHOD_RECEIVER); + } } diff -r 2c2f062cf52f -r 6e4ef4e0097f jdk/src/share/classes/java/lang/reflect/Executable.java --- a/jdk/src/share/classes/java/lang/reflect/Executable.java Thu Oct 24 13:06:05 2013 -0400 +++ b/jdk/src/share/classes/java/lang/reflect/Executable.java Thu Oct 24 19:04:27 2013 +0200 @@ -383,7 +383,7 @@ private transient volatile Parameter[] parameters; private native Parameter[] getParameters0(); - private native byte[] getTypeAnnotationBytes0(); + native byte[] getTypeAnnotationBytes0(); // Needed by reflectaccess byte[] getTypeAnnotationBytes() { diff -r 2c2f062cf52f -r 6e4ef4e0097f jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java --- a/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Thu Oct 24 13:06:05 2013 -0400 +++ b/jdk/src/share/classes/sun/reflect/annotation/AnnotatedTypeFactory.java Thu Oct 24 19:04:27 2013 +0200 @@ -95,6 +95,8 @@ Class clz = (Class)type; if (clz.getEnclosingClass() == null) return addTo; + if (Modifier.isStatic(clz.getModifiers())) + return addNesting(clz.getEnclosingClass(), addTo); return addNesting(clz.getEnclosingClass(), addTo.pushInner()); } else if (type instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType)type; diff -r 2c2f062cf52f -r 6e4ef4e0097f jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java --- a/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Thu Oct 24 13:06:05 2013 -0400 +++ b/jdk/src/share/classes/sun/reflect/annotation/TypeAnnotationParser.java Thu Oct 24 19:04:27 2013 +0200 @@ -54,7 +54,7 @@ * * @param rawAnnotations the byte[] encoding of all type annotations on this declaration * @param cp the ConstantPool needed to parse the embedded Annotation - * @param decl the dclaration this type annotation is on + * @param decl the declaration this type annotation is on * @param container the Class this type annotation is on (may be the same as decl) * @param type the type the AnnotatedType corresponds to * @param filter the type annotation targets included in this AnnotatedType diff -r 2c2f062cf52f -r 6e4ef4e0097f jdk/test/java/lang/annotation/typeAnnotations/ConstructorReceiverTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/annotation/typeAnnotations/ConstructorReceiverTest.java Thu Oct 24 19:04:27 2013 +0200 @@ -0,0 +1,147 @@ +/* + * 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 8023651 + * @summary Test that the receiver annotations and the return annotations of + * constructors behave correctly. + * @run testng ConstructorReceiverTest + */ + +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.Arrays; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static org.testng.Assert.*; + +public class ConstructorReceiverTest { + // Format is { + // { Class to get ctor for, + // ctor param class, + // value of anno of return type, + // value of anno for receiver or null if there should be no receiver anno + // }, + // ... + // } + public static final Object[][] TESTS = { + { ConstructorReceiverTest.class, null, Integer.valueOf(5), null }, + { ConstructorReceiverTest.Middle.class, ConstructorReceiverTest.class, Integer.valueOf(10), Integer.valueOf(15) }, + { ConstructorReceiverTest.Middle.Inner.class, ConstructorReceiverTest.Middle.class, Integer.valueOf(100), Integer.valueOf(150) }, + { ConstructorReceiverTest.Middle.Inner.Innermost.class, ConstructorReceiverTest.Middle.Inner.class, Integer.valueOf(1000), Integer.valueOf(1500) }, + { ConstructorReceiverTest.Middle.InnerNoReceiver.class, ConstructorReceiverTest.Middle.class, Integer.valueOf(300), null }, + { ConstructorReceiverTest.Nested.class, null, Integer.valueOf(20), null }, + { ConstructorReceiverTest.Nested.NestedMiddle.class, ConstructorReceiverTest.Nested.class, Integer.valueOf(200), Integer.valueOf(250)}, + { ConstructorReceiverTest.Nested.NestedMiddle.NestedInner.class, ConstructorReceiverTest.Nested.NestedMiddle.class, Integer.valueOf(2000), Integer.valueOf(2500)}, + { ConstructorReceiverTest.Nested.NestedMiddle.NestedInnerNoReceiver.class, ConstructorReceiverTest.Nested.NestedMiddle.class, Integer.valueOf(4000), null}, + }; + + @DataProvider + public Object[][] data() { return TESTS; } + + @Test(dataProvider = "data") + public void testAnnotatedReciver(Class toTest, Class ctorParamType, + Integer returnVal, Integer receiverVal) throws NoSuchMethodException { + Constructor c; + if (ctorParamType == null) + c = toTest.getDeclaredConstructor(); + else + c = toTest.getDeclaredConstructor(ctorParamType); + + AnnotatedType annotatedReceiverType = c.getAnnotatedReceiverType(); + Annotation[] receiverAnnotations = annotatedReceiverType.getAnnotations(); + + if (receiverVal == null) { + assertEquals(receiverAnnotations.length, 0, Arrays.asList(receiverAnnotations).toString() + + " should be empty. Looking at 'length': "); + return; + } + + assertEquals(receiverAnnotations.length, 1, "expecting a 1 element array. Looking at 'length': "); + assertEquals(((Annot)receiverAnnotations[0]).value(), receiverVal.intValue(), " wrong annotation found. Found " + + receiverAnnotations[0] + + " should find @Annot with value=" + + receiverVal); + } + + @Test(dataProvider = "data") + public void testAnnotatedReturn(Class toTest, Class ctorParamType, + Integer returnVal, Integer receiverVal) throws NoSuchMethodException { + Constructor c; + if (ctorParamType == null) + c = toTest.getDeclaredConstructor(); + else + c = toTest.getDeclaredConstructor(ctorParamType); + + AnnotatedType annotatedReturnType = c.getAnnotatedReturnType(); + Annotation[] returnAnnotations = annotatedReturnType.getAnnotations(); + + assertEquals(returnAnnotations.length, 1, "expecting a 1 element array. Looking at 'length': "); + assertEquals(((Annot)returnAnnotations[0]).value(), returnVal.intValue(), " wrong annotation found. Found " + + returnAnnotations[0] + + " should find @Annot with value=" + + returnVal); + } + + @Annot(5) ConstructorReceiverTest() {} + + private class Middle { + @Annot(10) public Middle(@Annot(15) ConstructorReceiverTest ConstructorReceiverTest.this) {} + + public class Inner { + @Annot(100) Inner(@Annot(150) Middle Middle.this) {} + + class Innermost { + @Annot(1000) private Innermost(@Annot(1500) Inner Inner.this) {} + } + } + + class InnerNoReceiver { + @Annot(300) InnerNoReceiver(Middle Middle.this) {} + } + } + + public static class Nested { + @Annot(20) public Nested() {} + + class NestedMiddle { + @Annot(200) public NestedMiddle(@Annot(250) Nested Nested.this) {} + + class NestedInner { + @Annot(2000) public NestedInner(@Annot(2500) NestedMiddle NestedMiddle.this) {} + } + + class NestedInnerNoReceiver { + @Annot(4000) public NestedInnerNoReceiver() {} + } + } + } + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE_USE) + public static @interface Annot { + int value(); + } +}