< prev index next >
src/java.base/share/classes/java/lang/Class.java
Print this page
*** 43,53 ****
import java.io.InputStream;
import java.io.ObjectStreamField;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
- import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
--- 43,52 ----
*** 429,439 ****
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
! final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
--- 428,440 ----
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
! // must copy constructor since we are modifying it
! final Constructor<T> c = getReflectionFactory().copyConstructor(
! getConstructor0(empty, Member.DECLARED));
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
*** 862,883 ****
* returned in that order.
*
* @return an array of interfaces directly implemented by this class
*/
public Class<?>[] getInterfaces() {
ReflectionData<T> rd = reflectionData();
if (rd == null) {
// no cloning required
return getInterfaces0();
} else {
Class<?>[] interfaces = rd.interfaces;
if (interfaces == null) {
interfaces = getInterfaces0();
rd.interfaces = interfaces;
}
! // defensively copy before handing over to user code
! return interfaces.clone();
}
}
private native Class<?>[] getInterfaces0();
--- 863,888 ----
* returned in that order.
*
* @return an array of interfaces directly implemented by this class
*/
public Class<?>[] getInterfaces() {
+ return getInterfaces(true);
+ }
+
+ private Class<?>[] getInterfaces(boolean cloneArray) {
ReflectionData<T> rd = reflectionData();
if (rd == null) {
// no cloning required
return getInterfaces0();
} else {
Class<?>[] interfaces = rd.interfaces;
if (interfaces == null) {
interfaces = getInterfaces0();
rd.interfaces = interfaces;
}
! // defensively copy cached array before handing over to user code
! return cloneArray ? interfaces.clone() : interfaces;
}
}
private native Class<?>[] getInterfaces0();
*** 1746,1756 ****
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Field field = getField0(name);
if (field == null) {
throw new NoSuchFieldException(name);
}
! return field;
}
/**
* Returns a {@code Method} object that reflects the specified public
--- 1751,1761 ----
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Field field = getField0(name);
if (field == null) {
throw new NoSuchFieldException(name);
}
! return getReflectionFactory().copyField(field);
}
/**
* Returns a {@code Method} object that reflects the specified public
*** 1829,1839 ****
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Method method = getMethod0(name, parameterTypes, true);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
! return method;
}
/**
* Returns a {@code Constructor} object that reflects the specified
--- 1834,1844 ----
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
Method method = getMethod0(name, parameterTypes, true);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
! return getReflectionFactory().copyMethod(method);
}
/**
* Returns a {@code Constructor} object that reflects the specified
*** 1866,1876 ****
*/
@CallerSensitive
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
! return getConstructor0(parameterTypes, Member.PUBLIC);
}
/**
* Returns an array of {@code Class} objects reflecting all the
--- 1871,1882 ----
*/
@CallerSensitive
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
! return getReflectionFactory().copyConstructor(
! getConstructor0(parameterTypes, Member.PUBLIC));
}
/**
* Returns an array of {@code Class} objects reflecting all the
*** 2113,2123 ****
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
Field field = searchFields(privateGetDeclaredFields(false), name);
if (field == null) {
throw new NoSuchFieldException(name);
}
! return field;
}
/**
* Returns a {@code Method} object that reflects the specified
--- 2119,2129 ----
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
Field field = searchFields(privateGetDeclaredFields(false), name);
if (field == null) {
throw new NoSuchFieldException(name);
}
! return getReflectionFactory().copyField(field);
}
/**
* Returns a {@code Method} object that reflects the specified
*** 2173,2183 ****
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
! return method;
}
/**
* Returns a {@code Constructor} object that reflects the specified
--- 2179,2189 ----
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
if (method == null) {
throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
}
! return getReflectionFactory().copyMethod(method);
}
/**
* Returns a {@code Constructor} object that reflects the specified
*** 2219,2229 ****
*/
@CallerSensitive
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
! return getConstructor0(parameterTypes, Member.DECLARED);
}
/**
* Finds a resource with a given name. The rules for searching resources
* associated with a given class are implemented by the defining
--- 2225,2236 ----
*/
@CallerSensitive
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
! return getReflectionFactory().copyConstructor(
! getConstructor0(parameterTypes, Member.DECLARED));
}
/**
* Finds a resource with a given name. The rules for searching resources
* associated with a given class are implemented by the defining
*** 2659,2669 ****
// Local fields
Field[] tmp = privateGetDeclaredFields(true);
addAll(fields, tmp);
// Direct superinterfaces, recursively
! for (Class<?> c : getInterfaces()) {
if (!traversedInterfaces.contains(c)) {
traversedInterfaces.add(c);
addAll(fields, c.privateGetPublicFields(traversedInterfaces));
}
}
--- 2666,2676 ----
// Local fields
Field[] tmp = privateGetDeclaredFields(true);
addAll(fields, tmp);
// Direct superinterfaces, recursively
! for (Class<?> c : getInterfaces(false)) {
if (!traversedInterfaces.contains(c)) {
traversedInterfaces.add(c);
addAll(fields, c.privateGetPublicFields(traversedInterfaces));
}
}
*** 2753,2935 ****
}
}
return res;
}
! static class MethodArray {
! // Don't add or remove methods except by add() or remove() calls.
! private Method[] methods;
! private int length;
! private int defaults;
!
! MethodArray() {
! this(20);
! }
!
! MethodArray(int initialSize) {
! if (initialSize < 2)
! throw new IllegalArgumentException("Size should be 2 or more");
!
! methods = new Method[initialSize];
! length = 0;
! defaults = 0;
! }
!
! boolean hasDefaults() {
! return defaults != 0;
! }
!
! void add(Method m) {
! if (length == methods.length) {
! methods = Arrays.copyOf(methods, 2 * methods.length);
! }
! methods[length++] = m;
!
! if (m != null && m.isDefault())
! defaults++;
! }
!
! void addAll(Method[] ma) {
! for (Method m : ma) {
! add(m);
! }
! }
!
! void addAll(MethodArray ma) {
! for (int i = 0; i < ma.length(); i++) {
! add(ma.get(i));
! }
! }
!
! void addIfNotPresent(Method newMethod) {
! for (int i = 0; i < length; i++) {
! Method m = methods[i];
! if (m == newMethod || (m != null && m.equals(newMethod))) {
! return;
! }
! }
! add(newMethod);
! }
!
! void addAllIfNotPresent(MethodArray newMethods) {
! for (int i = 0; i < newMethods.length(); i++) {
! Method m = newMethods.get(i);
! if (m != null) {
! addIfNotPresent(m);
! }
! }
! }
!
! /* Add Methods declared in an interface to this MethodArray.
! * Static methods declared in interfaces are not inherited.
! */
! void addInterfaceMethods(Method[] methods) {
! for (Method candidate : methods) {
! if (!Modifier.isStatic(candidate.getModifiers())) {
! add(candidate);
! }
! }
! }
!
! int length() {
! return length;
! }
!
! Method get(int i) {
! return methods[i];
! }
!
! Method getFirst() {
! for (Method m : methods)
! if (m != null)
! return m;
! return null;
! }
!
! void removeByNameAndDescriptor(Method toRemove) {
! for (int i = 0; i < length; i++) {
! Method m = methods[i];
! if (m != null && matchesNameAndDescriptor(m, toRemove)) {
! remove(i);
! }
! }
! }
!
! private void remove(int i) {
! if (methods[i] != null && methods[i].isDefault())
! defaults--;
! methods[i] = null;
! }
!
! private boolean matchesNameAndDescriptor(Method m1, Method m2) {
! return m1.getReturnType() == m2.getReturnType() &&
! m1.getName() == m2.getName() && // name is guaranteed to be interned
! arrayContentsEq(m1.getParameterTypes(),
! m2.getParameterTypes());
! }
!
! void compactAndTrim() {
! int newPos = 0;
! // Get rid of null slots
! for (int pos = 0; pos < length; pos++) {
! Method m = methods[pos];
! if (m != null) {
! if (pos != newPos) {
! methods[newPos] = m;
! }
! newPos++;
! }
! }
! if (newPos != methods.length) {
! methods = Arrays.copyOf(methods, newPos);
! }
! }
!
! /* Removes all Methods from this MethodArray that have a more specific
! * default Method in this MethodArray.
! *
! * Users of MethodArray are responsible for pruning Methods that have
! * a more specific <em>concrete</em> Method.
! */
! void removeLessSpecifics() {
! if (!hasDefaults())
! return;
!
! for (int i = 0; i < length; i++) {
! Method m = get(i);
! if (m == null || !m.isDefault())
! continue;
!
! for (int j = 0; j < length; j++) {
! if (i == j)
! continue;
!
! Method candidate = get(j);
! if (candidate == null)
! continue;
!
! if (!matchesNameAndDescriptor(m, candidate))
! continue;
!
! if (hasMoreSpecificClass(m, candidate))
! remove(j);
! }
! }
! }
!
! Method[] getArray() {
! return methods;
! }
!
! // Returns true if m1 is more specific than m2
! static boolean hasMoreSpecificClass(Method m1, Method m2) {
! Class<?> m1Class = m1.getDeclaringClass();
! Class<?> m2Class = m2.getDeclaringClass();
! return m1Class != m2Class && m2Class.isAssignableFrom(m1Class);
! }
! }
!
// Returns an array of "root" methods. These Method objects must NOT
// be propagated to the outside world, but must instead be copied
// via ReflectionFactory.copyMethod.
private Method[] privateGetPublicMethods() {
--- 2760,2770 ----
}
}
return res;
}
! private static final Method[] EMPTY_METHODS = new Method[0];
// Returns an array of "root" methods. These Method objects must NOT
// be propagated to the outside world, but must instead be copied
// via ReflectionFactory.copyMethod.
private Method[] privateGetPublicMethods() {
*** 2939,2994 ****
if (rd != null) {
res = rd.publicMethods;
if (res != null) return res;
}
! // No cached value available; compute value recursively.
! // Start by fetching public declared methods
! MethodArray methods = new MethodArray();
! {
! Method[] tmp = privateGetDeclaredMethods(true);
! methods.addAll(tmp);
}
! // Now recur over superclass and direct superinterfaces.
! // Go over superinterfaces first so we can more easily filter
! // out concrete implementations inherited from superclasses at
! // the end.
! MethodArray inheritedMethods = new MethodArray();
! for (Class<?> i : getInterfaces()) {
! inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods());
}
! if (!isInterface()) {
! Class<?> c = getSuperclass();
! if (c != null) {
! MethodArray supers = new MethodArray();
! supers.addAll(c.privateGetPublicMethods());
! // Filter out concrete implementations of any
! // interface methods
! for (int i = 0; i < supers.length(); i++) {
! Method m = supers.get(i);
! if (m != null &&
! !Modifier.isAbstract(m.getModifiers()) &&
! !m.isDefault()) {
! inheritedMethods.removeByNameAndDescriptor(m);
! }
! }
! // Insert superclass's inherited methods before
! // superinterfaces' to satisfy getMethod's search
! // order
! supers.addAll(inheritedMethods);
! inheritedMethods = supers;
! }
! }
! // Filter out all local methods from inherited ones
! for (int i = 0; i < methods.length(); i++) {
! Method m = methods.get(i);
! inheritedMethods.removeByNameAndDescriptor(m);
! }
! methods.addAllIfNotPresent(inheritedMethods);
! methods.removeLessSpecifics();
! methods.compactAndTrim();
! res = methods.getArray();
if (rd != null) {
rd.publicMethods = res;
}
return res;
}
--- 2774,2836 ----
if (rd != null) {
res = rd.publicMethods;
if (res != null) return res;
}
! Method[] declaredMethods = privateGetDeclaredMethods(true);
! Class<?> superclass = getSuperclass();
! Class<?>[] interfaces = getInterfaces(false);
!
! // optimization:
! // if we don't have a superclass (either we are j.l.Object or an interface)
! // and don't have (super)interfaces either, then public methods consist
! // of declared public methods
! if (superclass == null && interfaces.length == 0) {
! res = declaredMethods;
! } else {
! // we have to do some logic
! Method[] superclassMethods = (superclass == null)
! ? EMPTY_METHODS
! : superclass.privateGetPublicMethods();
! Method[][] interfacesMethods = new Method[interfaces.length][];
! int interfacesMethodsCount = 0;
! for (int i = 0; i < interfaces.length; i++) {
! interfacesMethods[i] = interfaces[i].privateGetPublicMethods();
! interfacesMethodsCount += interfacesMethods[i].length;
! }
!
! // ensure enough working capacity
! // (MethodTable implementation may not support dynamic resizing)
! MethodTable methodTable = MethodTable.newInstance(
! declaredMethods.length +
! superclassMethods.length +
! interfacesMethodsCount
! );
!
! // declared methods first
! for (Method m : declaredMethods) {
! methodTable.add(m);
}
!
! // inherited methods from superclass
! for (Method m : superclassMethods) {
! methodTable.addUnlessDeclaredExists(m, this);
}
!
! // inherited methods from (super)interfaces
! for (Method[] ms : interfacesMethods) {
! for (Method m : ms) {
! // interface static methods are not inherited
! if (!Modifier.isStatic(m.getModifiers())) {
! methodTable.consolidate(m, this);
! }
! }
! }
!
! res = methodTable.getMethods();
! }
!
if (rd != null) {
rd.publicMethods = res;
}
return res;
}
*** 2996,3015 ****
//
// Helpers for fetchers of one field, method, or constructor
//
private static Field searchFields(Field[] fields, String name) {
String internedName = name.intern();
for (Field field : fields) {
if (field.getName() == internedName) {
! return getReflectionFactory().copyField(field);
}
}
return null;
}
private Field getField0(String name) throws NoSuchFieldException {
// Note: the intent is that the search algorithm this routine
// uses be equivalent to the ordering imposed by
// privateGetPublicFields(). It fetches only the declared
// public fields for each class, however, to reduce the number
--- 2838,2866 ----
//
// Helpers for fetchers of one field, method, or constructor
//
+ /**
+ * This method does not copy returned 'root' Field object. It MUST be copied
+ * with ReflectionFactory before handed to any code outside java.lang.Class
+ * or modified.
+ */
private static Field searchFields(Field[] fields, String name) {
String internedName = name.intern();
for (Field field : fields) {
if (field.getName() == internedName) {
! return field;
}
}
return null;
}
+ /**
+ * This method returns 'root' Field object. It MUST be copied with ReflectionFactory
+ * before handed to any code outside java.lang.Class or modified.
+ */
private Field getField0(String name) throws NoSuchFieldException {
// Note: the intent is that the search algorithm this routine
// uses be equivalent to the ordering imposed by
// privateGetPublicFields(). It fetches only the declared
// public fields for each class, however, to reduce the number
*** 3020,3030 ****
// Search declared public fields
if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {
return res;
}
// Direct superinterfaces, recursively
! Class<?>[] interfaces = getInterfaces();
for (Class<?> c : interfaces) {
if ((res = c.getField0(name)) != null) {
return res;
}
}
--- 2871,2881 ----
// Search declared public fields
if ((res = searchFields(privateGetDeclaredFields(true), name)) != null) {
return res;
}
// Direct superinterfaces, recursively
! Class<?>[] interfaces = getInterfaces(false);
for (Class<?> c : interfaces) {
if ((res = c.getField0(name)) != null) {
return res;
}
}
*** 3038,3047 ****
--- 2889,2903 ----
}
}
return null;
}
+ /**
+ * This method does not copy returned 'root' Method object. It MUST be copied
+ * with ReflectionFactory before handed to any code outside java.lang.Class
+ * or modified.
+ */
private static Method searchMethods(Method[] methods,
String name,
Class<?>[] parameterTypes)
{
Method res = null;
*** 3052,3128 ****
&& (res == null
|| res.getReturnType().isAssignableFrom(m.getReturnType())))
res = m;
}
- return (res == null ? res : getReflectionFactory().copyMethod(res));
- }
-
- private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
- MethodArray interfaceCandidates = new MethodArray(2);
- Method res = privateGetMethodRecursive(name, parameterTypes, includeStaticMethods, interfaceCandidates);
- if (res != null)
return res;
-
- // Not found on class or superclass directly
- interfaceCandidates.removeLessSpecifics();
- return interfaceCandidates.getFirst(); // may be null
}
! private Method privateGetMethodRecursive(String name,
! Class<?>[] parameterTypes,
! boolean includeStaticMethods,
! MethodArray allInterfaceCandidates) {
// Note: the intent is that the search algorithm this routine
// uses be equivalent to the ordering imposed by
// privateGetPublicMethods(). It fetches only the declared
// public methods for each class, however, to reduce the
// number of Method objects which have to be created for the
// common case where the method being requested is declared in
// the class which is being queried.
- //
- // Due to default methods, unless a method is found on a superclass,
- // methods declared in any superinterface needs to be considered.
- // Collect all candidates declared in superinterfaces in {@code
- // allInterfaceCandidates} and select the most specific if no match on
- // a superclass is found.
-
- // Must _not_ return root methods
Method res;
! // Search declared public methods
if ((res = searchMethods(privateGetDeclaredMethods(true),
name,
! parameterTypes)) != null) {
! if (includeStaticMethods || !Modifier.isStatic(res.getModifiers()))
return res;
}
! // Search superclass's methods
! if (!isInterface()) {
! Class<? super T> c = getSuperclass();
! if (c != null) {
! if ((res = c.getMethod0(name, parameterTypes, true)) != null) {
return res;
}
}
}
! // Search superinterfaces' methods
! Class<?>[] interfaces = getInterfaces();
! for (Class<?> c : interfaces)
! if ((res = c.getMethod0(name, parameterTypes, false)) != null)
! allInterfaceCandidates.add(res);
! // Not found
! return null;
}
private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
int which) throws NoSuchMethodException
{
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
for (Constructor<T> constructor : constructors) {
if (arrayContentsEq(parameterTypes,
constructor.getParameterTypes())) {
! return getReflectionFactory().copyConstructor(constructor);
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}
--- 2908,2979 ----
&& (res == null
|| res.getReturnType().isAssignableFrom(m.getReturnType())))
res = m;
}
return res;
}
! /**
! * This method returns 'root' Method object. It MUST be copied with ReflectionFactory
! * before handed to any code outside java.lang.Class or modified.
! */
! private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) {
// Note: the intent is that the search algorithm this routine
// uses be equivalent to the ordering imposed by
// privateGetPublicMethods(). It fetches only the declared
// public methods for each class, however, to reduce the
// number of Method objects which have to be created for the
// common case where the method being requested is declared in
// the class which is being queried.
Method res;
! // 1st search declared public methods
if ((res = searchMethods(privateGetDeclaredMethods(true),
name,
! parameterTypes)) != null &&
! (includeStaticMethods ||
! !Modifier.isStatic(res.getModifiers()))) {
return res;
}
!
! // 2nd we try the superclass.
! Class<? super T> superclass = getSuperclass();
! if (superclass != null &&
! (res = superclass.getMethod0(name, parameterTypes, includeStaticMethods)) != null) {
return res;
}
+
+ // last we check (super) interfaces
+ Class<?>[] interfaces = getInterfaces(false);
+ if (interfaces.length == 0) {
+ return null;
+ }
+ // have to construct a MethodTable to consolidate
+ // public methods from (super)interfaces
+ MethodTable methodTable = MethodTable.newInstance(interfaces.length);
+ for (Class<?> c : interfaces) {
+ if ((res = c.getMethod0(name, parameterTypes, false)) != null) {
+ methodTable.consolidate(res, this);
}
}
!
! // return the first method with the most specific return type
! return methodTable.getFirstMethodWithMostSpecificReturnType();
}
+ /**
+ * This method returns 'root' Constructor object. It MUST be copied with ReflectionFactory
+ * before handed to any code outside java.lang.Class or modified.
+ */
private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
int which) throws NoSuchMethodException
{
Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
for (Constructor<T> constructor : constructors) {
if (arrayContentsEq(parameterTypes,
constructor.getParameterTypes())) {
! return constructor;
}
}
throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
}
< prev index next >