|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
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; |
|
|
|
|
|
/** <P> The master factory for all reflective objects, both those in |
|
java.lang.reflect (Fields, Methods, Constructors) as well as their |
|
delegates (FieldAccessors, MethodAccessors, ConstructorAccessors). |
|
</P> |
|
|
|
<P> The methods in this class are extremely unsafe and can cause |
|
subversion of both the language and the verifier. For this reason, |
|
they are all instance methods, and access to the constructor of |
|
this factory is guarded by a security check, in similar style to |
|
{@link sun.misc.Unsafe}. </P> |
|
*/ |
|
|
|
public class ReflectionFactory { |
|
|
|
private static boolean initted = false; |
|
private static final Permission reflectionFactoryAccessPerm |
|
= new RuntimePermission("reflectionFactoryAccess"); |
|
private static final ReflectionFactory soleInstance = new ReflectionFactory(); |
|
|
|
private static volatile LangReflectAccess langReflectAccess; |
|
|
|
|
|
private static volatile Method hasStaticInitializerMethod; |
|
|
|
// |
|
// "Inflation" mechanism. Loading bytecodes to implement |
|
// Method.invoke() and Constructor.newInstance() currently costs |
|
// 3-4x more than an invocation via native code for the first |
|
// invocation (though subsequent invocations have been benchmarked |
|
// to be over 20x faster). Unfortunately this cost increases |
|
// startup time for certain applications that use reflection |
|
// intensively (but only once per class) to bootstrap themselves. |
|
// To avoid this penalty we reuse the existing JVM entry points |
|
// for the first few invocations of Methods and Constructors and |
|
// then switch to the bytecode-based implementations. |
|
// |
|
// Package-private to be accessible to NativeMethodAccessorImpl |
|
|
|
private static boolean noInflation = false; |
|
private static int inflationThreshold = 15; |
|
|
|
private ReflectionFactory() {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static final class GetReflectionFactoryAction |
|
implements PrivilegedAction<ReflectionFactory> { |
|
public ReflectionFactory run() { |
|
return getReflectionFactory(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* access to the RuntimePermission "reflectionFactoryAccess". */ |
|
public static ReflectionFactory getReflectionFactory() { |
|
SecurityManager security = System.getSecurityManager(); |
|
if (security != null) { |
|
|
|
security.checkPermission(reflectionFactoryAccessPerm); |
|
} |
|
return soleInstance; |
|
} |
|
|
|
//-------------------------------------------------------------------------- |
|
// |
|
// Routines used by java.lang.reflect |
|
// |
|
// |
|
|
|
|
|
public void setLangReflectAccess(LangReflectAccess access) { |
|
langReflectAccess = access; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public FieldAccessor newFieldAccessor(Field field, boolean override) { |
|
checkInitted(); |
|
return UnsafeFieldAccessorFactory.newFieldAccessor(field, override); |
|
} |
|
|
|
public MethodAccessor newMethodAccessor(Method method) { |
|
checkInitted(); |
|
|
|
if (noInflation && !ReflectUtil.isVMAnonymousClass(method.getDeclaringClass())) { |
|
return new MethodAccessorGenerator(). |
|
generateMethod(method.getDeclaringClass(), |
|
method.getName(), |
|
method.getParameterTypes(), |
|
method.getReturnType(), |
|
method.getExceptionTypes(), |
|
method.getModifiers()); |
|
} else { |
|
NativeMethodAccessorImpl acc = |
|
new NativeMethodAccessorImpl(method); |
|
DelegatingMethodAccessorImpl res = |
|
new DelegatingMethodAccessorImpl(acc); |
|
acc.setParent(res); |
|
return res; |
|
} |
|
} |
|
|
|
public ConstructorAccessor newConstructorAccessor(Constructor<?> c) { |
|
checkInitted(); |
|
|
|
Class<?> declaringClass = c.getDeclaringClass(); |
|
if (Modifier.isAbstract(declaringClass.getModifiers())) { |
|
return new InstantiationExceptionConstructorAccessorImpl(null); |
|
} |
|
if (declaringClass == Class.class) { |
|
return new InstantiationExceptionConstructorAccessorImpl |
|
("Can not instantiate java.lang.Class"); |
|
} |
|
// Bootstrapping issue: since we use Class.newInstance() in |
|
// the ConstructorAccessor generation process, we have to |
|
|
|
if (Reflection.isSubclassOf(declaringClass, |
|
ConstructorAccessorImpl.class)) { |
|
return new BootstrapConstructorAccessorImpl(c); |
|
} |
|
|
|
if (noInflation && !ReflectUtil.isVMAnonymousClass(c.getDeclaringClass())) { |
|
return new MethodAccessorGenerator(). |
|
generateConstructor(c.getDeclaringClass(), |
|
c.getParameterTypes(), |
|
c.getExceptionTypes(), |
|
c.getModifiers()); |
|
} else { |
|
NativeConstructorAccessorImpl acc = |
|
new NativeConstructorAccessorImpl(c); |
|
DelegatingConstructorAccessorImpl res = |
|
new DelegatingConstructorAccessorImpl(acc); |
|
acc.setParent(res); |
|
return res; |
|
} |
|
} |
|
|
|
//-------------------------------------------------------------------------- |
|
// |
|
// Routines used by java.lang |
|
// |
|
// |
|
|
|
|
|
java.lang.reflect.AccessibleObject are not overridden. */ |
|
public Field newField(Class<?> declaringClass, |
|
String name, |
|
Class<?> type, |
|
int modifiers, |
|
int slot, |
|
String signature, |
|
byte[] annotations) |
|
{ |
|
return langReflectAccess().newField(declaringClass, |
|
name, |
|
type, |
|
modifiers, |
|
slot, |
|
signature, |
|
annotations); |
|
} |
|
|
|
|
|
java.lang.reflect.AccessibleObject are not overridden. */ |
|
public Method newMethod(Class<?> declaringClass, |
|
String name, |
|
Class<?>[] parameterTypes, |
|
Class<?> returnType, |
|
Class<?>[] checkedExceptions, |
|
int modifiers, |
|
int slot, |
|
String signature, |
|
byte[] annotations, |
|
byte[] parameterAnnotations, |
|
byte[] annotationDefault) |
|
{ |
|
return langReflectAccess().newMethod(declaringClass, |
|
name, |
|
parameterTypes, |
|
returnType, |
|
checkedExceptions, |
|
modifiers, |
|
slot, |
|
signature, |
|
annotations, |
|
parameterAnnotations, |
|
annotationDefault); |
|
} |
|
|
|
|
|
per java.lang.reflect.AccessibleObject are not overridden. */ |
|
public Constructor<?> newConstructor(Class<?> declaringClass, |
|
Class<?>[] parameterTypes, |
|
Class<?>[] checkedExceptions, |
|
int modifiers, |
|
int slot, |
|
String signature, |
|
byte[] annotations, |
|
byte[] parameterAnnotations) |
|
{ |
|
return langReflectAccess().newConstructor(declaringClass, |
|
parameterTypes, |
|
checkedExceptions, |
|
modifiers, |
|
slot, |
|
signature, |
|
annotations, |
|
parameterAnnotations); |
|
} |
|
|
|
|
|
public MethodAccessor getMethodAccessor(Method m) { |
|
return langReflectAccess().getMethodAccessor(m); |
|
} |
|
|
|
|
|
public void setMethodAccessor(Method m, MethodAccessor accessor) { |
|
langReflectAccess().setMethodAccessor(m, accessor); |
|
} |
|
|
|
|
|
java.lang.reflect.Constructor */ |
|
public ConstructorAccessor getConstructorAccessor(Constructor<?> c) { |
|
return langReflectAccess().getConstructorAccessor(c); |
|
} |
|
|
|
|
|
java.lang.reflect.Constructor */ |
|
public void setConstructorAccessor(Constructor<?> c, |
|
ConstructorAccessor accessor) |
|
{ |
|
langReflectAccess().setConstructorAccessor(c, accessor); |
|
} |
|
|
|
|
|
|
|
details. */ |
|
public Method copyMethod(Method arg) { |
|
return langReflectAccess().copyMethod(arg); |
|
} |
|
|
|
|
|
|
|
details. */ |
|
public Field copyField(Field arg) { |
|
return langReflectAccess().copyField(arg); |
|
} |
|
|
|
|
|
|
|
in Constructor.java for details. */ |
|
public <T> Constructor<T> copyConstructor(Constructor<T> arg) { |
|
return langReflectAccess().copyConstructor(arg); |
|
} |
|
|
|
|
|
*/ |
|
public byte[] getExecutableTypeAnnotationBytes(Executable ex) { |
|
return langReflectAccess().getExecutableTypeAnnotationBytes(ex); |
|
} |
|
|
|
//-------------------------------------------------------------------------- |
|
// |
|
// Routines used by serialization |
|
// |
|
// |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public Constructor<?> newConstructorForSerialization |
|
(Class<?> classToInstantiate, Constructor<?> constructorToCall) |
|
{ |
|
|
|
if (constructorToCall.getDeclaringClass() == classToInstantiate) { |
|
return constructorToCall; |
|
} |
|
return generateConstructor(classToInstantiate, constructorToCall); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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, |
|
constructorToCall.getParameterTypes(), |
|
constructorToCall.getExceptionTypes(), |
|
constructorToCall.getModifiers(), |
|
constructorToCall.getDeclaringClass()); |
|
Constructor<?> c = newConstructor(constructorToCall.getDeclaringClass(), |
|
constructorToCall.getParameterTypes(), |
|
constructorToCall.getExceptionTypes(), |
|
constructorToCall.getModifiers(), |
|
langReflectAccess(). |
|
getConstructorSlot(constructorToCall), |
|
langReflectAccess(). |
|
getConstructorSignature(constructorToCall), |
|
langReflectAccess(). |
|
getConstructorAnnotations(constructorToCall), |
|
langReflectAccess(). |
|
getConstructorParameterAnnotations(constructorToCall)); |
|
setConstructorAccessor(c, acc); |
|
c.setAccessible(true); |
|
return c; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final MethodHandle readObjectForSerialization(Class<?> cl) { |
|
return findReadWriteObjectForSerialization(cl, "readObject", ObjectInputStream.class); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final MethodHandle readObjectNoDataForSerialization(Class<?> cl) { |
|
return findReadWriteObjectForSerialization(cl, "readObjectNoData", ObjectInputStream.class); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final MethodHandle readResolveForSerialization(Class<?> cl) { |
|
return getReplaceResolveForSerialization(cl, "readResolve"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final MethodHandle writeReplaceForSerialization(Class<?> cl) { |
|
return getReplaceResolveForSerialization(cl, "writeReplace"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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 { |
|
|
|
m.setAccessible(true); |
|
return MethodHandles.lookup().unreflect(m); |
|
} catch (IllegalAccessException ex0) { |
|
|
|
throw new InternalError("Error", ex0); |
|
} |
|
} catch (NoSuchMethodException ex) { |
|
defCl = defCl.getSuperclass(); |
|
} |
|
} |
|
return null; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
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); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public final OptionalDataException newOptionalDataExceptionForSerialization(boolean bool) { |
|
try { |
|
Constructor<OptionalDataException> 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 |
|
// |
|
|
|
static int inflationThreshold() { |
|
return inflationThreshold; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
run, before the system properties are set up. */ |
|
private static void checkInitted() { |
|
if (initted) return; |
|
AccessController.doPrivileged( |
|
new PrivilegedAction<Void>() { |
|
public Void run() { |
|
// Tests to ensure the system properties table is fully |
|
// initialized. This is needed because reflection code is |
|
// called very early in the initialization process (before |
|
// command-line arguments have been parsed and therefore |
|
// these user-settable properties installed.) We assume that |
|
// if System.out is non-null then the System class has been |
|
// fully initialized and that the bulk of the startup code |
|
// has been run. |
|
|
|
if (System.out == null) { |
|
|
|
return null; |
|
} |
|
|
|
String val = System.getProperty("sun.reflect.noInflation"); |
|
if (val != null && val.equals("true")) { |
|
noInflation = true; |
|
} |
|
|
|
val = System.getProperty("sun.reflect.inflationThreshold"); |
|
if (val != null) { |
|
try { |
|
inflationThreshold = Integer.parseInt(val); |
|
} catch (NumberFormatException e) { |
|
throw new RuntimeException("Unable to parse property sun.reflect.inflationThreshold", e); |
|
} |
|
} |
|
|
|
initted = true; |
|
return null; |
|
} |
|
}); |
|
} |
|
|
|
private static LangReflectAccess langReflectAccess() { |
|
if (langReflectAccess == null) { |
|
// Call a static method to get class java.lang.reflect.Modifier |
|
// initialized. Its static initializer will cause |
|
// setLangReflectAccess() to be called from the context of the |
|
|
|
Modifier.isPublic(Modifier.PUBLIC); |
|
} |
|
return langReflectAccess; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static boolean packageEquals(Class<?> cl1, Class<?> cl2) { |
|
return cl1.getClassLoader() == cl2.getClassLoader() && |
|
Objects.equals(cl1.getPackage(), cl2.getPackage()); |
|
} |
|
|
|
} |