ReflectionFactory.java revision 15893:5c851d70cb76
1230557Sjimharris/*
2230557Sjimharris * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
3230557Sjimharris * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4230557Sjimharris *
5230557Sjimharris * This code is free software; you can redistribute it and/or modify it
6230557Sjimharris * under the terms of the GNU General Public License version 2 only, as
7230557Sjimharris * published by the Free Software Foundation.  Oracle designates this
8230557Sjimharris * particular file as subject to the "Classpath" exception as provided
9230557Sjimharris * by Oracle in the LICENSE file that accompanied this code.
10230557Sjimharris *
11230557Sjimharris * This code is distributed in the hope that it will be useful, but WITHOUT
12230557Sjimharris * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13230557Sjimharris * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14230557Sjimharris * version 2 for more details (a copy is included in the LICENSE file that
15230557Sjimharris * accompanied this code).
16230557Sjimharris *
17230557Sjimharris * You should have received a copy of the GNU General Public License version
18230557Sjimharris * 2 along with this work; if not, write to the Free Software Foundation,
19230557Sjimharris * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20230557Sjimharris *
21230557Sjimharris * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22230557Sjimharris * or visit www.oracle.com if you need additional information or have any
23230557Sjimharris * questions.
24230557Sjimharris */
25230557Sjimharris
26230557Sjimharrispackage jdk.internal.reflect;
27230557Sjimharris
28230557Sjimharrisimport java.io.Externalizable;
29230557Sjimharrisimport java.io.ObjectInputStream;
30230557Sjimharrisimport java.io.ObjectOutputStream;
31230557Sjimharrisimport java.io.ObjectStreamClass;
32230557Sjimharrisimport java.io.OptionalDataException;
33230557Sjimharrisimport java.io.Serializable;
34230557Sjimharrisimport java.lang.invoke.MethodHandle;
35230557Sjimharrisimport java.lang.invoke.MethodHandles;
36230557Sjimharrisimport java.lang.reflect.Field;
37230557Sjimharrisimport java.lang.reflect.Executable;
38230557Sjimharrisimport java.lang.reflect.InvocationTargetException;
39230557Sjimharrisimport java.lang.reflect.Method;
40230557Sjimharrisimport java.lang.reflect.Constructor;
41230557Sjimharrisimport java.lang.reflect.Modifier;
42230557Sjimharrisimport java.security.Permission;
43230557Sjimharrisimport java.security.PrivilegedAction;
44230557Sjimharrisimport java.util.Objects;
45230557Sjimharrisimport java.util.Properties;
46230557Sjimharris
47230557Sjimharrisimport sun.reflect.misc.ReflectUtil;
48230557Sjimharrisimport sun.security.action.GetPropertyAction;
49230557Sjimharris
50230557Sjimharris/** <P> The master factory for all reflective objects, both those in
51230557Sjimharris    java.lang.reflect (Fields, Methods, Constructors) as well as their
52230557Sjimharris    delegates (FieldAccessors, MethodAccessors, ConstructorAccessors).
53230557Sjimharris    </P>
54230557Sjimharris
55230557Sjimharris    <P> The methods in this class are extremely unsafe and can cause
56230557Sjimharris    subversion of both the language and the verifier. For this reason,
57230557Sjimharris    they are all instance methods, and access to the constructor of
58230557Sjimharris    this factory is guarded by a security check, in similar style to
59230557Sjimharris    {@link jdk.internal.misc.Unsafe}. </P>
60230557Sjimharris*/
61230557Sjimharris
62230557Sjimharrispublic class ReflectionFactory {
63230557Sjimharris
64230557Sjimharris    private static boolean initted = false;
65230557Sjimharris    private static final Permission reflectionFactoryAccessPerm
66230557Sjimharris        = new RuntimePermission("reflectionFactoryAccess");
67230557Sjimharris    private static final ReflectionFactory soleInstance = new ReflectionFactory();
68230557Sjimharris    // Provides access to package-private mechanisms in java.lang.reflect
69230557Sjimharris    private static volatile LangReflectAccess langReflectAccess;
70230557Sjimharris
71230557Sjimharris    /* Method for static class initializer <clinit>, or null */
72230557Sjimharris    private static volatile Method hasStaticInitializerMethod;
73230557Sjimharris
74230557Sjimharris    //
75230557Sjimharris    // "Inflation" mechanism. Loading bytecodes to implement
76230557Sjimharris    // Method.invoke() and Constructor.newInstance() currently costs
77230557Sjimharris    // 3-4x more than an invocation via native code for the first
78230557Sjimharris    // invocation (though subsequent invocations have been benchmarked
79230557Sjimharris    // to be over 20x faster). Unfortunately this cost increases
80230557Sjimharris    // startup time for certain applications that use reflection
81230557Sjimharris    // intensively (but only once per class) to bootstrap themselves.
82230557Sjimharris    // To avoid this penalty we reuse the existing JVM entry points
83230557Sjimharris    // for the first few invocations of Methods and Constructors and
84230557Sjimharris    // then switch to the bytecode-based implementations.
85230557Sjimharris    //
86230557Sjimharris    // Package-private to be accessible to NativeMethodAccessorImpl
87230557Sjimharris    // and NativeConstructorAccessorImpl
88230557Sjimharris    private static boolean noInflation        = false;
89230557Sjimharris    private static int     inflationThreshold = 15;
90230557Sjimharris
91230557Sjimharris    private ReflectionFactory() {
92230557Sjimharris    }
93230557Sjimharris
94230557Sjimharris    /**
95230557Sjimharris     * A convenience class for acquiring the capability to instantiate
96230557Sjimharris     * reflective objects.  Use this instead of a raw call to {@link
97230557Sjimharris     * #getReflectionFactory} in order to avoid being limited by the
98230557Sjimharris     * permissions of your callers.
99230557Sjimharris     *
100230557Sjimharris     * <p>An instance of this class can be used as the argument of
101230557Sjimharris     * <code>AccessController.doPrivileged</code>.
102230557Sjimharris     */
103230557Sjimharris    public static final class GetReflectionFactoryAction
104230557Sjimharris        implements PrivilegedAction<ReflectionFactory> {
105230557Sjimharris        public ReflectionFactory run() {
106230557Sjimharris            return getReflectionFactory();
107230557Sjimharris        }
108230557Sjimharris    }
109230557Sjimharris
110230557Sjimharris    /**
111230557Sjimharris     * Provides the caller with the capability to instantiate reflective
112230557Sjimharris     * objects.
113230557Sjimharris     *
114230557Sjimharris     * <p> First, if there is a security manager, its
115230557Sjimharris     * <code>checkPermission</code> method is called with a {@link
116230557Sjimharris     * java.lang.RuntimePermission} with target
117230557Sjimharris     * <code>"reflectionFactoryAccess"</code>.  This may result in a
118230557Sjimharris     * security exception.
119230557Sjimharris     *
120230557Sjimharris     * <p> The returned <code>ReflectionFactory</code> object should be
121230557Sjimharris     * carefully guarded by the caller, since it can be used to read and
122230557Sjimharris     * write private data and invoke private methods, as well as to load
123230557Sjimharris     * unverified bytecodes.  It must never be passed to untrusted code.
124230557Sjimharris     *
125230557Sjimharris     * @exception SecurityException if a security manager exists and its
126230557Sjimharris     *             <code>checkPermission</code> method doesn't allow
127230557Sjimharris     *             access to the RuntimePermission "reflectionFactoryAccess".  */
128230557Sjimharris    public static ReflectionFactory getReflectionFactory() {
129230557Sjimharris        SecurityManager security = System.getSecurityManager();
130230557Sjimharris        if (security != null) {
131230557Sjimharris            // TO DO: security.checkReflectionFactoryAccess();
132230557Sjimharris            security.checkPermission(reflectionFactoryAccessPerm);
133230557Sjimharris        }
134230557Sjimharris        return soleInstance;
135230557Sjimharris    }
136230557Sjimharris
137230557Sjimharris    //--------------------------------------------------------------------------
138230557Sjimharris    //
139230557Sjimharris    // Routines used by java.lang.reflect
140230557Sjimharris    //
141230557Sjimharris    //
142230557Sjimharris
143230557Sjimharris    /** Called only by java.lang.reflect.Modifier's static initializer */
144230557Sjimharris    public void setLangReflectAccess(LangReflectAccess access) {
145230557Sjimharris        langReflectAccess = access;
146230557Sjimharris    }
147230557Sjimharris
148230557Sjimharris    /**
149230557Sjimharris     * Note: this routine can cause the declaring class for the field
150230557Sjimharris     * be initialized and therefore must not be called until the
151230557Sjimharris     * first get/set of this field.
152230557Sjimharris     * @param field the field
153230557Sjimharris     * @param override true if caller has overridden accessibility
154230557Sjimharris     */
155230557Sjimharris    public FieldAccessor newFieldAccessor(Field field, boolean override) {
156230557Sjimharris        checkInitted();
157230557Sjimharris        return UnsafeFieldAccessorFactory.newFieldAccessor(field, override);
158230557Sjimharris    }
159230557Sjimharris
160230557Sjimharris    public MethodAccessor newMethodAccessor(Method method) {
161230557Sjimharris        checkInitted();
162230557Sjimharris
163230557Sjimharris        if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) {
164230557Sjimharris            return new MethodAccessorGenerator().
165230557Sjimharris                generateMethod(method.getDeclaringClass(),
166230557Sjimharris                               method.getName(),
167230557Sjimharris                               method.getParameterTypes(),
168230557Sjimharris                               method.getReturnType(),
169230557Sjimharris                               method.getExceptionTypes(),
170230557Sjimharris                               method.getModifiers());
171230557Sjimharris        } else {
172230557Sjimharris            NativeMethodAccessorImpl acc =
173230557Sjimharris                new NativeMethodAccessorImpl(method);
174230557Sjimharris            DelegatingMethodAccessorImpl res =
175230557Sjimharris                new DelegatingMethodAccessorImpl(acc);
176230557Sjimharris            acc.setParent(res);
177230557Sjimharris            return res;
178230557Sjimharris        }
179230557Sjimharris    }
180230557Sjimharris
181230557Sjimharris    public ConstructorAccessor newConstructorAccessor(Constructor<?> c) {
182230557Sjimharris        checkInitted();
183230557Sjimharris
184230557Sjimharris        Class<?> declaringClass = c.getDeclaringClass();
185230557Sjimharris        if (Modifier.isAbstract(declaringClass.getModifiers())) {
186230557Sjimharris            return new InstantiationExceptionConstructorAccessorImpl(null);
187230557Sjimharris        }
188230557Sjimharris        if (declaringClass == Class.class) {
189230557Sjimharris            return new InstantiationExceptionConstructorAccessorImpl
190230557Sjimharris                ("Can not instantiate java.lang.Class");
191230557Sjimharris        }
192230557Sjimharris        // Bootstrapping issue: since we use Class.newInstance() in
193230557Sjimharris        // the ConstructorAccessor generation process, we have to
194230557Sjimharris        // break the cycle here.
195230557Sjimharris        if (Reflection.isSubclassOf(declaringClass,
196230557Sjimharris                                    ConstructorAccessorImpl.class)) {
197230557Sjimharris            return new BootstrapConstructorAccessorImpl(c);
198230557Sjimharris        }
199230557Sjimharris
200230557Sjimharris        if (noInflation && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) {
201230557Sjimharris            return new MethodAccessorGenerator().
202230557Sjimharris                generateConstructor(c.getDeclaringClass(),
203230557Sjimharris                                    c.getParameterTypes(),
204230557Sjimharris                                    c.getExceptionTypes(),
205230557Sjimharris                                    c.getModifiers());
206230557Sjimharris        } else {
207230557Sjimharris            NativeConstructorAccessorImpl acc =
208230557Sjimharris                new NativeConstructorAccessorImpl(c);
209230557Sjimharris            DelegatingConstructorAccessorImpl res =
210230557Sjimharris                new DelegatingConstructorAccessorImpl(acc);
211230557Sjimharris            acc.setParent(res);
212230557Sjimharris            return res;
213230557Sjimharris        }
214230557Sjimharris    }
215230557Sjimharris
216230557Sjimharris    //--------------------------------------------------------------------------
217230557Sjimharris    //
218230557Sjimharris    // Routines used by java.lang
219230557Sjimharris    //
220230557Sjimharris    //
221230557Sjimharris
222230557Sjimharris    /** Creates a new java.lang.reflect.Field. Access checks as per
223230557Sjimharris        java.lang.reflect.AccessibleObject are not overridden. */
224230557Sjimharris    public Field newField(Class<?> declaringClass,
225230557Sjimharris                          String name,
226230557Sjimharris                          Class<?> type,
227230557Sjimharris                          int modifiers,
228230557Sjimharris                          int slot,
229230557Sjimharris                          String signature,
230230557Sjimharris                          byte[] annotations)
231230557Sjimharris    {
232230557Sjimharris        return langReflectAccess().newField(declaringClass,
233230557Sjimharris                                            name,
234230557Sjimharris                                            type,
235230557Sjimharris                                            modifiers,
236230557Sjimharris                                            slot,
237230557Sjimharris                                            signature,
238230557Sjimharris                                            annotations);
239230557Sjimharris    }
240230557Sjimharris
241230557Sjimharris    /** Creates a new java.lang.reflect.Method. Access checks as per
242230557Sjimharris        java.lang.reflect.AccessibleObject are not overridden. */
243230557Sjimharris    public Method newMethod(Class<?> declaringClass,
244230557Sjimharris                            String name,
245230557Sjimharris                            Class<?>[] parameterTypes,
246230557Sjimharris                            Class<?> returnType,
247230557Sjimharris                            Class<?>[] checkedExceptions,
248230557Sjimharris                            int modifiers,
249230557Sjimharris                            int slot,
250230557Sjimharris                            String signature,
251230557Sjimharris                            byte[] annotations,
252230557Sjimharris                            byte[] parameterAnnotations,
253230557Sjimharris                            byte[] annotationDefault)
254230557Sjimharris    {
255230557Sjimharris        return langReflectAccess().newMethod(declaringClass,
256230557Sjimharris                                             name,
257230557Sjimharris                                             parameterTypes,
258230557Sjimharris                                             returnType,
259230557Sjimharris                                             checkedExceptions,
260230557Sjimharris                                             modifiers,
261230557Sjimharris                                             slot,
262230557Sjimharris                                             signature,
263230557Sjimharris                                             annotations,
264230557Sjimharris                                             parameterAnnotations,
265230557Sjimharris                                             annotationDefault);
266230557Sjimharris    }
267230557Sjimharris
268230557Sjimharris    /** Creates a new java.lang.reflect.Constructor. Access checks as
269230557Sjimharris        per java.lang.reflect.AccessibleObject are not overridden. */
270230557Sjimharris    public Constructor<?> newConstructor(Class<?> declaringClass,
271230557Sjimharris                                         Class<?>[] parameterTypes,
272230557Sjimharris                                         Class<?>[] checkedExceptions,
273230557Sjimharris                                         int modifiers,
274230557Sjimharris                                         int slot,
275230557Sjimharris                                         String signature,
276230557Sjimharris                                         byte[] annotations,
277230557Sjimharris                                         byte[] parameterAnnotations)
278230557Sjimharris    {
279230557Sjimharris        return langReflectAccess().newConstructor(declaringClass,
280230557Sjimharris                                                  parameterTypes,
281230557Sjimharris                                                  checkedExceptions,
282230557Sjimharris                                                  modifiers,
283230557Sjimharris                                                  slot,
284230557Sjimharris                                                  signature,
285230557Sjimharris                                                  annotations,
286230557Sjimharris                                                  parameterAnnotations);
287230557Sjimharris    }
288230557Sjimharris
289230557Sjimharris    /** Gets the MethodAccessor object for a java.lang.reflect.Method */
290230557Sjimharris    public MethodAccessor getMethodAccessor(Method m) {
291230557Sjimharris        return langReflectAccess().getMethodAccessor(m);
292230557Sjimharris    }
293230557Sjimharris
294230557Sjimharris    /** Sets the MethodAccessor object for a java.lang.reflect.Method */
295230557Sjimharris    public void setMethodAccessor(Method m, MethodAccessor accessor) {
296230557Sjimharris        langReflectAccess().setMethodAccessor(m, accessor);
297230557Sjimharris    }
298230557Sjimharris
299230557Sjimharris    /** Gets the ConstructorAccessor object for a
300230557Sjimharris        java.lang.reflect.Constructor */
301230557Sjimharris    public ConstructorAccessor getConstructorAccessor(Constructor<?> c) {
302230557Sjimharris        return langReflectAccess().getConstructorAccessor(c);
303230557Sjimharris    }
304230557Sjimharris
305230557Sjimharris    /** Sets the ConstructorAccessor object for a
306230557Sjimharris        java.lang.reflect.Constructor */
307230557Sjimharris    public void setConstructorAccessor(Constructor<?> c,
308230557Sjimharris                                       ConstructorAccessor accessor)
309230557Sjimharris    {
310230557Sjimharris        langReflectAccess().setConstructorAccessor(c, accessor);
311230557Sjimharris    }
312230557Sjimharris
313230557Sjimharris    /** Makes a copy of the passed method. The returned method is a
314230557Sjimharris        "child" of the passed one; see the comments in Method.java for
315230557Sjimharris        details. */
316230557Sjimharris    public Method copyMethod(Method arg) {
317230557Sjimharris        return langReflectAccess().copyMethod(arg);
318230557Sjimharris    }
319230557Sjimharris
320230557Sjimharris    /** Makes a copy of the passed method. The returned method is NOT
321230557Sjimharris     * a "child" but a "sibling" of the Method in arg. Should only be
322230557Sjimharris     * used on non-root methods. */
323230557Sjimharris    public Method leafCopyMethod(Method arg) {
324230557Sjimharris        return langReflectAccess().leafCopyMethod(arg);
325230557Sjimharris    }
326230557Sjimharris
327230557Sjimharris
328230557Sjimharris    /** Makes a copy of the passed field. The returned field is a
329230557Sjimharris        "child" of the passed one; see the comments in Field.java for
330230557Sjimharris        details. */
331230557Sjimharris    public Field copyField(Field arg) {
332230557Sjimharris        return langReflectAccess().copyField(arg);
333230557Sjimharris    }
334230557Sjimharris
335230557Sjimharris    /** Makes a copy of the passed constructor. The returned
336230557Sjimharris        constructor is a "child" of the passed one; see the comments
337230557Sjimharris        in Constructor.java for details. */
338230557Sjimharris    public <T> Constructor<T> copyConstructor(Constructor<T> arg) {
339230557Sjimharris        return langReflectAccess().copyConstructor(arg);
340230557Sjimharris    }
341230557Sjimharris
342230557Sjimharris    /** Gets the byte[] that encodes TypeAnnotations on an executable.
343230557Sjimharris     */
344230557Sjimharris    public byte[] getExecutableTypeAnnotationBytes(Executable ex) {
345230557Sjimharris        return langReflectAccess().getExecutableTypeAnnotationBytes(ex);
346230557Sjimharris    }
347230557Sjimharris
348230557Sjimharris    //--------------------------------------------------------------------------
349230557Sjimharris    //
350230557Sjimharris    // Routines used by serialization
351230557Sjimharris    //
352230557Sjimharris    //
353230557Sjimharris
354230557Sjimharris    public final Constructor<?> newConstructorForExternalization(Class<?> cl) {
355230557Sjimharris        if (!Externalizable.class.isAssignableFrom(cl)) {
356230557Sjimharris            return null;
357230557Sjimharris        }
358230557Sjimharris        try {
359230557Sjimharris            Constructor<?> cons = cl.getConstructor();
360230557Sjimharris            cons.setAccessible(true);
361230557Sjimharris            return cons;
362230557Sjimharris        } catch (NoSuchMethodException ex) {
363230557Sjimharris            return null;
364230557Sjimharris        }
365230557Sjimharris    }
366230557Sjimharris
367230557Sjimharris    public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
368230557Sjimharris        Class<?> initCl = cl;
369230557Sjimharris        while (Serializable.class.isAssignableFrom(initCl)) {
370230557Sjimharris            if ((initCl = initCl.getSuperclass()) == null) {
371230557Sjimharris                return null;
372230557Sjimharris            }
373230557Sjimharris        }
374230557Sjimharris        Constructor<?> constructorToCall;
375230557Sjimharris        try {
376230557Sjimharris            constructorToCall = initCl.getDeclaredConstructor();
377230557Sjimharris            int mods = constructorToCall.getModifiers();
378230557Sjimharris            if ((mods & Modifier.PRIVATE) != 0 ||
379230557Sjimharris                    ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
380230557Sjimharris                            !packageEquals(cl, initCl))) {
381230557Sjimharris                return null;
382230557Sjimharris            }
383230557Sjimharris        } catch (NoSuchMethodException ex) {
384230557Sjimharris            return null;
385230557Sjimharris        }
386230557Sjimharris
387230557Sjimharris        ConstructorAccessor acc = new MethodAccessorGenerator().
388230557Sjimharris            generateSerializationConstructor(cl,
389230557Sjimharris                                             constructorToCall.getParameterTypes(),
390230557Sjimharris                                             constructorToCall.getExceptionTypes(),
391230557Sjimharris                                             constructorToCall.getModifiers(),
392230557Sjimharris                                             constructorToCall.getDeclaringClass());
393230557Sjimharris        Constructor<?> c = newConstructor(constructorToCall.getDeclaringClass(),
394230557Sjimharris                                          constructorToCall.getParameterTypes(),
395230557Sjimharris                                          constructorToCall.getExceptionTypes(),
396230557Sjimharris                                          constructorToCall.getModifiers(),
397230557Sjimharris                                          langReflectAccess().
398230557Sjimharris                                          getConstructorSlot(constructorToCall),
399230557Sjimharris                                          langReflectAccess().
400230557Sjimharris                                          getConstructorSignature(constructorToCall),
401230557Sjimharris                                          langReflectAccess().
402230557Sjimharris                                          getConstructorAnnotations(constructorToCall),
403230557Sjimharris                                          langReflectAccess().
404230557Sjimharris                                          getConstructorParameterAnnotations(constructorToCall));
405230557Sjimharris        setConstructorAccessor(c, acc);
406230557Sjimharris        c.setAccessible(true);
407230557Sjimharris        return c;
408230557Sjimharris    }
409230557Sjimharris
410230557Sjimharris    public final MethodHandle readObjectForSerialization(Class<?> cl) {
411230557Sjimharris        return findReadWriteObjectForSerialization(cl, "readObject", ObjectInputStream.class);
412230557Sjimharris    }
413230557Sjimharris
414230557Sjimharris    public final MethodHandle readObjectNoDataForSerialization(Class<?> cl) {
415230557Sjimharris        return findReadWriteObjectForSerialization(cl, "readObjectNoData", ObjectInputStream.class);
416230557Sjimharris    }
417230557Sjimharris
418230557Sjimharris    public final MethodHandle writeObjectForSerialization(Class<?> cl) {
419230557Sjimharris        return findReadWriteObjectForSerialization(cl, "writeObject", ObjectOutputStream.class);
420230557Sjimharris    }
421230557Sjimharris
422230557Sjimharris    private final MethodHandle findReadWriteObjectForSerialization(Class<?> cl,
423230557Sjimharris                                                                   String methodName,
424230557Sjimharris                                                                   Class<?> streamClass) {
425230557Sjimharris        if (!Serializable.class.isAssignableFrom(cl)) {
426230557Sjimharris            return null;
427230557Sjimharris        }
428230557Sjimharris
429230557Sjimharris        try {
430230557Sjimharris            Method meth = cl.getDeclaredMethod(methodName, streamClass);
431230557Sjimharris            int mods = meth.getModifiers();
432230557Sjimharris            if (meth.getReturnType() != Void.TYPE ||
433230557Sjimharris                    Modifier.isStatic(mods) ||
434230557Sjimharris                    !Modifier.isPrivate(mods)) {
435230557Sjimharris                return null;
436230557Sjimharris            }
437230557Sjimharris            meth.setAccessible(true);
438230557Sjimharris            return MethodHandles.lookup().unreflect(meth);
439230557Sjimharris        } catch (NoSuchMethodException ex) {
440230557Sjimharris            return null;
441230557Sjimharris        } catch (IllegalAccessException ex1) {
442230557Sjimharris            throw new InternalError("Error", ex1);
443230557Sjimharris        }
444230557Sjimharris    }
445230557Sjimharris
446230557Sjimharris    /**
447230557Sjimharris     * Returns a MethodHandle for {@code writeReplace} on the serializable class
448230557Sjimharris     * or null if no match found.
449230557Sjimharris     * @param cl a serializable class
450230557Sjimharris     * @returnss the {@code writeReplace} MethodHandle or {@code null} if not found
451230557Sjimharris     */
452230557Sjimharris    public final MethodHandle writeReplaceForSerialization(Class<?> cl) {
453230557Sjimharris        return getReplaceResolveForSerialization(cl, "writeReplace");
454230557Sjimharris    }
455230557Sjimharris
456230557Sjimharris    /**
457230557Sjimharris     * Returns a MethodHandle for {@code readResolve} on the serializable class
458230557Sjimharris     * or null if no match found.
459230557Sjimharris     * @param cl a serializable class
460230557Sjimharris     * @returns the {@code writeReplace} MethodHandle or {@code null} if not found
461230557Sjimharris     */
462230557Sjimharris    public final MethodHandle readResolveForSerialization(Class<?> cl) {
463230557Sjimharris        return getReplaceResolveForSerialization(cl, "readResolve");
464230557Sjimharris    }
465230557Sjimharris
466230557Sjimharris    /**
467230557Sjimharris     * Lookup readResolve or writeReplace on a class with specified
468230557Sjimharris     * signature constraints.
469230557Sjimharris     * @param cl a serializable class
470230557Sjimharris     * @param methodName the method name to find
471230557Sjimharris     * @returns a MethodHandle for the method or {@code null} if not found or
472230557Sjimharris     *       has the wrong signature.
473230557Sjimharris     */
474230557Sjimharris    private MethodHandle getReplaceResolveForSerialization(Class<?> cl,
475230557Sjimharris                                                           String methodName) {
476230557Sjimharris        if (!Serializable.class.isAssignableFrom(cl)) {
477230557Sjimharris            return null;
478230557Sjimharris        }
479230557Sjimharris
480230557Sjimharris        Class<?> defCl = cl;
481230557Sjimharris        while (defCl != null) {
482230557Sjimharris            try {
483230557Sjimharris                Method m = defCl.getDeclaredMethod(methodName);
484230557Sjimharris                if (m.getReturnType() != Object.class) {
485230557Sjimharris                    return null;
486230557Sjimharris                }
487230557Sjimharris                int mods = m.getModifiers();
488230557Sjimharris                if (Modifier.isStatic(mods) | Modifier.isAbstract(mods)) {
489230557Sjimharris                    return null;
490230557Sjimharris                } else if (Modifier.isPublic(mods) | Modifier.isProtected(mods)) {
491230557Sjimharris                    // fall through
492230557Sjimharris                } else if (Modifier.isPrivate(mods) && (cl != defCl)) {
493230557Sjimharris                    return null;
494230557Sjimharris                } else if (!packageEquals(cl, defCl)) {
495230557Sjimharris                    return null;
496230557Sjimharris                }
497230557Sjimharris                try {
498230557Sjimharris                    // Normal return
499230557Sjimharris                    m.setAccessible(true);
500230557Sjimharris                    return MethodHandles.lookup().unreflect(m);
501230557Sjimharris                } catch (IllegalAccessException ex0) {
502230557Sjimharris                    // setAccessible should prevent IAE
503230557Sjimharris                    throw new InternalError("Error", ex0);
504230557Sjimharris                }
505230557Sjimharris            } catch (NoSuchMethodException ex) {
506230557Sjimharris                defCl = defCl.getSuperclass();
507230557Sjimharris            }
508230557Sjimharris        }
509230557Sjimharris        return null;
510230557Sjimharris    }
511230557Sjimharris
512230557Sjimharris    /**
513230557Sjimharris     * Returns true if the given class defines a static initializer method,
514230557Sjimharris     * false otherwise.
515230557Sjimharris     */
516230557Sjimharris    public final boolean hasStaticInitializerForSerialization(Class<?> cl) {
517230557Sjimharris        Method m = hasStaticInitializerMethod;
518230557Sjimharris        if (m == null) {
519230557Sjimharris            try {
520230557Sjimharris                m = ObjectStreamClass.class.getDeclaredMethod("hasStaticInitializer",
521230557Sjimharris                        new Class<?>[]{Class.class});
522230557Sjimharris                m.setAccessible(true);
523230557Sjimharris                hasStaticInitializerMethod = m;
524230557Sjimharris            } catch (NoSuchMethodException ex) {
525230557Sjimharris                throw new InternalError("No such method hasStaticInitializer on "
526230557Sjimharris                        + ObjectStreamClass.class, ex);
527230557Sjimharris            }
528230557Sjimharris        }
529230557Sjimharris        try {
530230557Sjimharris            return (Boolean) m.invoke(null, cl);
531230557Sjimharris        } catch (InvocationTargetException | IllegalAccessException ex) {
532230557Sjimharris            throw new InternalError("Exception invoking hasStaticInitializer", ex);
533230557Sjimharris        }
534230557Sjimharris    }
535230557Sjimharris
536230557Sjimharris    /**
537230557Sjimharris     * Return the accessible constructor for OptionalDataException signaling eof.
538230557Sjimharris     * @returns the eof constructor for OptionalDataException
539230557Sjimharris     */
540230557Sjimharris    public final Constructor<OptionalDataException> newOptionalDataExceptionForSerialization() {
541230557Sjimharris        try {
542230557Sjimharris            Constructor<OptionalDataException> boolCtor =
543230557Sjimharris                    OptionalDataException.class.getDeclaredConstructor(Boolean.TYPE);
544230557Sjimharris            boolCtor.setAccessible(true);
545230557Sjimharris            return boolCtor;
546230557Sjimharris        } catch (NoSuchMethodException ex) {
547230557Sjimharris            throw new InternalError("Constructor not found", ex);
548230557Sjimharris        }
549230557Sjimharris    }
550230557Sjimharris
551230557Sjimharris    //--------------------------------------------------------------------------
552230557Sjimharris    //
553230557Sjimharris    // Internals only below this point
554230557Sjimharris    //
555230557Sjimharris
556230557Sjimharris    static int inflationThreshold() {
557230557Sjimharris        return inflationThreshold;
558230557Sjimharris    }
559230557Sjimharris
560230557Sjimharris    /** We have to defer full initialization of this class until after
561230557Sjimharris        the static initializer is run since java.lang.reflect.Method's
562230557Sjimharris        static initializer (more properly, that for
563230557Sjimharris        java.lang.reflect.AccessibleObject) causes this class's to be
564230557Sjimharris        run, before the system properties are set up. */
565230557Sjimharris    private static void checkInitted() {
566230557Sjimharris        if (initted) return;
567230557Sjimharris
568230557Sjimharris        // Tests to ensure the system properties table is fully
569230557Sjimharris        // initialized. This is needed because reflection code is
570230557Sjimharris        // called very early in the initialization process (before
571230557Sjimharris        // command-line arguments have been parsed and therefore
572230557Sjimharris        // these user-settable properties installed.) We assume that
573230557Sjimharris        // if System.out is non-null then the System class has been
574230557Sjimharris        // fully initialized and that the bulk of the startup code
575230557Sjimharris        // has been run.
576230557Sjimharris
577230557Sjimharris        if (System.out == null) {
578230557Sjimharris            // java.lang.System not yet fully initialized
579230557Sjimharris            return;
580230557Sjimharris        }
581230557Sjimharris
582230557Sjimharris        Properties props = GetPropertyAction.privilegedGetProperties();
583230557Sjimharris        String val = props.getProperty("sun.reflect.noInflation");
584230557Sjimharris        if (val != null && val.equals("true")) {
585230557Sjimharris            noInflation = true;
586230557Sjimharris        }
587230557Sjimharris
588230557Sjimharris        val = props.getProperty("sun.reflect.inflationThreshold");
589230557Sjimharris        if (val != null) {
590230557Sjimharris            try {
591230557Sjimharris                inflationThreshold = Integer.parseInt(val);
592230557Sjimharris            } catch (NumberFormatException e) {
593230557Sjimharris                throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e);
594230557Sjimharris            }
595230557Sjimharris        }
596230557Sjimharris
597230557Sjimharris        initted = true;
598230557Sjimharris    }
599230557Sjimharris
600230557Sjimharris    private static LangReflectAccess langReflectAccess() {
601230557Sjimharris        if (langReflectAccess == null) {
602230557Sjimharris            // Call a static method to get class java.lang.reflect.Modifier
603230557Sjimharris            // initialized. Its static initializer will cause
604230557Sjimharris            // setLangReflectAccess() to be called from the context of the
605230557Sjimharris            // java.lang.reflect package.
606230557Sjimharris            Modifier.isPublic(Modifier.PUBLIC);
607230557Sjimharris        }
608230557Sjimharris        return langReflectAccess;
609230557Sjimharris    }
610230557Sjimharris
611230557Sjimharris    /**
612230557Sjimharris     * Returns true if classes are defined in the classloader and same package, false
613230557Sjimharris     * otherwise.
614230557Sjimharris     * @param cl1 a class
615230557Sjimharris     * @param cl2 another class
616230557Sjimharris     * @returns true if the two classes are in the same classloader and package
617230557Sjimharris     */
618230557Sjimharris    private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
619230557Sjimharris        return cl1.getClassLoader() == cl2.getClassLoader() &&
620230557Sjimharris                Objects.equals(cl1.getPackage(), cl2.getPackage());
621230557Sjimharris    }
622230557Sjimharris
623230557Sjimharris}
624230557Sjimharris