--- old/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java 2016-11-01 11:28:36.000000000 +0000 +++ new/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java 2016-11-01 11:28:36.000000000 +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, --- old/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java 2016-11-01 11:28:38.000000000 +0000 +++ new/src/jdk.unsupported/share/classes/sun/reflect/ReflectionFactory.java 2016-11-01 11:28:38.000000000 +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. * --- old/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java 2016-11-01 11:28:40.000000000 +0000 +++ new/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java 2016-11-01 11:28:39.000000000 +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