8055063: Parameter#toString() fails w/ AIOOBE for ctr of inner class w/ generic type
Summary: Add getAllGenericParameters, which attempts to report generic parameters with synthetic parameters to the best extent possible with current classfile information.
Reviewed-by: jfranck
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java Sun Nov 09 17:59:06 2014 -0500
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Executable.java Mon Nov 10 11:23:23 2014 -0500
@@ -286,6 +286,53 @@
}
/**
+ * Behaves like {@code getGenericParameterTypes}, but returns type
+ * information for all parameters, including synthetic parameters.
+ */
+ Type[] getAllGenericParameterTypes() {
+ final boolean genericInfo = hasGenericInformation();
+
+ // Easy case: we don't have generic parameter information. In
+ // this case, we just return the result of
+ // getParameterTypes().
+ if (!genericInfo) {
+ return getParameterTypes();
+ } else {
+ final boolean realParamData = hasRealParameterData();
+ final Type[] genericParamTypes = getGenericParameterTypes();
+ final Type[] nonGenericParamTypes = getParameterTypes();
+ final Type[] out = new Type[nonGenericParamTypes.length];
+ final Parameter[] params = getParameters();
+ int fromidx = 0;
+ // If we have real parameter data, then we use the
+ // synthetic and mandate flags to our advantage.
+ if (realParamData) {
+ for (int i = 0; i < out.length; i++) {
+ final Parameter param = params[i];
+ if (param.isSynthetic() || param.isImplicit()) {
+ // If we hit a synthetic or mandated parameter,
+ // use the non generic parameter info.
+ out[i] = nonGenericParamTypes[i];
+ } else {
+ // Otherwise, use the generic parameter info.
+ out[i] = genericParamTypes[fromidx];
+ fromidx++;
+ }
+ }
+ } else {
+ // Otherwise, use the non-generic parameter data.
+ // Without method parameter reflection data, we have
+ // no way to figure out which parameters are
+ // synthetic/mandated, thus, no way to match up the
+ // indexes.
+ return genericParamTypes.length == nonGenericParamTypes.length ?
+ genericParamTypes : nonGenericParamTypes;
+ }
+ return out;
+ }
+ }
+
+ /**
* Returns an array of {@code Parameter} objects that represent
* all the parameters to the underlying executable represented by
* this object. Returns an array of length 0 if the executable
@@ -646,7 +693,7 @@
getConstantPool(getDeclaringClass()),
this,
getDeclaringClass(),
- getGenericParameterTypes(),
+ getAllGenericParameterTypes(),
TypeAnnotation.TypeAnnotationTarget.METHOD_FORMAL_PARAMETER);
}
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java Sun Nov 09 17:59:06 2014 -0500
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java Mon Nov 10 11:23:23 2014 -0500
@@ -198,7 +198,7 @@
public Type getParameterizedType() {
Type tmp = parameterTypeCache;
if (null == tmp) {
- tmp = executable.getGenericParameterTypes()[index];
+ tmp = executable.getAllGenericParameterTypes()[index];
parameterTypeCache = tmp;
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/Parameter/InnerClassToString.java Mon Nov 10 11:23:23 2014 -0500
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014, 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 8055063
+ * @summary javac should generate method parameters correctly.
+ * @clean InnerClassToString
+ * @compile -parameters InnerClassToString.java
+ * @run main InnerClassToString
+ * @clean InnerClassToString
+ * @compile InnerClassToString.java
+ * @run main InnerClassToString
+ */
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Parameter;
+import java.util.Set;
+
+// Test copied and expanded from webbug group report.
+public class InnerClassToString {
+ private static final Class<?>[] genericParamClasses = new Class<?>[] {
+ InnerClassToString.class, Set.class
+ };
+
+ private static final Class<?>[] nongenericParamClasses = new Class<?>[] {
+ InnerClassToString.class, String.class
+ };
+
+ private int errors = 0;
+
+ private void test(Constructor<MyEntity> constructor,
+ Class<?>[] paramClasses) {
+ final Parameter[] params = constructor.getParameters();
+
+ for (int i = 0; i < params.length; i++) {
+ final Parameter parameter = params[i];
+ System.out.println(parameter.toString());
+
+ if (!parameter.getType().equals(paramClasses[i])) {
+ errors++;
+ System.err.println("Expected type " + paramClasses[i] +
+ " but got " + parameter.getType());
+ }
+
+ System.out.println(parameter.getParameterizedType());
+ System.out.println(parameter.getAnnotatedType());
+ }
+
+ }
+
+ private void run() throws Exception {
+ final Constructor<MyEntity> genericConstructor =
+ MyEntity.class.getConstructor(InnerClassToString.class, Set.class);
+
+ test(genericConstructor, genericParamClasses);
+
+ final Constructor<MyEntity> nongenericConstructor =
+ MyEntity.class.getConstructor(InnerClassToString.class, String.class);
+
+ test(nongenericConstructor, nongenericParamClasses);
+
+ if (errors != 0)
+ throw new RuntimeException(errors + " errors in test");
+ }
+
+ public static void main(String[] args) throws Exception {
+ new InnerClassToString().run();
+ }
+
+ public class MyEntity {
+ public MyEntity(Set<?> names) {}
+ public MyEntity(String names) {}
+ }
+}