JDK-6406447 : MXBean framework should support non-generic subclasses of generic classes
  • Type: Bug
  • Component: core-svc
  • Sub-Component: javax.management
  • Affected Version: 6
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2006-03-30
  • Updated: 2010-07-29
  • Resolved: 2006-07-01
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 6
6 b91Fixed
Related Reports
Relates :  
Relates :  
Description
Consider the following classes:

public class Gen<T> {
    public T getThing() {...}
}

public class NonGen extends Gen<String> {
    public String getThing() {...}
}

and an MXBean interface that references NonGen:

public interface TestMXBean {
    public NonGen getFoo();
}

We would expect this to work the same as if NonGen had no superclass.  But in fact it does not.  NonGen has a synthetic method (generated by the compiler) which looks like "public Object getThing()" and which calls the declared method "public String getThing()".  The MXBean framework sees the two methods called getThing() and complains.  It should recognize that this is covariance, using the same logic already present for MBean interfaces, and drop the covariantly-overridden method.

Ideally we would also like to be able to use this class:

public class NonGen extends Gen<String> {}

which does not override the getThing() method from Gen at all.  But this would require the MXBean framework to be able to match the return type T of the inherited getThing() method with the parameter T of the superclass.  The logic to do this correctly is not tremendously complicated but it's not trivial either, so given that there's a simple work-around (just override the method and call the superclass method from it) we can afford not to fix that problem for now.  The logic in question would basically have to run up the supertype hierarchy (the transitive closure of all superclasses and superinterfaces) while tracking the meaning of each type parameter as it goes.

Comments
EVALUATION Once CR 6337171 is fixed (in JDK 7), it should no longer be necessary to add an explicit override in cases like the public class NonGen extends Gen<String> {} mentioned in the Description.
31-10-2006

SUGGESTED FIX *** /tmp/old1167 Thu Mar 30 18:44:42 2006 --- OpenConverter.java Thu Mar 30 18:13:23 2006 *************** *** 413,426 **** (c.getName().equals("com.sun.management.GcInfo") && c.getClassLoader() == null); ! final Method[] methods = c.getMethods(); final SortedMap<String,Method> getterMap = newSortedMap(); /* Select public methods that look like "T getX()" or "boolean isX()", where T is not void and X is not the empty string. Exclude "Class getClass()" inherited from Object. */ ! for (int i = 0; i < methods.length; i++) { ! final Method method = methods[i]; final String propertyName = propertyName(method); if (propertyName == null) --- 413,426 ---- (c.getName().equals("com.sun.management.GcInfo") && c.getClassLoader() == null); ! final List<Method> methods = ! MBeanAnalyzer.eliminateCovariantMethods(c.getMethods()); final SortedMap<String,Method> getterMap = newSortedMap(); /* Select public methods that look like "T getX()" or "boolean isX()", where T is not void and X is not the empty string. Exclude "Class getClass()" inherited from Object. */ ! for (Method method : methods) { final String propertyName = propertyName(method); if (propertyName == null) *** /tmp/old1167 Thu Mar 30 18:44:42 2006 --- MBeanAnalyzer.java Thu Mar 30 18:13:22 2006 *************** *** 178,184 **** in the same order they arrived in. This isn't required by the spec but existing code may depend on it and users may be used to seeing operations or attributes appear in a particular order. */ ! private static List<Method> eliminateCovariantMethods(Method[] methodArray) { // We are assuming that you never have very many methods with the // same name, so it is OK to use algorithms that are quadratic --- 178,184 ---- in the same order they arrived in. This isn't required by the spec but existing code may depend on it and users may be used to seeing operations or attributes appear in a particular order. */ ! static List<Method> eliminateCovariantMethods(Method[] methodArray) { // We are assuming that you never have very many methods with the // same name, so it is OK to use algorithms that are quadratic *************** *** 212,219 **** return false; Class aclass = a.getDeclaringClass(); Class bclass = b.getDeclaringClass(); ! if (aclass == bclass || ! !bclass.isAssignableFrom(aclass) || !b.getReturnType().isAssignableFrom(a.getReturnType())) return false; Class[] ap = a.getParameterTypes(); --- 212,218 ---- return false; Class aclass = a.getDeclaringClass(); Class bclass = b.getDeclaringClass(); ! if (!bclass.isAssignableFrom(aclass) || !b.getReturnType().isAssignableFrom(a.getReturnType())) return false; Class[] ap = a.getParameterTypes();
30-03-2006

EVALUATION Simple to fix using the existing method MBeanAnalyzer.eliminateCovariantMethods. The logic for method overriding must be changed so it allows a method to covariantly-override another method in the same class. (This was not an issue before because we were only dealing with interfaces and the synthetic methods don't appear there.)
30-03-2006