提交 b3f1e174 编写于 作者: J jfranck

8029674: (reflect) getMethods returns default methods that are not members of the class

Summary: Filter out methods that have a more specific default method from result
Reviewed-by: darcy, dlsmith
上级 0c508c8b
...@@ -2697,12 +2697,26 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2697,12 +2697,26 @@ public final class Class<T> implements java.io.Serializable,
} }
static class MethodArray { static class MethodArray {
// Don't add or remove methods except by add() or remove() calls.
private Method[] methods; private Method[] methods;
private int length; private int length;
private int defaults;
MethodArray() { MethodArray() {
methods = new Method[20]; this(20);
}
MethodArray(int initialSize) {
if (initialSize < 2)
throw new IllegalArgumentException("Size should be 2 or more");
methods = new Method[initialSize];
length = 0; length = 0;
defaults = 0;
}
boolean hasDefaults() {
return defaults != 0;
} }
void add(Method m) { void add(Method m) {
...@@ -2710,6 +2724,9 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2710,6 +2724,9 @@ public final class Class<T> implements java.io.Serializable,
methods = Arrays.copyOf(methods, 2 * methods.length); methods = Arrays.copyOf(methods, 2 * methods.length);
} }
methods[length++] = m; methods[length++] = m;
if (m != null && m.isDefault())
defaults++;
} }
void addAll(Method[] ma) { void addAll(Method[] ma) {
...@@ -2743,7 +2760,10 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2743,7 +2760,10 @@ public final class Class<T> implements java.io.Serializable,
} }
} }
void addAllNonStatic(Method[] methods) { /* 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) { for (Method candidate : methods) {
if (!Modifier.isStatic(candidate.getModifiers())) { if (!Modifier.isStatic(candidate.getModifiers())) {
add(candidate); add(candidate);
...@@ -2759,19 +2779,35 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2759,19 +2779,35 @@ public final class Class<T> implements java.io.Serializable,
return methods[i]; return methods[i];
} }
void removeByNameAndSignature(Method toRemove) { Method getFirst() {
for (Method m : methods)
if (m != null)
return m;
return null;
}
void removeByNameAndDescriptor(Method toRemove) {
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++) {
Method m = methods[i]; Method m = methods[i];
if (m != null && if (m != null && matchesNameAndDescriptor(m, toRemove)) {
m.getReturnType() == toRemove.getReturnType() && remove(i);
m.getName() == toRemove.getName() &&
arrayContentsEq(m.getParameterTypes(),
toRemove.getParameterTypes())) {
methods[i] = null;
} }
} }
} }
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() { void compactAndTrim() {
int newPos = 0; int newPos = 0;
// Get rid of null slots // Get rid of null slots
...@@ -2789,9 +2825,48 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2789,9 +2825,48 @@ public final class Class<T> implements java.io.Serializable,
} }
} }
/* 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() { Method[] getArray() {
return methods; 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);
}
} }
...@@ -2819,9 +2894,8 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2819,9 +2894,8 @@ public final class Class<T> implements java.io.Serializable,
// out concrete implementations inherited from superclasses at // out concrete implementations inherited from superclasses at
// the end. // the end.
MethodArray inheritedMethods = new MethodArray(); MethodArray inheritedMethods = new MethodArray();
Class<?>[] interfaces = getInterfaces(); for (Class<?> i : getInterfaces()) {
for (int i = 0; i < interfaces.length; i++) { inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods());
inheritedMethods.addAllNonStatic(interfaces[i].privateGetPublicMethods());
} }
if (!isInterface()) { if (!isInterface()) {
Class<?> c = getSuperclass(); Class<?> c = getSuperclass();
...@@ -2832,8 +2906,10 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2832,8 +2906,10 @@ public final class Class<T> implements java.io.Serializable,
// interface methods // interface methods
for (int i = 0; i < supers.length(); i++) { for (int i = 0; i < supers.length(); i++) {
Method m = supers.get(i); Method m = supers.get(i);
if (m != null && !Modifier.isAbstract(m.getModifiers())) { if (m != null &&
inheritedMethods.removeByNameAndSignature(m); !Modifier.isAbstract(m.getModifiers()) &&
!m.isDefault()) {
inheritedMethods.removeByNameAndDescriptor(m);
} }
} }
// Insert superclass's inherited methods before // Insert superclass's inherited methods before
...@@ -2846,9 +2922,10 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2846,9 +2922,10 @@ public final class Class<T> implements java.io.Serializable,
// Filter out all local methods from inherited ones // Filter out all local methods from inherited ones
for (int i = 0; i < methods.length(); i++) { for (int i = 0; i < methods.length(); i++) {
Method m = methods.get(i); Method m = methods.get(i);
inheritedMethods.removeByNameAndSignature(m); inheritedMethods.removeByNameAndDescriptor(m);
} }
methods.addAllIfNotPresent(inheritedMethods); methods.addAllIfNotPresent(inheritedMethods);
methods.removeLessSpecifics();
methods.compactAndTrim(); methods.compactAndTrim();
res = methods.getArray(); res = methods.getArray();
if (rd != null) { if (rd != null) {
...@@ -2923,8 +3000,21 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2923,8 +3000,21 @@ public final class Class<T> implements java.io.Serializable,
return (res == null ? res : getReflectionFactory().copyMethod(res)); return (res == null ? res : getReflectionFactory().copyMethod(res));
} }
private Method getMethod0(String name, Class<?>[] parameterTypes, boolean includeStaticMethods) { 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 // Note: the intent is that the search algorithm this routine
// uses be equivalent to the ordering imposed by // uses be equivalent to the ordering imposed by
// privateGetPublicMethods(). It fetches only the declared // privateGetPublicMethods(). It fetches only the declared
...@@ -2932,6 +3022,14 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2932,6 +3022,14 @@ public final class Class<T> implements java.io.Serializable,
// number of Method objects which have to be created for the // number of Method objects which have to be created for the
// common case where the method being requested is declared in // common case where the method being requested is declared in
// the class which is being queried. // 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; Method res;
// Search declared public methods // Search declared public methods
if ((res = searchMethods(privateGetDeclaredMethods(true), if ((res = searchMethods(privateGetDeclaredMethods(true),
...@@ -2953,7 +3051,7 @@ public final class Class<T> implements java.io.Serializable, ...@@ -2953,7 +3051,7 @@ public final class Class<T> implements java.io.Serializable,
Class<?>[] interfaces = getInterfaces(); Class<?>[] interfaces = getInterfaces();
for (Class<?> c : interfaces) for (Class<?> c : interfaces)
if ((res = c.getMethod0(name, parameterTypes, false)) != null) if ((res = c.getMethod0(name, parameterTypes, false)) != null)
return res; allInterfaceCandidates.add(res);
// Not found // Not found
return null; return null;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册