Proposal: AMX Java Generics API Changes for AppServer 9.0

by Lloyd L Chambers
28 Feb 2006

1. Introduction

[This change has already been approved by asarch at its Feb 14, 2006 meeting. The author feels that the proposal is inappropriate for CCC review, but is submitting it per request].

This is a proposal to make a variety of "changes" to the AMX API involving the correct use of JDK 1.5 generic types. The word "changes" is quoted because the API is not changed semantically. This proposal affects only AppServer 9.0; it does not affect prior versions.

The proposal is in essence a bug-fix, because the current API:

  • uses generic types incorrectly in a number of cases;
  • does not use generic types in all appropriate cases.

See the specifics of the Proposal further on as well as the Impact Summary and Conclusion.

The benefits of this proposal include:

  • compile-time parameter-type checking, reducing programmer errors;
  • better documentation as to the semantics of the AMX APIs;
  • greater programmer convenience in being able to use the correct data types without the use of casts.

1.1 Method signatures (background)

Prior to JDK 1.5, generic types were not available, and all AMX methods were declared using "blind" Maps, Sets, etc:

CustomMBeanConfig createCustomMBeanConfig( ..., Map reserved );

Map getCustomMBeanConfigMap();


public Set queryJ2EETypeSet( String j2eeTypeValue );

With JDK 1.5, type-safe declarations may be utlized, thus allowing both more informative method signatures, as well as compile-time type checking:

CustomMBeanConfig createCustomMBeanConfig(..., Map<String,String> reserved);

public Map<String,CustomMBeanConfig> getCustomMBeanConfigMap();

public <T extends AMX> Set<T> queryJ2EETypeSet( String j2eeTypeValue );

1.2 Example of incorrect usage of generics

During the course of AppServer 9.0 development, some of the method signatures began to employ Generics. This had no effect on clients except for compiler warnings, as intended per the designers of Java Generics. Unfortunately, an inappropriate data type was used for many of these method signatures. For example, the following pre-9.0 style:

CustomMBeanConfig createCustomMBeanConfig( ..., Map reserved );

was changed to:

CustomMBeanConfig createCustomMBeanConfig( ..., Map<String,Object> reserved );

Due to the design of generics, a Map<String,String> cannot be passed to the above method! (See the Tutorial if you'd like to understand why).

2. Proposal

2.1 Require Map<String,String> for all create() methods

Change all create() methods with a signature using Map or Map<String,Object> to use Map<String,String>. The Map used in the create() methods is used only for optional parameters; all required ones are already explicit parameters. Example:

Something createSomething( String name, Map optional)
Something createSomething( String name, Map<String,Object> optional)
=> Something createSomething( String name, Map<String,String> optional )

This change allows the most common type of invocation of create() to compile (and to compile without warnings).  Currently, the following (correct) code will not compile due to the use of Map<String,Object>:

Map<String,String> optional = ....;
Something  newItem    = createSomething( ..., optional );

This API change restricts optional parameters to String. Values other than String were allowed before (though they were ultimately all converted to String anyway). Server-side code continues to accept such parameters (since the JDK doesn't and can't enforce the actual types inside a Map).

[Background note: The types Boolean, Long and Integer are infrequently used in the AMX API; our templated domain.xml ${...} approach doesn't allow for anything but String in most cases anyway; this "restriction" merely enforces what is already a requirement--and ultimately, everything becomes a String in domain.xml.  Furthermore, it is not possible to declare a Map which accounts for the actual semantics,  which were "only the following Serializable types: String, Integer, Long and Boolean".]

A further advantage of using Map<String,String> is that it allows for a future, backward compatible change to:

<T extends Serializable> Abc createAbc( ..., Map<String,T> );

The impact of this change is as follows:

  • 8.1/8.2 clients upgrading to 9.0: no impact; such users would see a compiler warning either way.
  • 9.0 clients which have converted to using generics (probably no such clients): code must be changed to use Map<String,String> instead of Map<String,Object>.

It should be emphasized there 9.0 has not shipped and therefore the number of 9.0 AMX clients is necessarily low, possibly zero. In short, there should be little or no impact.

2.2 To fix all other AMX APIs which have similar Generics issues.

Various other places employ Map, Set and List. All such sites would be modified to use generics.

Examples:

Map asMap()
=> Map<String,Serializable> asMap()

Iterator getSubStages()
=> Iterator<Map<String,Serializable>> getSubStages(
)

Map getAdditionalStatus()
=> Map<String,Serializable> getAdditionalStatus()

void startDeploy(Object deployID, Map source, Map plan, Map options)
=> <T extends Serializable> void startDeploy(Object deployID, Map<String,T> source, Map<String,T> plan, Map<String,String> options)

public Map getFinalDeploymentStatus(Object deployID)
=> public Map<String,Serializable> getFinalDeploymentStatus(Object deployID)

public Map undeploy(String moduleID, Map<String,Object> optionalParams)
=> public Map<String,Serializable> undeploy(String moduleID, Map<String,String> optionalParams)

3. Impact summary

Client using AMX in 8.1 or 8.2 who move their code to 9.0 would not be impacted by this change because Java Generics are backward compatible. The javac compiler issues warnings, but the code compiles and runs as before. In short, this change is irrelevant to such users.

Clients using AMX in 9.0 without Java Generics are impacted the same way as 8.1 and 8.2 clients: compiler warnings are the only side-effect. Clients which have started using Java Generics against the 9.0 AMX APIs would be impacted by needing to make trivial code changes to use the correct data type. Code already compiled would continue to work.

4. Conclusion

The impact is trivial to non-existent, depending on the specific case.

Failure to move ahead with this change introduces semi-permanent ugliness into the AMX APIs in which AMX clients will be forced to use the wrong data types and/or excessive casts to make code compile.

There are no support issues involved, nor are any tools needed for this change. Programmers using the AMX APIs who do not understand generics need to educate themselves just as they do when using the JDK itself.