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