JDK-8029459 : (reflect) getMethods returns methods that are not members of the class
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-12-03
  • Updated: 2017-01-05
  • Resolved: 2017-01-03
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b151Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Sub Tasks
JDK-8177360 :  
Description
Dan writes:

---

To illustrate, the JDK 7 implementation of getMethods includes the following:
1) The class's/interface's declared (public) methods
2) The getMethods() of the superclass (if this is a class), minus any that have a match in (1)
3) The getMethods() of each superinterface, minus any that have a match in (1) or a _concrete_ match in (2)

So, for example, as expected:
interface I { void m(); }
interface J extends I { void m(); }
interface K extends J {}
K.class.getMethods() = [ J.m ]

But:
interface I { void m(); }
interface J extends I { void m(); }
interface K extends ***I,*** J {}
K.class.getMethods() = [ I.m, J.m ]

This is consistent with a reasonable reading of JLS 7 (though it is vague)*, but conflicts with JLS 8.  We changed the 8 spec because, unlike abstract methods, inheriting two conflicting default methods is a compiler error, and that should be avoided.

[* There was a time when I thought the current behavior could be considered a 7 bug, but having experimented with it more, I no longer think that's the case.  This is a new issue in 8.]

An implementation of getMethods consistent with JLS 8 would include the following (see Lambda Spec, Part H, 9.4.1 and 8.4.8):
1) The class's/interface's declared (public) methods
2) The getMethods() of the superclass (if this is a class), minus any that have a match in (1)
3) The getMethods() of each superinterface, minus any that have a match in (1) or a _concrete_ match in (2) ***or a match from a more-specific class/interface in (2) or (3)***

However, there is a compatibility concern: the behavior of K.class.getMethods in the second example above changes.  How much do we care about this?  The spec change was made with the understanding that this was simply an internal change to an intermediate result, without observable consequences.  Reflection exposes that intermediate result.  But, even so, client code should not be depending on the rather vague notion of how many identical abstract methods are members of a class.

---

That is, the spec changed in 8 but the implementation (which was correct up through 7) has not changed.

This issue is for the general case, there is a separate issue: JDK-8029674 for the case of default methods, which  since new to the platform, has less of a compatibility baggage.

Comments
Re-application of fix for this bug is tracked by JDK-8172190
03-01-2017

Reopened because the change was backed out to resolve test failures
26-12-2016

FWIW (which may not be a lot) I just ran into this in the Panama project context, where I am experimenting with modeling c++ classes in Java. I had a hierarchy of interfaces which happens to mirror the original "interface K extends ***I,*** J {}" pretty much exactly, and I was surprised and puzzled by the fact that getMethods returned more than one method.
28-10-2016

The algorithm in above proposal does not do the following: An implementation of getMethods consistent with JLS 8 would include the following (see Lambda Spec, Part H, 9.4.1 and 8.4.8): 1) The class's/interface's declared (public) methods 2) The getMethods() of the superclass (if this is a class), minus any that have a match in (1) 3) The getMethods() of each superinterface, minus any that have a match in (1) or a _concrete_ match in (2) ***or a match from a more-specific class/interface in (2) or (3)*** as this definition has a flaw in the following example: interface E { void m(); } interface F extends E { void m(); } abstract class G implements E {} abstract class H extends G implements F {} H.class.getMethods() should return just {F::m}, not {E::m, F::m} (modulo Object methods) which would be the case when following above definition. In the proposed patch, Class::getMethods() returns: 1) The class's/interface's declared public methods (minus methods that loose to matching methods from (2) or (3) - there are none of that kind; ever); plus 2) The getMethods() of the superclass (if this is a class), minus methods that loose to matching methods from (1) or (3); plus 3) The non-static getMethods() of each superinterface, minus methods that loose to matching methods from (1), (2) or some other interface from (3) where: a "matching" method is a method with same name, parameter types and return type; and a method that "looses" to another matching method is a method that: - is declared by interface while another method is declared by class; or - is declared by a supertype of the other method's declaring type and both methods are either declared by interfaces or both by classes I think this is a more precise definition.
04-10-2016

Here is a proposal to fix this: http://cr.openjdk.java.net/~plevart/jdk9-dev/Class.getMethods.new/webrev.04/ This also fixes the related JDK-8062389 and JDK-8061950 bugs.
04-10-2016

Release team: Approved for deferral.
11-12-2013

IMO the spec is clear about this already. The javadoc refers to JLS which is clear about which methods are members and not, so there is no spec issue stopping us from fixing this in 8u. What I'm worried about here is the behavioral compatibility.
09-12-2013

OK with deferral, but would prefer it to be possible to fix in 8uX. Is there something we can add to the spec to make this more of a possibility?
06-12-2013

Release team: Mark to follow up with Brian on this one.
06-12-2013

8-defer justification: Proposing to defer this to 9. Changing the implementation for getMethods() has compatibility concerns that needs to be carefully considered. We do not lightly change behavior that clients may depend on, and reducing the set of returned methods can cause issues. We should revisit this early in 9 and communicate any changes here early and repeatedly. Note that I'm proposing to fix the default methods case ( JDK-8029674 ) in 8u20 since it has no compatibility baggage.
06-12-2013

The two attached files highlight the issue ILV: M (conformance), M (when reflecting over interfaces), M (rewrite the calling code to filter out the wrong ones) -> P3 edit: I'm lowering the impact to M because this behavior is consistent with the long standing (and until 8 correct) behavior of the platform
06-12-2013