United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4847959 JMX API should use generics where applicable
JDK-4847959 : JMX API should use generics where applicable

Submit Date:
Updated Date:
Project Name:
Resolved Date:
Affected Versions:
Fixed Versions:

Related Reports

Sub Tasks

JMX as integrated into J2SE should use generics in its interfaces.
Through the magic of type erasure this should not affect portability
of JMX client code to standalone JMX 1.2.

Here is a possibly incomplete list of changes:

MBeanServer[Connection].queryMBeans should return Set<ObjectInstance>.
MBeanServer[Connection].queryNames should return Set<ObjectName>.
AttributeChangeNotificationFilter.getEnabledAttributes should return Vector<String>.
AttributeList should extend ArrayList<Attribute>.
MBeanServerFactory.findMBeanServer should return ArrayList<MBeanServer>.
NotificationFilterSupport.getEnabledTypes should return Vector<String>.
ObjectName's constructor and getInstance method that take a Hashtable should take a Hashtable<String,String>.
ObjectName.getKeyPropertyList should return Hashtable<String,String>.
MLetMBean and MLet's methods getMBeansFromURL cannot use generics because the elements of the returned Set can be either ObjectInstance or Throwable.
CompositeType.keySet should return Set<String>.
Not sure about some other keySet methods in openmbean package.
TabularType.getIndexNames should return List<String>.
Relation.getReferencedMBeans should return Map<ObjectName,ArrayList<String>>.
In RelationServiceMBean:
- findAssociatedMBeans returns Map<ObjectName,ArrayList<String>>.
- findRelationsOfType returns List<String>.
- getRole returns List<ObjectName>.
- findReferencingRelations returns Map<String,ArrayList<String>>.
- getAllRelationIds returns List<String>.
- getAllRelationTypeNames returns List<String>.
- getRoleInfos returns List<RoleInfo>.
- getReferencedMBeans returns Map<ObjectName,ArrayList<String>>.
- sendRelationRemovalNotification takes List<ObjectName>.
- updateRoleMap takes List<ObjectName>.
- sendRoleUpdateNotification takes List<ObjectName>.
- sendRoleUpdateNotification takes List<ArrayList>.

RelationType.getRoleInfos returns List<RoleInfo>.
MBeanServerNotificationFilter.get{Enabled|Disabled}ObjectNames returns Vector<ObjectName>.

- constructor arg theUnregMBeanList should be List<ObjectName>.
- constructor args the{New|Old}RoleValue should be List<ObjectName>.
- getMBeansToUnregister returns List<ObjectName>.
- get{Old|New}RoleValue returns List<ObjectName>.

RelationService methods specified by RelationServiceMBean need same changes as it.
RelationSupport methods specified by Relation need same changes as it.
RelationTypeSupport.getRoleInfos returns List<RoleInfo>.
Role constructor and getRoleValue use List<ObjectName>.
RoleList extends List<Role>.
RoleUnresolved uses List<ObjectName>.
RoleUnresolvedList extends ArrayList<RoleUnresolved>.
Timer[MBean].get[All]NotificationIDs returns Vector<Integer>.



This is more or less a mechanical transformation.
Methods that return collection types such as List, Vector, Map, Hashtable,
ArrayList, should where possible return parameterised types such as List<String>.
Arguments to methods and constructors that are of collection types should where possible parameterise them.  This may cause warnings for client code.  For example, if we change the constructor ObjectName(String,Hashtable) into ObjectName(String,Hashtable<String,String>), then existing code that calls this constructor with Hashtable alone will produce a warning (probably not even that if -source 1.5 is not specified).  But it will compile and work.  From the JSR 14 spec:

"The reverse assignment from Vector to Vector<String> is unsafe from the standpoint of the generic semantics (since the vector might have had a different element type), but is still permitted in order to enable interfacing with legacy code. In this case, a compiler will issue a warning message that the assignment is deprecated."

As a minimum test of correctness, the genericized code must compile without warning and the existing JMX 1.2 TCK must pass (except possibly the signature test).
###@###.### 2003-04-15

Unfortunately, making this change in Tiger conflicts with the inclusion of JMX 1.2 in J2EE 1.4.  With this change in place, it would be possible to write JMX code that compiles with J2EE 1.4 + J2SE 1.5 but not with J2EE 1.4 + J2SE 1.4, even though it uses an interface (JMX 1.2) that is supposed to be present in J2EE 1.4.  So we cannot make this change before the next revision of J2SE.
(Example: ObjectName[] names = MBeanServer.queryNames().toArray(new ObjectName[0]).  With J2SE 1.4, requires a cast (ObjectName[]).)
###@###.### 2003-09-23

Unfortunately making this change to J2SE 1.5 could cause any implementation of J2EE 1.4 to fail the signature test from the J2EE Compatibility Test Suite.  So we can't make this change now.  It will have to wait for the next version of J2SE.
###@###.### 2003-11-26

Reopening this bug and committing for Mustang (J2SE 6.0).
###@###.### 2004-07-09

I have now made a generification pass over the JMX API.  The changes in the Description section could all be applied, except that AttributeList, RoleList, and RoleUnresolvedList cannot be made to extend ArrayList<Attribute> (etc) rather than plain ArrayList.  The reason is that they all define e.g.
    void add(Attribute attr);
whereas ArrayList<Attribute> defines
    boolean add(Attribute o);
The conflicting return types mean that AttributeList no longer compiles if it is made to extend ArrayList<Attribute>.  Instead, we can define a constructor:
    AttributeList(List<Attribute> list)
to convert from a List<Attribute> to an AttributeList, and a method:
    List<Attribute> asList()
to convert back (in fact, an unsafe cast suffices for the latter).  The same remarks apply for RoleList and RoleUnresolvedList except that they already have a (List) constructor which just needs to be generified.

There are some additional opportunities for generification:

- MBeanServerInvocationHandler.newProxyInstance can be defined as:
    public static <T> T newProxyInstance(..., Class<T> interfaceClass, ...)
  which means that where you previously wrote:
    MyMBean proxy = (MyMBean) MBSIH.newProxyInstance(..., MyMBean.class, ...)
  you can now omit the cast.

- The two-argument StandardMBean constructor can be generified as:
    public <T> StandardMBean(T impl, Class<T> mbeanInterface)
  which means that the compiler will check that impl does
  indeed implement the given interface.

- OpenType can be generified as OpenType<T> so that the Java type of
  the corresponding instances can be specified.  For example,
  SimpleType.INTEGER is an OpenType<Integer>; every CompositeType
  is an OpenType<CompositeData>.  This allows the compiler to check
  that the default, legal, and bound values in an OpenMBeanAttributeInfo
  or OpenMBeanParameterInfo are valid for the given OpenType.  Thus we
  have e.g. this generified constructor:
    public <T> OpenMBeanParameterInfoSupport(String name,
                                             String description,
                                             OpenType<T> openType,
                                             T defaultValue)

- MBeanServerPermission.elements returns Enumeration<Permission>.
###@###.### 2004-08-27

JMX as integrated into J2SE should use
generic types in parameters and return values.

BugTraq+ Release Management Values



Concerning the SDN comment about the use of ArrayList in the API:

I think everyone can agree that the API should not have used ArrayList anywhere.  But that dates from the earliest days of the API, when best practices for API design were perhaps less well-known.

I do not think there is anything to gain from adding parallel methods that return List.  For example, we could certainly add MBeanServerFactory.findMBeanServer2 that returns List<MBeanServer>.  However, that would be awkward, since we would have to invent a different name for every such new method; two methods can't differ only in their return types.  And it would make no real difference to users of the API, who can and should already write:

List<MBeanServer> servers = MBeanServerFactory.findMBeanServer(...);

Fortunately, the API doesn't contain any places where *parameters* use concrete Collection types rather than interfaces.  That would be much more inconvenient for users.

A further restriction is that we cannot add new methods to interfaces if there is any chance that user code might have implemented those interfaces.  Since we don't explicitly discourage that anywhere, that means that all interfaces in the API are frozen.

The generification rationale at http://weblogs.java.net/blog/emcmanus/archive/generification.txt may be of interest for further information about the details of how this API was generified.

Hardware and Software, Engineered to Work Together