src/share/classes/java/lang/Class.java
Print this page
rev 9896 : [mq]: patch-v1
*** 2694,2716 ****
}
return res;
}
static class MethodArray {
private Method[] methods;
private int length;
MethodArray() {
! methods = new Method[20];
length = 0;
}
void add(Method m) {
if (length == methods.length) {
methods = Arrays.copyOf(methods, 2 * methods.length);
}
methods[length++] = m;
}
void addAll(Method[] ma) {
for (Method m : ma) {
add(m);
--- 2694,2733 ----
}
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);
*** 2740,2750 ****
addIfNotPresent(m);
}
}
}
! void addAllNonStatic(Method[] methods) {
for (Method candidate : methods) {
if (!Modifier.isStatic(candidate.getModifiers())) {
add(candidate);
}
}
--- 2757,2770 ----
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);
}
}
*** 2756,2776 ****
Method get(int i) {
return methods[i];
}
! void removeByNameAndSignature(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;
}
}
}
void compactAndTrim() {
int newPos = 0;
// Get rid of null slots
--- 2776,2812 ----
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() &&
+ arrayContentsEq(m1.getParameterTypes(),
+ m2.getParameterTypes());
}
void compactAndTrim() {
int newPos = 0;
// Get rid of null slots
*** 2786,2798 ****
--- 2822,2873 ----
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
*** 2817,2839 ****
// 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.addAllNonStatic(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())) {
! inheritedMethods.removeByNameAndSignature(m);
}
}
// Insert superclass's inherited methods before
// superinterfaces' to satisfy getMethod's search
// order
--- 2892,2916 ----
// 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
*** 2842,2854 ****
}
}
// Filter out all local methods from inherited ones
for (int i = 0; i < methods.length(); i++) {
Method m = methods.get(i);
! inheritedMethods.removeByNameAndSignature(m);
}
methods.addAllIfNotPresent(inheritedMethods);
methods.compactAndTrim();
res = methods.getArray();
if (rd != null) {
rd.publicMethods = res;
}
--- 2919,2932 ----
}
}
// 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;
}
*** 2917,2935 ****
}
return (res == null ? res : getReflectionFactory().copyMethod(res));
}
-
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;
// Search declared public methods
if ((res = searchMethods(privateGetDeclaredMethods(true),
name,
parameterTypes)) != null) {
--- 2995,3034 ----
}
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) {
*** 2947,2957 ****
}
// Search superinterfaces' methods
Class<?>[] interfaces = getInterfaces();
for (Class<?> c : interfaces)
if ((res = c.getMethod0(name, parameterTypes, false)) != null)
! return res;
// Not found
return null;
}
private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
--- 3046,3056 ----
}
// 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,