ReflectionFactoryTest.java revision 15893:5c851d70cb76
1/*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24import java.io.ByteArrayInputStream;
25import java.io.ByteArrayOutputStream;
26import java.io.Externalizable;
27import java.io.IOException;
28import java.io.ObjectInput;
29import java.io.ObjectInputStream;
30import java.io.ObjectOutput;
31import java.io.ObjectOutputStream;
32import java.io.OptionalDataException;
33import java.io.Serializable;
34import java.lang.invoke.MethodHandle;
35import java.lang.reflect.Constructor;
36import java.lang.reflect.InvocationTargetException;
37
38import sun.reflect.ReflectionFactory;
39
40import org.testng.Assert;
41import org.testng.annotations.BeforeClass;
42import org.testng.annotations.Test;
43import org.testng.annotations.DataProvider;
44import org.testng.TestNG;
45
46/*
47 * @test
48 * @bug 8137058 8164908
49 * @run testng ReflectionFactoryTest
50 * @run testng/othervm/policy=security.policy ReflectionFactoryTest
51 * @summary Basic test for the unsupported ReflectionFactory
52 * @modules jdk.unsupported
53 */
54
55public class ReflectionFactoryTest {
56
57    // Initialized by init()
58    static ReflectionFactory factory;
59
60    @DataProvider(name = "ClassConstructors")
61    static Object[][] classConstructors() {
62        return new Object[][] {
63                {Object.class},
64                {Foo.class},
65                {Bar.class},
66        };
67    }
68
69    @BeforeClass
70    static void init() {
71        factory = ReflectionFactory.getReflectionFactory();
72    }
73
74    /**
75     * Test that the correct Constructor is selected and run.
76     * @param type type of object to create
77     * @throws NoSuchMethodException - error
78     * @throws InstantiationException - error
79     * @throws IllegalAccessException - error
80     * @throws InvocationTargetException - error
81     */
82    @Test(dataProvider="ClassConstructors")
83    static void testConstructor(Class<?> type)
84        throws NoSuchMethodException, InstantiationException,
85            IllegalAccessException, InvocationTargetException
86    {
87        @SuppressWarnings("unchecked")
88        Constructor<?> c = factory.newConstructorForSerialization(type);
89
90        Object o = c.newInstance();
91        Assert.assertEquals(o.getClass(), type, "Instance is wrong type");
92        if (o instanceof Foo) {
93            Foo foo = (Foo)o;
94            foo.check();
95        }
96    }
97
98    static class Foo {
99        private int foo;
100        public Foo() {
101            this.foo = 1;
102        }
103
104        public String toString() {
105            return "foo: " + foo;
106        }
107
108        public void check() {
109            int expectedFoo = 1;
110            Assert.assertEquals(foo, expectedFoo, "foo() constructor not run");
111        }
112    }
113
114    static class Bar extends Foo implements Serializable {
115        private int bar;
116        public Bar() {
117            this.bar = 1;
118        }
119
120        public String toString() {
121            return super.toString() + ", bar: " + bar;
122        }
123
124        public void check() {
125            super.check();
126            int expectedBar = 0;
127            Assert.assertEquals(bar, expectedBar, "bar() constructor not run");
128        }
129    }
130
131    /**
132     * Test newConstructorForExternalization returns the constructor and it can be called.
133     * @throws NoSuchMethodException - error
134     * @throws InstantiationException - error
135     * @throws IllegalAccessException - error
136     * @throws InvocationTargetException - error
137     */
138    @Test
139    static void newConstructorForExternalization()
140            throws NoSuchMethodException, InstantiationException,
141            IllegalAccessException, InvocationTargetException {
142        Constructor<?> cons = factory.newConstructorForExternalization(Ext.class);
143        Ext ext = (Ext)cons.newInstance();
144        Assert.assertEquals(ext.ext, 1, "Constructor not run");
145    }
146
147    static class Ext implements Externalizable {
148        private static final long serialVersionUID = 1L;
149
150        int ext;
151
152        public Ext() {
153            ext = 1;
154        }
155
156        @Override
157        public void writeExternal(ObjectOutput out) throws IOException {}
158
159        @Override
160        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {}
161    }
162
163    @Test
164    static void testReadWriteObjectForSerialization() throws Throwable {
165        MethodHandle readObjectMethod = factory.readObjectForSerialization(Ser.class);
166        Assert.assertNotNull(readObjectMethod, "readObjectMethod not found");
167
168        MethodHandle readObjectNoDataMethod = factory.readObjectNoDataForSerialization(Ser.class);
169        Assert.assertNotNull(readObjectNoDataMethod, "readObjectNoDataMethod not found");
170
171        MethodHandle writeObjectMethod = factory.writeObjectForSerialization(Ser.class);
172        Assert.assertNotNull(writeObjectMethod, "writeObjectMethod not found");
173
174        MethodHandle readResolveMethod = factory.readResolveForSerialization(Ser.class);
175        Assert.assertNotNull(readResolveMethod, "readResolveMethod not found");
176
177        MethodHandle writeReplaceMethod = factory.writeReplaceForSerialization(Ser.class);
178        Assert.assertNotNull(writeReplaceMethod, "writeReplaceMethod not found");
179
180        byte[] data = null;
181        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
182            ObjectOutputStream oos = new ObjectOutputStream(baos)) {
183            Ser ser = new Ser();
184
185            writeReplaceMethod.invoke(ser);
186            Assert.assertTrue(ser.writeReplaceCalled, "writeReplace not called");
187            Assert.assertFalse(ser.writeObjectCalled, "writeObject should not have been called");
188
189            writeObjectMethod.invoke(ser, oos);
190            Assert.assertTrue(ser.writeReplaceCalled, "writeReplace should have been called");
191            Assert.assertTrue(ser.writeObjectCalled, "writeObject not called");
192            oos.flush();
193            data = baos.toByteArray();
194        }
195
196        try (ByteArrayInputStream bais = new ByteArrayInputStream(data);
197             ObjectInputStream ois = new ObjectInputStream(bais)) {
198            Ser ser2 = new Ser();
199
200            readObjectMethod.invoke(ser2, ois);
201            Assert.assertTrue(ser2.readObjectCalled, "readObject not called");
202            Assert.assertFalse(ser2.readObjectNoDataCalled, "readObjectNoData should not be called");
203            Assert.assertFalse(ser2.readResolveCalled, "readResolve should not be called");
204
205            readObjectNoDataMethod.invoke(ser2, ois);
206            Assert.assertTrue(ser2.readObjectCalled, "readObject should have been called");
207            Assert.assertTrue(ser2.readObjectNoDataCalled, "readObjectNoData not called");
208            Assert.assertFalse(ser2.readResolveCalled, "readResolve should not be called");
209
210            readResolveMethod.invoke(ser2);
211            Assert.assertTrue(ser2.readObjectCalled, "readObject should have been called");
212            Assert.assertTrue(ser2.readObjectNoDataCalled, "readObjectNoData not called");
213            Assert.assertTrue(ser2.readResolveCalled, "readResolve not called");
214        }
215    }
216
217    @Test
218    static void hasStaticInitializer() {
219        boolean actual = factory.hasStaticInitializerForSerialization(Ser.class);
220        Assert.assertTrue(actual, "hasStaticInitializerForSerialization is wrong");
221    }
222
223    static class Ser implements Serializable {
224        private static final long serialVersionUID = 2L;
225        static {
226            // Define a static class initialization method
227        }
228
229        boolean readObjectCalled = false;
230        boolean readObjectNoDataCalled = false;
231        boolean writeObjectCalled = false;
232        boolean readResolveCalled = false;
233        boolean writeReplaceCalled = false;
234
235        public Ser() {}
236
237        private void readObject(ObjectInputStream ois) throws IOException {
238            Assert.assertFalse(writeObjectCalled, "readObject called too many times");
239            readObjectCalled = ois.readBoolean();
240        }
241
242        private void readObjectNoData(ObjectInputStream ois) throws IOException {
243            Assert.assertFalse(readObjectNoDataCalled, "readObjectNoData called too many times");
244            readObjectNoDataCalled = true;
245        }
246
247        private void writeObject(ObjectOutputStream oos) throws IOException {
248            Assert.assertFalse(writeObjectCalled, "writeObject called too many times");
249            writeObjectCalled = true;
250            oos.writeBoolean(writeObjectCalled);
251        }
252
253        private Object writeReplace() {
254            Assert.assertFalse(writeReplaceCalled, "writeReplace called too many times");
255            writeReplaceCalled = true;
256            return this;
257        }
258
259        private Object readResolve() {
260            Assert.assertFalse(readResolveCalled, "readResolve called too many times");
261            readResolveCalled = true;
262            return this;
263        }
264    }
265
266    /**
267     * Test the constructor of OptionalDataExceptions.
268     */
269    @Test
270    static void newOptionalDataException() {
271        OptionalDataException ode = factory.newOptionalDataExceptionForSerialization(true);
272        Assert.assertTrue(ode.eof, "eof wrong");
273        ode = factory.newOptionalDataExceptionForSerialization(false);
274        Assert.assertFalse(ode.eof, "eof wrong");
275
276    }
277
278
279
280    // Main can be used to run the tests from the command line with only testng.jar.
281    @SuppressWarnings("raw_types")
282    @Test(enabled = false)
283    public static void main(String[] args) {
284        Class<?>[] testclass = {ReflectionFactoryTest.class};
285        TestNG testng = new TestNG();
286        testng.setTestClasses(testclass);
287        testng.run();
288    }
289}
290