diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java
index acac29be9abc53bb8fc7542932378e3bebaf5b72..7b9353ab0f1b8fc8764c83384ea644afaed66c85 100644
--- a/src/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/share/classes/java/lang/invoke/MethodHandles.java
@@ -680,7 +680,9 @@ public class MethodHandles {
// disallow lookup more restricted packages
if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) {
if (name.startsWith("java.") ||
- (name.startsWith("sun.") && !name.startsWith("sun.invoke."))) {
+ (name.startsWith("sun.")
+ && !name.startsWith("sun.invoke.")
+ && !name.equals("sun.reflect.ReflectionFactory"))) {
throw newIllegalArgumentException("illegal lookupClass: " + lookupClass);
}
}
diff --git a/src/share/classes/sun/reflect/ReflectionFactory.java b/src/share/classes/sun/reflect/ReflectionFactory.java
index dc26fab816b51ad419050964f068b63f6af57720..95408bd931bb04a79d7bb7c712e5233d7aa8b1ed 100644
--- a/src/share/classes/sun/reflect/ReflectionFactory.java
+++ b/src/share/classes/sun/reflect/ReflectionFactory.java
@@ -25,16 +25,28 @@
package sun.reflect;
+import java.io.Externalizable;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.OptionalDataException;
+import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;
import java.lang.reflect.Executable;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
+import java.util.Objects;
+
import sun.reflect.misc.ReflectUtil;
+
/**
The master factory for all reflective objects, both those in
java.lang.reflect (Fields, Methods, Constructors) as well as their
delegates (FieldAccessors, MethodAccessors, ConstructorAccessors).
@@ -56,6 +68,9 @@ public class ReflectionFactory {
// Provides access to package-private mechanisms in java.lang.reflect
private static volatile LangReflectAccess langReflectAccess;
+ /* Method for static class initializer , or null */
+ private static volatile Method hasStaticInitializerMethod;
+
//
// "Inflation" mechanism. Loading bytecodes to implement
// Method.invoke() and Constructor.newInstance() currently costs
@@ -73,8 +88,7 @@ public class ReflectionFactory {
private static boolean noInflation = false;
private static int inflationThreshold = 15;
- private ReflectionFactory() {
- }
+ private ReflectionFactory() {}
/**
* A convenience class for acquiring the capability to instantiate
@@ -328,6 +342,14 @@ public class ReflectionFactory {
//
//
+ /**
+ * Returns an accessible constructor capable of creating instances
+ * of the given class, initialized by the given constructor.
+ *
+ * @param classToInstantiate the class to instantiate
+ * @param constructorToCall the constructor to call
+ * @return an accessible constructor
+ */
public Constructor> newConstructorForSerialization
(Class> classToInstantiate, Constructor> constructorToCall)
{
@@ -335,6 +357,42 @@ public class ReflectionFactory {
if (constructorToCall.getDeclaringClass() == classToInstantiate) {
return constructorToCall;
}
+ return generateConstructor(classToInstantiate, constructorToCall);
+ }
+
+ /**
+ * Returns an accessible no-arg constructor for a class.
+ * The no-arg constructor is found searching the class and its supertypes.
+ *
+ * @param cl the class to instantiate
+ * @return a no-arg constructor for the class or {@code null} if
+ * the class or supertypes do not have a suitable no-arg constructor
+ */
+ public final Constructor> newConstructorForSerialization(Class> cl) {
+ Class> initCl = cl;
+ while (Serializable.class.isAssignableFrom(initCl)) {
+ if ((initCl = initCl.getSuperclass()) == null) {
+ return null;
+ }
+ }
+ Constructor> constructorToCall;
+ try {
+ constructorToCall = initCl.getDeclaredConstructor();
+ int mods = constructorToCall.getModifiers();
+ if ((mods & Modifier.PRIVATE) != 0 ||
+ ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
+ !packageEquals(cl, initCl))) {
+ return null;
+ }
+ } catch (NoSuchMethodException ex) {
+ return null;
+ }
+ return generateConstructor(cl, constructorToCall);
+ }
+
+ private final Constructor> generateConstructor(Class> classToInstantiate,
+ Constructor> constructorToCall) {
+
ConstructorAccessor acc = new MethodAccessorGenerator().
generateSerializationConstructor(classToInstantiate,
@@ -355,9 +413,222 @@ public class ReflectionFactory {
langReflectAccess().
getConstructorParameterAnnotations(constructorToCall));
setConstructorAccessor(c, acc);
+ c.setAccessible(true);
return c;
}
+ /**
+ * Returns an accessible no-arg constructor for an externalizable class to be
+ * initialized using a public no-argument constructor.
+ *
+ * @param cl the class to instantiate
+ * @return A no-arg constructor for the class; returns {@code null} if
+ * the class does not implement {@link java.io.Externalizable}
+ */
+ public final Constructor> newConstructorForExternalization(Class> cl) {
+ if (!Externalizable.class.isAssignableFrom(cl)) {
+ return null;
+ }
+ try {
+ Constructor> cons = cl.getConstructor();
+ cons.setAccessible(true);
+ return cons;
+ } catch (NoSuchMethodException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Returns a direct MethodHandle for the {@code readObject} method on
+ * a Serializable class.
+ * The first argument of {@link MethodHandle#invoke} is the serializable
+ * object and the second argument is the {@code ObjectInputStream} passed to
+ * {@code readObject}.
+ *
+ * @param cl a Serializable class
+ * @return a direct MethodHandle for the {@code readObject} method of the class or
+ * {@code null} if the class does not have a {@code readObject} method
+ */
+ public final MethodHandle readObjectForSerialization(Class> cl) {
+ return findReadWriteObjectForSerialization(cl, "readObject", ObjectInputStream.class);
+ }
+
+ /**
+ * Returns a direct MethodHandle for the {@code readObjectNoData} method on
+ * a Serializable class.
+ * The first argument of {@link MethodHandle#invoke} is the serializable
+ * object and the second argument is the {@code ObjectInputStream} passed to
+ * {@code readObjectNoData}.
+ *
+ * @param cl a Serializable class
+ * @return a direct MethodHandle for the {@code readObjectNoData} method
+ * of the class or {@code null} if the class does not have a
+ * {@code readObjectNoData} method
+ */
+ public final MethodHandle readObjectNoDataForSerialization(Class> cl) {
+ return findReadWriteObjectForSerialization(cl, "readObjectNoData", ObjectInputStream.class);
+ }
+
+ /**
+ * Returns a direct MethodHandle for the {@code writeObject} method on
+ * a Serializable class.
+ * The first argument of {@link MethodHandle#invoke} is the serializable
+ * object and the second argument is the {@code ObjectOutputStream} passed to
+ * {@code writeObject}.
+ *
+ * @param cl a Serializable class
+ * @return a direct MethodHandle for the {@code writeObject} method of the class or
+ * {@code null} if the class does not have a {@code writeObject} method
+ */
+ public final MethodHandle writeObjectForSerialization(Class> cl) {
+ return findReadWriteObjectForSerialization(cl, "writeObject", ObjectOutputStream.class);
+ }
+
+ private final MethodHandle findReadWriteObjectForSerialization(Class> cl,
+ String methodName,
+ Class> streamClass) {
+ if (!Serializable.class.isAssignableFrom(cl)) {
+ return null;
+ }
+
+ try {
+ Method meth = cl.getDeclaredMethod(methodName, streamClass);
+ int mods = meth.getModifiers();
+ if (meth.getReturnType() != Void.TYPE ||
+ Modifier.isStatic(mods) ||
+ !Modifier.isPrivate(mods)) {
+ return null;
+ }
+ meth.setAccessible(true);
+ return MethodHandles.lookup().unreflect(meth);
+ } catch (NoSuchMethodException ex) {
+ return null;
+ } catch (IllegalAccessException ex1) {
+ throw new InternalError("Error", ex1);
+ }
+ }
+
+ /**
+ * Returns a direct MethodHandle for the {@code readResolve} method on
+ * a serializable class.
+ * The single argument of {@link MethodHandle#invoke} is the serializable
+ * object.
+ *
+ * @param cl the Serializable class
+ * @return a direct MethodHandle for the {@code readResolve} method of the class or
+ * {@code null} if the class does not have a {@code readResolve} method
+ */
+ public final MethodHandle readResolveForSerialization(Class> cl) {
+ return getReplaceResolveForSerialization(cl, "readResolve");
+ }
+
+ /**
+ * Returns a direct MethodHandle for the {@code writeReplace} method on
+ * a serializable class.
+ * The single argument of {@link MethodHandle#invoke} is the serializable
+ * object.
+ *
+ * @param cl the Serializable class
+ * @return a direct MethodHandle for the {@code writeReplace} method of the class or
+ * {@code null} if the class does not have a {@code writeReplace} method
+ */
+ public final MethodHandle writeReplaceForSerialization(Class> cl) {
+ return getReplaceResolveForSerialization(cl, "writeReplace");
+ }
+
+ /**
+ * Returns a direct MethodHandle for the {@code writeReplace} method on
+ * a serializable class.
+ * The single argument of {@link MethodHandle#invoke} is the serializable
+ * object.
+ *
+ * @param cl the Serializable class
+ * @return a direct MethodHandle for the {@code writeReplace} method of the class or
+ * {@code null} if the class does not have a {@code writeReplace} method
+ */
+ private MethodHandle getReplaceResolveForSerialization(Class> cl,
+ String methodName) {
+ if (!Serializable.class.isAssignableFrom(cl)) {
+ return null;
+ }
+
+ Class> defCl = cl;
+ while (defCl != null) {
+ try {
+ Method m = defCl.getDeclaredMethod(methodName);
+ if (m.getReturnType() != Object.class) {
+ return null;
+ }
+ int mods = m.getModifiers();
+ if (Modifier.isStatic(mods) | Modifier.isAbstract(mods)) {
+ return null;
+ } else if (Modifier.isPublic(mods) | Modifier.isProtected(mods)) {
+ // fall through
+ } else if (Modifier.isPrivate(mods) && (cl != defCl)) {
+ return null;
+ } else if (!packageEquals(cl, defCl)) {
+ return null;
+ }
+ try {
+ // Normal return
+ m.setAccessible(true);
+ return MethodHandles.lookup().unreflect(m);
+ } catch (IllegalAccessException ex0) {
+ // setAccessible should prevent IAE
+ throw new InternalError("Error", ex0);
+ }
+ } catch (NoSuchMethodException ex) {
+ defCl = defCl.getSuperclass();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if the class has a static initializer.
+ * The presence of a static initializer is used to compute the serialVersionUID.
+ * @param cl a serializable classLook
+ * @return {@code true} if the class has a static initializer,
+ * otherwise {@code false}
+ */
+ public final boolean hasStaticInitializerForSerialization(Class> cl) {
+ Method m = hasStaticInitializerMethod;
+ if (m == null) {
+ try {
+ m = ObjectStreamClass.class.getDeclaredMethod("hasStaticInitializer",
+ new Class>[]{Class.class});
+ m.setAccessible(true);
+ hasStaticInitializerMethod = m;
+ } catch (NoSuchMethodException ex) {
+ throw new InternalError("No such method hasStaticInitializer on "
+ + ObjectStreamClass.class, ex);
+ }
+ }
+ try {
+ return (Boolean) m.invoke(null, cl);
+ } catch (InvocationTargetException | IllegalAccessException ex) {
+ throw new InternalError("Exception invoking hasStaticInitializer", ex);
+ }
+ }
+
+ /**
+ * Returns a new OptionalDataException with {@code eof} set to {@code true}
+ * or {@code false}.
+ * @param bool the value of {@code eof} in the created OptionalDataException
+ * @return a new OptionalDataException
+ */
+ public final OptionalDataException newOptionalDataExceptionForSerialization(boolean bool) {
+ try {
+ Constructor boolCtor =
+ OptionalDataException.class.getDeclaredConstructor(Boolean.TYPE);
+ boolCtor.setAccessible(true);
+ return boolCtor.newInstance(bool);
+ } catch (NoSuchMethodException | InstantiationException|
+ IllegalAccessException|InvocationTargetException ex) {
+ throw new InternalError("unable to create OptionalDataException", ex);
+ }
+ }
+
//--------------------------------------------------------------------------
//
// Internals only below this point
@@ -421,4 +692,17 @@ public class ReflectionFactory {
}
return langReflectAccess;
}
+
+ /**
+ * Returns true if classes are defined in the classloader and same package, false
+ * otherwise.
+ * @param cl1 a class
+ * @param cl2 another class
+ * @returns true if the two classes are in the same classloader and package
+ */
+ private static boolean packageEquals(Class> cl1, Class> cl2) {
+ return cl1.getClassLoader() == cl2.getClassLoader() &&
+ Objects.equals(cl1.getPackage(), cl2.getPackage());
+ }
+
}
diff --git a/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java b/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..68e0d49954c7fad7443d5a6fabb6bbd5ca3011b2
--- /dev/null
+++ b/test/sun/reflect/ReflectionFactory/ReflectionFactoryTest.java
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OptionalDataException;
+import java.io.Serializable;
+import java.lang.invoke.MethodHandle;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import sun.reflect.ReflectionFactory;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import org.testng.TestNG;
+
+/*
+ * @test
+ * @bug 8137058 8164908 8168980
+ * @run testng ReflectionFactoryTest
+ * @run testng/othervm/policy=security.policy ReflectionFactoryTest
+ * @summary Basic test for the unsupported ReflectionFactory
+ */
+
+public class ReflectionFactoryTest {
+
+ // Initialized by init()
+ static ReflectionFactory factory;
+
+ @DataProvider(name = "ClassConstructors")
+ static Object[][] classConstructors() {
+ return new Object[][] {
+ {Object.class},
+ {Foo.class},
+ {Bar.class},
+ };
+ }
+
+ @BeforeClass
+ static void init() {
+ factory = ReflectionFactory.getReflectionFactory();
+ }
+
+ /**
+ * Test that the correct Constructor is selected and run.
+ * @param type type of object to create
+ * @throws NoSuchMethodException - error
+ * @throws InstantiationException - error
+ * @throws IllegalAccessException - error
+ * @throws InvocationTargetException - error
+ */
+ @Test(dataProvider="ClassConstructors")
+ static void testConstructor(Class> type)
+ throws NoSuchMethodException, InstantiationException,
+ IllegalAccessException, InvocationTargetException
+ {
+ @SuppressWarnings("unchecked")
+ Constructor> c = factory.newConstructorForSerialization(type);
+
+ Object o = c.newInstance();
+ Assert.assertEquals(o.getClass(), type, "Instance is wrong type");
+ if (o instanceof Foo) {
+ Foo foo = (Foo)o;
+ foo.check();
+ }
+ }
+
+ @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() {
+ this.foo = 1;
+ }
+
+ public String toString() {
+ return "foo: " + foo;
+ }
+
+ public void check() {
+ int expectedFoo = 1;
+ Assert.assertEquals(foo, expectedFoo, "foo() constructor not run");
+ }
+
+ public int foo() { return foo; }
+ }
+
+ static class Bar extends Foo implements Serializable {
+ private static final long serialVersionUID = 3L;
+
+ private int bar;
+ public Bar() {
+ this.bar = 1;
+ }
+
+ public String toString() {
+ return super.toString() + ", bar: " + bar;
+ }
+
+ public void check() {
+ super.check();
+ int expectedBar = 0;
+ Assert.assertEquals(bar, expectedBar, "bar() constructor not run");
+ }
+ }
+
+ static class Baz extends Foo {
+ private static final long serialVersionUID = 4L;
+
+ 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
+ * @throws InstantiationException - error
+ * @throws IllegalAccessException - error
+ * @throws InvocationTargetException - error
+ */
+ @Test
+ static void newConstructorForExternalization()
+ throws NoSuchMethodException, InstantiationException,
+ IllegalAccessException, InvocationTargetException {
+ Constructor> cons = factory.newConstructorForExternalization(Ext.class);
+ Ext ext = (Ext)cons.newInstance();
+ Assert.assertEquals(ext.ext, 1, "Constructor not run");
+ }
+
+ static class Ext implements Externalizable {
+ private static final long serialVersionUID = 1L;
+
+ int ext;
+
+ public Ext() {
+ ext = 1;
+ }
+
+ @Override
+ public void writeExternal(ObjectOutput out) throws IOException {}
+
+ @Override
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {}
+ }
+
+ @Test
+ static void testReadWriteObjectForSerialization() throws Throwable {
+ MethodHandle readObjectMethod = factory.readObjectForSerialization(Ser.class);
+ Assert.assertNotNull(readObjectMethod, "readObjectMethod not found");
+
+ MethodHandle readObjectNoDataMethod = factory.readObjectNoDataForSerialization(Ser.class);
+ Assert.assertNotNull(readObjectNoDataMethod, "readObjectNoDataMethod not found");
+
+ MethodHandle writeObjectMethod = factory.writeObjectForSerialization(Ser.class);
+ Assert.assertNotNull(writeObjectMethod, "writeObjectMethod not found");
+
+ MethodHandle readResolveMethod = factory.readResolveForSerialization(Ser.class);
+ Assert.assertNotNull(readResolveMethod, "readResolveMethod not found");
+
+ MethodHandle writeReplaceMethod = factory.writeReplaceForSerialization(Ser.class);
+ Assert.assertNotNull(writeReplaceMethod, "writeReplaceMethod not found");
+
+ byte[] data = null;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+ Ser ser = new Ser();
+
+ writeReplaceMethod.invoke(ser);
+ Assert.assertTrue(ser.writeReplaceCalled, "writeReplace not called");
+ Assert.assertFalse(ser.writeObjectCalled, "writeObject should not have been called");
+
+ writeObjectMethod.invoke(ser, oos);
+ Assert.assertTrue(ser.writeReplaceCalled, "writeReplace should have been called");
+ Assert.assertTrue(ser.writeObjectCalled, "writeObject not called");
+ oos.flush();
+ data = baos.toByteArray();
+ }
+
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
+ ObjectInputStream ois = new ObjectInputStream(bais)) {
+ Ser ser2 = new Ser();
+
+ readObjectMethod.invoke(ser2, ois);
+ Assert.assertTrue(ser2.readObjectCalled, "readObject not called");
+ Assert.assertFalse(ser2.readObjectNoDataCalled, "readObjectNoData should not be called");
+ Assert.assertFalse(ser2.readResolveCalled, "readResolve should not be called");
+
+ readObjectNoDataMethod.invoke(ser2, ois);
+ Assert.assertTrue(ser2.readObjectCalled, "readObject should have been called");
+ Assert.assertTrue(ser2.readObjectNoDataCalled, "readObjectNoData not called");
+ Assert.assertFalse(ser2.readResolveCalled, "readResolve should not be called");
+
+ readResolveMethod.invoke(ser2);
+ Assert.assertTrue(ser2.readObjectCalled, "readObject should have been called");
+ Assert.assertTrue(ser2.readObjectNoDataCalled, "readObjectNoData not called");
+ Assert.assertTrue(ser2.readResolveCalled, "readResolve not called");
+ }
+ }
+
+ @Test
+ static void hasStaticInitializer() {
+ boolean actual = factory.hasStaticInitializerForSerialization(Ser.class);
+ Assert.assertTrue(actual, "hasStaticInitializerForSerialization is wrong");
+ }
+
+ static class Ser implements Serializable {
+ private static final long serialVersionUID = 2L;
+ static {
+ // Define a static class initialization method
+ }
+
+ boolean readObjectCalled = false;
+ boolean readObjectNoDataCalled = false;
+ boolean writeObjectCalled = false;
+ boolean readResolveCalled = false;
+ boolean writeReplaceCalled = false;
+
+ public Ser() {}
+
+ private void readObject(ObjectInputStream ois) throws IOException {
+ Assert.assertFalse(writeObjectCalled, "readObject called too many times");
+ readObjectCalled = ois.readBoolean();
+ }
+
+ private void readObjectNoData(ObjectInputStream ois) throws IOException {
+ Assert.assertFalse(readObjectNoDataCalled, "readObjectNoData called too many times");
+ readObjectNoDataCalled = true;
+ }
+
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ Assert.assertFalse(writeObjectCalled, "writeObject called too many times");
+ writeObjectCalled = true;
+ oos.writeBoolean(writeObjectCalled);
+ }
+
+ private Object writeReplace() {
+ Assert.assertFalse(writeReplaceCalled, "writeReplace called too many times");
+ writeReplaceCalled = true;
+ return this;
+ }
+
+ private Object readResolve() {
+ Assert.assertFalse(readResolveCalled, "readResolve called too many times");
+ readResolveCalled = true;
+ return this;
+ }
+ }
+
+ /**
+ * Test the constructor of OptionalDataExceptions.
+ */
+ @Test
+ static void newOptionalDataException() {
+ OptionalDataException ode = factory.newOptionalDataExceptionForSerialization(true);
+ Assert.assertTrue(ode.eof, "eof wrong");
+ ode = factory.newOptionalDataExceptionForSerialization(false);
+ Assert.assertFalse(ode.eof, "eof wrong");
+
+ }
+
+
+
+ // Main can be used to run the tests from the command line with only testng.jar.
+ @SuppressWarnings("raw_types")
+ @Test(enabled = false)
+ public static void main(String[] args) {
+ Class>[] testclass = {ReflectionFactoryTest.class};
+ TestNG testng = new TestNG();
+ testng.setTestClasses(testclass);
+ testng.run();
+ }
+}
diff --git a/test/sun/reflect/ReflectionFactory/security.policy b/test/sun/reflect/ReflectionFactory/security.policy
new file mode 100644
index 0000000000000000000000000000000000000000..8c30f3b278c5913d641cefba5de0805a052e6db8
--- /dev/null
+++ b/test/sun/reflect/ReflectionFactory/security.policy
@@ -0,0 +1,11 @@
+// Individual Permissions for ReflectionFactoryTest
+grant {
+ // Permissions needed to run the test
+ permission java.util.PropertyPermission "*", "read";
+ permission java.io.FilePermission "<>", "read,write,delete,execute";
+
+ permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
+ permission java.lang.RuntimePermission "accessDeclaredMembers";
+ permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect";
+ permission java.lang.RuntimePermission "reflectionFactoryAccess";
+};