提交 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,
}
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() {
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;
defaults = 0;
}
boolean hasDefaults() {
return defaults != 0;
}
void add(Method m) {
......@@ -2710,6 +2724,9 @@ public final class Class<T> implements java.io.Serializable,
methods = Arrays.copyOf(methods, 2 * methods.length);
}
methods[length++] = m;
if (m != null && m.isDefault())
defaults++;
}
void addAll(Method[] ma) {
......@@ -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) {
if (!Modifier.isStatic(candidate.getModifiers())) {
add(candidate);
......@@ -2759,19 +2779,35 @@ public final class Class<T> implements java.io.Serializable,
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++) {
Method m = methods[i];
if (m != null &&
m.getReturnType() == toRemove.getReturnType() &&
m.getName() == toRemove.getName() &&
arrayContentsEq(m.getParameterTypes(),
toRemove.getParameterTypes())) {
methods[i] = null;
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
......@@ -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() {
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,
// out concrete implementations inherited from superclasses at
// the end.
MethodArray inheritedMethods = new MethodArray();
Class<?>[] interfaces = getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
inheritedMethods.addAllNonStatic(interfaces[i].privateGetPublicMethods());
for (Class<?> i : getInterfaces()) {
inheritedMethods.addInterfaceMethods(i.privateGetPublicMethods());
}
if (!isInterface()) {
Class<?> c = getSuperclass();
......@@ -2832,8 +2906,10 @@ public final class Class<T> implements java.io.Serializable,
// interface methods
for (int i = 0; i < supers.length(); i++) {
Method m = supers.get(i);
if (m != null && !Modifier.isAbstract(m.getModifiers())) {
inheritedMethods.removeByNameAndSignature(m);
if (m != null &&
!Modifier.isAbstract(m.getModifiers()) &&
!m.isDefault()) {
inheritedMethods.removeByNameAndDescriptor(m);
}
}
// Insert superclass's inherited methods before
......@@ -2846,9 +2922,10 @@ public final class Class<T> implements java.io.Serializable,
// Filter out all local methods from inherited ones
for (int i = 0; i < methods.length(); i++) {
Method m = methods.get(i);
inheritedMethods.removeByNameAndSignature(m);
inheritedMethods.removeByNameAndDescriptor(m);
}
methods.addAllIfNotPresent(inheritedMethods);
methods.removeLessSpecifics();
methods.compactAndTrim();
res = methods.getArray();
if (rd != null) {
......@@ -2923,8 +3000,21 @@ public final class Class<T> implements java.io.Serializable,
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
......@@ -2932,6 +3022,14 @@ public final class Class<T> implements java.io.Serializable,
// 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),
......@@ -2953,7 +3051,7 @@ public final class Class<T> implements java.io.Serializable,
Class<?>[] interfaces = getInterfaces();
for (Class<?> c : interfaces)
if ((res = c.getMethod0(name, parameterTypes, false)) != null)
return res;
allInterfaceCandidates.add(res);
// Not found
return null;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册