JDK-6250772 : Some classes in JMX API mix generic and raw types
  • Type: Bug
  • Component: core-svc
  • Sub-Component: javax.management
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2005-04-05
  • Updated: 2017-05-16
  • Resolved: 2005-05-14
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 b37Fixed
Related Reports
Relates :  
Relates :  
Description
In the generification of the JMX API for Mustang, some classes contain references to both generic types such as List<Attribute> and raw types such as ArrayList.  This is considered bad practice.  To quote ###@###.###, "Raw types are for legacy code interoperability. If you are aware of generics and are generifying your code, make it consistently generic."
###@###.### 2005-04-05 16:18:09 GMT

Comments
EVALUATION Need to revisit the generification so we no longer mix generic and raw types. Here is a first pass: AttributeList, RoleList, and RoleUnresolvedList currently extend raw ArrayList rather than ArrayList<Attribute> etc, because of compatibility problems with method return types. But they have constructors such as AttributeList(List<Attribute>) and methods such as List<Attribute> asList(), so they are generics-aware. The proposed solution is to extend ArrayList<Object> and document why this is so. TabularDataSupport implements raw Map. Either it must make no references to generic types, or it must implement some parameterization of Map. TabularDataSupport behaves like a Map<List<?>,CompositeData> but we cannot change it to implement that, because that would make the return type of e.g. remove(Object) change from Object to CompositeData, and break code that might have subclassed TabularDataSupport and overridden remove(Object). On the other hand, we can safely implement Map<List<?>,Object> because there are no methods in Map<K,V> that return K. Thus, keySet() returns Set<List<?>> and entrySet() returns Set<Map.Entry<List<?>,Object>>. The interface TabularData is implemented by TabularDataSupport. Its keySet() method should return Set<List<Object>> rather than plain Set, as suggested by RFE 5100192. Its values() method can unfortunately at best return Collection<?> rather than the true Collection<CompositeData> since TabularDataSupport.values() must return Collection<Object>. In OpenMBeanParameterInfo, OpenMBeanAttributeInfoSupport, and OpenMBeanParameterInfoSupport there are methods that refer to raw Set and Comparable. These should be Set<?> and Comparable<?>. The interface ClassLoaderRepository should refer to Class<?> rather than Class. ###@###.### 2005-04-05 16:18:09 GMT Concerning AttributeList etc, we should have the following behaviour: * If you call AttributeList(List<Attribute>), it should throw a ClassCastException if the List contains an element that is not an Attribute. This can happen in code that gets "unchecked" warnings, for example if you pass a raw List to this constructor. * If you call AttributeList.asList(), and the AttributeList contains an element that is not an attribute, it should throw a ClassCastException. * Once asList() has been called on a given AttributeList instance, an attempt to add an item to the list that is not an Attribute should throw a ClassCastException. This means that the List<Attribute> that the caller of asList() has received is guaranteed to be type-safe. We have to allow people to add non-Attribute objects to the AttributeList for compatibility reasons, but since the asList() method is new, we know that code that calls it is new too and we don't need to preserve this ability. * The same changes should be applied mutatis mutandis to RoleList and RoleUnresolvedList. ###@###.### 2005-04-12 14:41:16 GMT Slightly changes to the aboved proposition: send IllegalArgumentException instead of ClassCastException to preserve existing behavior in RoleList(List<Role>) and RoleUnresolvedList(List<RoleUnresolved>). We should have the following behaviour: * If you call AttributeList(List<Attribute>), it should throw an IllegalArgumentException if the List is null or contains an element that is not an Attribute. This can happen in code that gets "unchecked" warnings, for example if you pass a raw List to this constructor. * If you call AttributeList.asList(), and the AttributeList contains an element that is not an attribute, it should throw an IllegalArgumentException. * Once asList() has been called on a given AttributeList instance, an attempt to add an item to the list that is not an Attribute should throw a IllegalArgumentException. This means that the List<Attribute> that the caller of asList() has received is guaranteed to be type-safe. We have to allow people to add non-Attribute objects to the AttributeList for compatibility reasons, but since the asList() method is new, we know that code that calls it is new too and we don't need to preserve this ability. * The same changes should be applied mutatis mutandis to RoleList and RoleUnresolvedList. ###@###.### 2005-04-14 07:47:42 GMT --- TabularData and TabularDataSupport --- TabularDataSupport implements raw Map. Either it must make no references to generic types, or it must implement some parameterization of Map. TabularDataSupport behaves like a Map<List<?>,CompositeData> but we cannot change it to implement that, because that would make the return type of e.g. remove(Object) change from Object to CompositeData, and break code that might have subclassed TabularDataSupport and overridden remove(Object). We cannot either change it to Map<List<?>,Object> because the inherited Map<K,V> method put(K,V) would behave like put(List<?>,Object) and this could break existing code which does not pass a List as the first parameter. Finally, we can safely implement Map<Object,Object>, thus keySet() returns Set<Object>, values() returns Collection<Object> and entrySet() returns Set<Map.Entry<Object,Object>>. However in the javadoc we will explicitly document that keySet() returns Set<List<?>>, values() returns Collection<CompositeData> and entrySet() returns Set<Map.Entry<List<?>,CompositeData>> but we declared them to return Set<Object>, Collection<Object> and Set<Map.Entry<Object,Object>> for compatibility reasons. The interface TabularData is implemented by TabularDataSupport. Its keySet() method can unfortunately at best return Set<?> rather than the true Set<List<?>> since TabularDataSupport.keySet() must return Set<Object>. Its values() method can unfortunately at best return Collection<?> rather than the true Collection<CompositeData> since TabularDataSupport.values() must return Collection<Object>. ###@###.### 2005-04-15 16:20:34 GMT
05-04-2005