--- old/src/java.base/share/classes/java/lang/Class.java 2016-12-26 10:22:49.571044987 +0100 +++ new/src/java.base/share/classes/java/lang/Class.java 2016-12-26 10:22:49.469046825 +0100 @@ -26,6 +26,8 @@ package java.lang; import java.lang.annotation.Annotation; +import java.lang.module.ModuleDescriptor.Version; +import java.lang.module.ModuleFinder; import java.lang.module.ModuleReader; import java.lang.ref.SoftReference; import java.io.IOException; @@ -40,6 +42,7 @@ import java.lang.reflect.GenericArrayType; import java.lang.reflect.GenericDeclaration; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Layer; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -51,6 +54,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -58,15 +62,19 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.StringJoiner; +import java.util.stream.Collectors; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.loader.BootLoader; import jdk.internal.loader.BuiltinClassLoader; import jdk.internal.loader.ResourceHelper; +import jdk.internal.misc.SharedSecrets; import jdk.internal.misc.Unsafe; import jdk.internal.misc.VM; +import jdk.internal.module.ModuleHashes; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.ConstantPool; import jdk.internal.reflect.Reflection; @@ -524,8 +532,7 @@ } try { Class[] empty = {}; - final Constructor c = getReflectionFactory().copyConstructor( - getConstructor0(empty, Member.DECLARED)); + final Constructor 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 @@ -1017,11 +1024,6 @@ * @return an array of interfaces directly implemented by this class */ public Class[] getInterfaces() { - // defensively copy before handing over to user code - return getInterfaces(true); - } - - private Class[] getInterfaces(boolean cloneArray) { ReflectionData rd = reflectionData(); if (rd == null) { // no cloning required @@ -1032,8 +1034,8 @@ interfaces = getInterfaces0(); rd.interfaces = interfaces; } - // defensively copy if requested - return cloneArray ? interfaces.clone() : interfaces; + // defensively copy before handing over to user code + return interfaces.clone(); } } @@ -1765,6 +1767,15 @@ * Class} object, including those declared by the class or interface and * those inherited from superclasses and superinterfaces. * + *

If this {@code Class} object represents a type that has multiple + * public methods with the same name and parameter types, but different + * return types, then the returned array has a {@code Method} object for + * each such method. + * + *

If this {@code Class} object represents a type with a class + * initialization method {@code }, then the returned array does + * not have a corresponding {@code Method} object. + * *

If this {@code Class} object represents an array type, then the * returned array has a {@code Method} object for each of the public * methods inherited by the array type from {@code Object}. It does not @@ -1777,54 +1788,16 @@ * has length 0. (Note that a {@code Class} object which represents a class * always has public methods, inherited from {@code Object}.) * - *

The returned array never contains methods with names "{@code }" - * or "{@code }". + *

If this {@code Class} object represents a primitive type or void, + * then the returned array has length 0. + * + *

Static methods declared in superinterfaces of the class or interface + * represented by this {@code Class} object are not considered members of + * the class or interface. * *

The elements in the returned array are not sorted and are not in any * particular order. * - *

Generally, the result is computed as with the following 4 step algorithm. - * Let C be the class or interface represented by this {@code Class} object: - *

    - *
  1. A union of methods is composed of: - *
      - *
    1. C's declared public instance and static methods as returned by - * {@link #getDeclaredMethods()} and filtered to include only public - * methods.
    2. - *
    3. If C is a class other than {@code Object}, then include the result - * of invoking this algorithm recursively on the superclass of C.
    4. - *
    5. Include the results of invoking this algorithm recursively on all - * direct superinterfaces of C, but include only instance methods.
    6. - *
  2. - *
  3. Union from step 1 is partitioned into subsets of methods with same - * signature (name, parameter types) and return type.
  4. - *
  5. Within each such subset only the most specific methods are selected. - * Let method M be a method from a set of methods with same signature - * and return type. M is most specific if there is no such method - * N != M from the same set, such that N is more specific than M. - * N is more specific than M if: - *
      - *
    1. N is declared by a class and M is declared by an interface; or
    2. - *
    3. N and M are both declared by classes or both by interfaces and - * N's declaring type is the same as or a subtype of M's declaring type - * (clearly, if M's and N's declaring types are the same type, then - * M and N are the same method).
    4. - *
  6. - *
  7. The result of this algorithm is the union of all selected methods from - * step 3.
  8. - *
- * - * @apiNote There may be more than one method with a particular name - * and parameter types in a class because while the Java language forbids a - * class to declare multiple methods with the same signature but different - * return types, the Java virtual machine does not. This - * increased flexibility in the virtual machine can be used to - * implement various language features. For example, covariant - * returns can be implemented with {@linkplain - * java.lang.reflect.Method#isBridge bridge methods}; the bridge - * method and the overriding method would have the same - * signature but different return types. - * * @return the array of {@code Method} objects representing the * public methods of this class * @throws SecurityException @@ -1932,7 +1905,7 @@ if (field == null) { throw new NoSuchFieldException(name); } - return getReflectionFactory().copyField(field); + return field; } @@ -1946,69 +1919,47 @@ * order. If {@code parameterTypes} is {@code null}, it is * treated as if it were an empty array. * - *

If this {@code Class} object represents an array type, then this - * method finds any public method inherited by the array type from - * {@code Object} except method {@code clone()}. - * - *

If this {@code Class} object represents an interface then this - * method does not find any implicitly declared method from - * {@code Object}. Therefore, if no methods are explicitly declared in - * this interface or any of its superinterfaces, then this method does not - * find any method. + *

If the {@code name} is "{@code }" or "{@code }" a + * {@code NoSuchMethodException} is raised. Otherwise, the method to + * be reflected is determined by the algorithm that follows. Let C be the + * class or interface represented by this object: + *

    + *
  1. C is searched for a matching method, as defined below. If a + * matching method is found, it is reflected.
  2. + *
  3. If no matching method is found by step 1 then: + *
      + *
    1. If C is a class other than {@code Object}, then this algorithm is + * invoked recursively on the superclass of C.
    2. + *
    3. If C is the class {@code Object}, or if C is an interface, then + * the superinterfaces of C (if any) are searched for a matching + * method. If any such method is found, it is reflected.
    4. + *
  4. + *
* - *

This method does not find any method with name "{@code }" or - * "{@code }". + *

To find a matching method in a class or interface C:  If C + * declares exactly one public method with the specified name and exactly + * the same formal parameter types, that is the method reflected. If more + * than one such method is found in C, and one of these methods has a + * return type that is more specific than any of the others, that method is + * reflected; otherwise one of the methods is chosen arbitrarily. * - *

Generally, the method to be reflected is determined by the 4 step - * algorithm that follows. - * Let C be the class or interface represented by this {@code Class} object: - *

    - *
  1. A union of methods is composed of: - *
      - *
    1. C's declared public instance and static methods as returned by - * {@link #getDeclaredMethods()} and filtered to include only public - * methods that match given {@code name} and {@code parameterTypes}
    2. - *
    3. If C is a class other than {@code Object}, then include the result - * of invoking this algorithm recursively on the superclass of C.
    4. - *
    5. Include the results of invoking this algorithm recursively on all - * direct superinterfaces of C, but include only instance methods.
    6. - *
  2. - *
  3. This union is partitioned into subsets of methods with same - * return type (the selection of methods from step 1 also guarantees that - * they have the same method name and parameter types).
  4. - *
  5. Within each such subset only the most specific methods are selected. - * Let method M be a method from a set of methods with same VM - * signature (return type, name, parameter types). - * M is most specific if there is no such method N != M from the same - * set, such that N is more specific than M. N is more specific than M - * if: - *
      - *
    1. N is declared by a class and M is declared by an interface; or
    2. - *
    3. N and M are both declared by classes or both by interfaces and - * N's declaring type is the same as or a subtype of M's declaring type - * (clearly, if M's and N's declaring types are the same type, then - * M and N are the same method).
    4. - *
  6. - *
  7. The result of this algorithm is chosen arbitrarily from the methods - * with most specific return type among all selected methods from step 3. - * Let R be a return type of a method M from the set of all selected methods - * from step 3. M is a method with most specific return type if there is - * no such method N != M from the same set, having return type S != R, - * such that S is a subtype of R as determined by - * R.class.{@link #isAssignableFrom}(S.class). - *
- * - * @apiNote There may be more than one method with matching name and - * parameter types in a class because while the Java language forbids a - * class to declare multiple methods with the same signature but different + *

Note that there may be more than one matching method in a + * class because while the Java language forbids a class to + * declare multiple methods with the same signature but different * return types, the Java virtual machine does not. This * increased flexibility in the virtual machine can be used to * implement various language features. For example, covariant * returns can be implemented with {@linkplain * java.lang.reflect.Method#isBridge bridge methods}; the bridge - * method and the overriding method would have the same - * signature but different return types. This method would return the - * overriding method as it would have a more specific return type. + * method and the method being overridden would have the same + * signature but different return types. + * + *

If this {@code Class} object represents an array type, then this + * method does not find the {@code clone()} method. + * + *

Static methods declared in superinterfaces of the class or interface + * represented by this {@code Class} object are not considered members of + * the class or interface. * * @param name the name of the method * @param parameterTypes the list of parameters @@ -2033,11 +1984,11 @@ public Method getMethod(String name, Class... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - Method method = getMethod0(name, parameterTypes); + Method method = getMethod0(name, parameterTypes, true); if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); } - return getReflectionFactory().copyMethod(method); + return method; } /** @@ -2053,8 +2004,7 @@ * "<init>"or "<clinit>". */ Method getMethodOrNull(String name, Class... parameterTypes) { - Method method = getMethod0(name, parameterTypes); - return method == null ? null : getReflectionFactory().copyMethod(method); + return getMethod0(name, parameterTypes, true); } @@ -2091,8 +2041,7 @@ public Constructor getConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true); - return getReflectionFactory().copyConstructor( - getConstructor0(parameterTypes, Member.PUBLIC)); + return getConstructor0(parameterTypes, Member.PUBLIC); } @@ -2339,7 +2288,7 @@ if (field == null) { throw new NoSuchFieldException(name); } - return getReflectionFactory().copyField(field); + return field; } @@ -2399,7 +2348,7 @@ if (method == null) { throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes)); } - return getReflectionFactory().copyMethod(method); + return method; } @@ -2445,8 +2394,7 @@ public Constructor getDeclaredConstructor(Class... parameterTypes) throws NoSuchMethodException, SecurityException { checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true); - return getReflectionFactory().copyConstructor( - getConstructor0(parameterTypes, Member.DECLARED)); + return getConstructor0(parameterTypes, Member.DECLARED); } /** @@ -3056,6 +3004,180 @@ 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 concrete 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. @@ -3068,29 +3190,51 @@ } // No cached value available; compute value recursively. - // Start by fetching public declared methods... - PublicMethods pms = new PublicMethods(); - for (Method m : privateGetDeclaredMethods(/* publicOnly */ true)) { - pms.merge(m); + // 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()); } - // ...then recur over superclass methods... - Class sc = getSuperclass(); - if (sc != null) { - for (Method m : sc.privateGetPublicMethods()) { - pms.merge(m); - } - } - // ...and finally over direct superinterfaces. - for (Class intf : getInterfaces(/* cloneArray */ false)) { - for (Method m : intf.privateGetPublicMethods()) { - // static interface methods are not inherited - if (!Modifier.isStatic(m.getModifiers())) { - pms.merge(m); + 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); + } } - } - } - - res = pms.toArray(); + // 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; } @@ -3102,20 +3246,17 @@ // Helpers for fetchers of one field, method, or constructor // - // This method does not copy the returned Field object! private static Field searchFields(Field[] fields, String name) { + String internedName = name.intern(); for (Field field : fields) { - if (field.getName().equals(name)) { - return field; + if (field.getName() == internedName) { + return getReflectionFactory().copyField(field); } } return null; } - // Returns a "root" Field object. This Field object must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyField. - private Field getField0(String name) { + 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 @@ -3129,7 +3270,7 @@ return res; } // Direct superinterfaces, recursively - Class[] interfaces = getInterfaces(/* cloneArray */ false); + Class[] interfaces = getInterfaces(); for (Class c : interfaces) { if ((res = c.getField0(name)) != null) { return res; @@ -3147,85 +3288,87 @@ return null; } - // This method does not copy the returned Method object! private static Method searchMethods(Method[] methods, String name, Class[] parameterTypes) { - ReflectionFactory fact = getReflectionFactory(); Method res = null; + String internedName = name.intern(); for (Method m : methods) { - if (m.getName().equals(name) - && arrayContentsEq(parameterTypes, - fact.getExecutableSharedParameterTypes(m)) + if (m.getName() == internedName + && arrayContentsEq(parameterTypes, m.getParameterTypes()) && (res == null - || (res.getReturnType() != m.getReturnType() - && res.getReturnType().isAssignableFrom(m.getReturnType())))) + || res.getReturnType().isAssignableFrom(m.getReturnType()))) res = m; } - return res; - } - private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - - // Returns a "root" Method object. This Method object must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyMethod. - private Method getMethod0(String name, Class[] parameterTypes) { - PublicMethods.MethodList res = getMethodsRecursive( - name, - parameterTypes == null ? EMPTY_CLASS_ARRAY : parameterTypes, - /* includeStatic */ true); - return res == null ? null : res.getMostSpecific(); + return (res == null ? res : getReflectionFactory().copyMethod(res)); } - // Returns a list of "root" Method objects. These Method objects must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyMethod. - private PublicMethods.MethodList getMethodsRecursive(String name, - Class[] parameterTypes, - boolean includeStatic) { - // 1st check declared public methods - Method[] methods = privateGetDeclaredMethods(/* publicOnly */ true); - PublicMethods.MethodList res = PublicMethods.MethodList - .filter(methods, name, parameterTypes, includeStatic); - // if there is at least one match among declared methods, we need not - // search any further as such match surely overrides matching methods - // declared in superclass(es) or interface(s). - if (res != null) { + 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; - } - // if there was no match among declared methods, - // we must consult the superclass (if any) recursively... - Class sc = getSuperclass(); - if (sc != null) { - res = sc.getMethodsRecursive(name, parameterTypes, includeStatic); - } + // Not found on class or superclass directly + interfaceCandidates.removeLessSpecifics(); + return interfaceCandidates.getFirst(); // may be null + } - // ...and coalesce the superclass methods with methods obtained - // from directly implemented interfaces excluding static methods... - for (Class intf : getInterfaces(/* cloneArray */ false)) { - res = PublicMethods.MethodList.merge( - res, intf.getMethodsRecursive(name, parameterTypes, - /* includeStatic */ false)); + 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; } - - return res; + // Search superclass's methods + if (!isInterface()) { + Class 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; } - // Returns a "root" Constructor object. This Constructor object must NOT - // be propagated to the outside world, but must instead be copied - // via ReflectionFactory.copyConstructor. private Constructor getConstructor0(Class[] parameterTypes, int which) throws NoSuchMethodException { - ReflectionFactory fact = getReflectionFactory(); Constructor[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC)); for (Constructor constructor : constructors) { if (arrayContentsEq(parameterTypes, - fact.getExecutableSharedParameterTypes(constructor))) { - return constructor; + constructor.getParameterTypes())) { + return getReflectionFactory().copyConstructor(constructor); } } throw new NoSuchMethodException(getName() + "." + argumentTypesToString(parameterTypes));