8168980: Reinstate sun.reflect.ReflectionFactory.newConstructorForSerialization(Class,Constructor)
Reviewed-by: alanb
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java Mon Oct 31 14:09:42 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java Tue Nov 01 12:37:29 2016 +0000
@@ -364,6 +364,16 @@
}
}
+ public final Constructor<?> newConstructorForSerialization(Class<?> cl,
+ Constructor<?> constructorToCall)
+ {
+ if (constructorToCall.getDeclaringClass() == cl) {
+ constructorToCall.setAccessible(true);
+ return constructorToCall;
+ }
+ return generateConstructor(cl, constructorToCall);
+ }
+
public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
Class<?> initCl = cl;
while (Serializable.class.isAssignableFrom(initCl)) {
@@ -383,6 +393,12 @@
} catch (NoSuchMethodException ex) {
return null;
}
+ return generateConstructor(cl, constructorToCall);
+ }
+
+ private final Constructor<?> generateConstructor(Class<?> cl,
+ Constructor<?> constructorToCall) {
+
ConstructorAccessor acc = new MethodAccessorGenerator().
generateSerializationConstructor(cl,
--- a/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java Mon Oct 31 14:09:42 2016 -0700
+++ b/jdk/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java Tue Nov 01 12:37:29 2016 +0000
@@ -85,6 +85,21 @@
}
/**
+ * Returns an accessible constructor capable of creating instances
+ * of the given class, initialized by the given constructor.
+ *
+ * @param cl the class to instantiate
+ * @param constructorToCall the constructor to call
+ * @return an accessible constructor
+ */
+ public Constructor<?> newConstructorForSerialization(Class<?> cl,
+ Constructor<?> constructorToCall)
+ {
+ return delegate.newConstructorForSerialization(cl,
+ constructorToCall);
+ }
+
+ /**
* Returns an accessible no-arg constructor for a class.
* The no-arg constructor is found searching the class and its supertypes.
*
--- a/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java Mon Oct 31 14:09:42 2016 -0700
+++ b/jdk/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java Tue Nov 01 12:37:29 2016 +0000
@@ -45,7 +45,7 @@
/*
* @test
- * @bug 8137058 8164908
+ * @bug 8137058 8164908 8168980
* @run testng ReflectionFactoryTest
* @run testng/othervm/policy=security.policy ReflectionFactoryTest
* @summary Basic test for the unsupported ReflectionFactory
@@ -95,6 +95,47 @@
}
}
+ @DataProvider(name = "NonSerialConstructors")
+ static Object[][] constructors() throws NoSuchMethodException {
+ return new Object[][] {
+ {Foo.class, Object.class.getDeclaredConstructor()},
+ {Foo.class, Foo.class.getDeclaredConstructor()},
+ {Baz.class, Object.class.getDeclaredConstructor()},
+ {Baz.class, Foo.class.getDeclaredConstructor()},
+ {Baz.class, Baz.class.getDeclaredConstructor()}
+ };
+ }
+
+ /**
+ * Tests that the given Constructor, in the hierarchy, is run.
+ */
+ @Test(dataProvider="NonSerialConstructors")
+ static void testNonSerializableConstructor(Class<?> cl,
+ Constructor<?> constructorToCall)
+ throws ReflectiveOperationException
+ {
+ @SuppressWarnings("unchecked")
+ Constructor<?> c = factory.newConstructorForSerialization(cl,
+ constructorToCall);
+
+ Object o = c.newInstance();
+ Assert.assertEquals(o.getClass(), cl, "Instance is wrong type");
+
+ int expectedFoo = 0;
+ int expectedBaz = 0;
+ if (constructorToCall.getName().equals("ReflectionFactoryTest$Foo")) {
+ expectedFoo = 1;
+ } else if (constructorToCall.getName().equals("ReflectionFactoryTest$Baz")) {
+ expectedFoo = 1;
+ expectedBaz = 4;
+ }
+
+ Assert.assertEquals(((Foo)o).foo(), expectedFoo);
+ if (o instanceof Baz) {
+ Assert.assertEquals(((Baz)o).baz(), expectedBaz);
+ }
+ }
+
static class Foo {
private int foo;
public Foo() {
@@ -109,6 +150,8 @@
int expectedFoo = 1;
Assert.assertEquals(foo, expectedFoo, "foo() constructor not run");
}
+
+ public int foo() { return foo; }
}
static class Bar extends Foo implements Serializable {
@@ -128,6 +171,12 @@
}
}
+ static class Baz extends Foo {
+ private final int baz;
+ public Baz() { this.baz = 4; }
+ public int baz() { return baz; }
+ }
+
/**
* Test newConstructorForExternalization returns the constructor and it can be called.
* @throws NoSuchMethodException - error