JDK-5072004 : Better support for schema evolution in CompositeData and CompositeType
  • Type: Enhancement
  • Component: core-svc
  • Sub-Component: javax.management
  • Affected Version: 6
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2004-07-07
  • Updated: 2017-05-16
  • Resolved: 2006-04-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.
6 b81Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  

CompositeType.isValue, following the inherited contract for OpenType.isValue, tests whether its argument is a CompositeData whose CompositeType is equal to this one.  In other words, the CompositeData must have exactly the same item names and types as described in this CompositeType.  This is needlessly restrictive, and harms schema evolution.  Instead, CompositeType.isValue should return true provided that its argument is a CompositeData whose CompositeType is an improper superset of this one.  In other words, the CompositeData argument can contain extra items and they will be ignored by isValue.

This allows new items to be added to the information model.  A peer (client or server) that does not know about those new items will never see them, and if takes the trouble to call isValue it will accept the newer CompositeData.


When a newer client or server receives a CompositeData from a possibly older peer, the added items may be missing.  The newer peer of course knows that the items are new, and should add default values to the CompositeData when they are missing.  It would be convenient if CompositeDataSupport had a constructor to simplify this:

    public CompositeDataSupport(CompositeType type,
                                CompositeData cd,
                                String[] defaultNames,
                                Object[] defaultValues)


    public CompositeDataSupport(CompositeType type,
                                CompositeData cd,
                                Map<String,?> defaults)

If an item is in the CompositeType argument, but is in neither the CompositeData nor the defaults, then that should generate an exception.  Trying to fabricate a default value as a convenience (e.g. 0 for a SimpleType.INTEGER) seems tricky, particularly in the more complicated cases (e.g. when the missing item is itself a CompositeData or TabularData).  This is not much of a convenience and loses error-checking.

EVALUATION The specification of CompositeType.isValue has been extended so it will ccept a CompositeData that has additional items beyond the ones in the CompositeType, provided it does have all the values in the CompositeType. Thus, a client that only references these items (because it has an earlier version or is only relying the standard items) will continue to work, but a client that knows the additional items can access them. This change also impacts TabularType.isValue and ArrayType.isValue, since TabularData contains a CompositeData, and arrays can also contain CompositeData. For the moment, there is no public isAssignableFrom method.

EVALUATION A case where this would be useful is the Hotspot extension to the standard java.lang.management.GarbageCollectorMXBean. This defines a field called LastGcInfo which is mapped to a CompositeData containing some standard fields, plus some gc-type-specific fields. The derived CompositeType should include the standard fields, but a mapped CompositeData may contain additional ones.

EVALUATION This question was recently raised on the JMX-FORUM; see <http://archives.java.sun.com/cgi-bin/wa?A1=ind0512&L=jmx-forum>. An important point that was raised there is that TabularDataSupport will refuse to add a row if that row's CompositeType is not exactly equal to the tabularDataSupport.getRowType(). So we don't support schema evolution very well in this case. Here's what I wrote on the forum: <<< Making this work the way we would like appears moderately tricky, especially since we don't want to change the behaviour of any existing code. In particular we have to consider nested CompositeData, which is presumably subject to the same constraints. What we might imagine would be the following. We add to OpenType a new method isAssignableFrom(OpenType) that looks like this: public abstract class OpenType<T> implements Serializable { ... public boolean isAssignableFrom(OpenType<?> ot) { return this.equals(ot); } } Then in CompositeType we override this method and we add a new constructor that says whether type matching is strict: public class CompositeType extends OpenType<CompositeData> { ... public CompositeType(String typeName, String description, String[] itemNames, String[] itemDescriptions, OpenType<?>[] itemTypes, boolean allowExtraItems) { ... this.allowExtraItems = allowExtraItems; } public boolean allowExtraItems() { return allowExtraItems; } @Override public boolean isAssignableFrom(OpenType<?> ot) { if (!allowExtraItems) return equals(ot); if (!(ot instanceof CompositeType)) return false; CompositeType ct = (CompositeType) ot; for (String key : ct.keySet()) { OpenType<?> otItemType = ct.getType(key); OpenType<?> thisItemType = getType(key); if (thisItemType == null || !thisItemType.isAssignableFrom(otItemType)) return false; } return true; } ... } So if ct1 and ct2 are both CompositeTypes, and if ct1.allowExtraItems(), then ct1.isAssignableFrom(ct2) is true if all the items in ct2 also appear in ct1 with the same name and compatible type. However this only addresses schema evolution in one direction, where ct2 is more recent than ct1 and therefore contains more items. We'd really like to address the case where ct2 is less recent and is missing some items. We could cover this case by allowing the constructor of CompositeType to specify a default value for certain items. If ct2 is missing some items, but all of those items have default values, then isAssignableFrom returns true. >>>

EVALUATION This seems obviously right to allow new items to be added during schema evolution. There does not seem to be any correspondingly obvious way to allow items to be removed, so the suggestion is that they cannot be. ###@###.### 2004-07-07 The CompositeData.values() method will probably need to be deprecated for schema evolution to work reliably. Since this method returns values in lexicographical order of the item names, if new items are added then the Collection returned by CompositeData.values() will be meaningless to a peer that does not know about them. This method is not of much obvious use anyway, except possibly to call toString() on the Collection. The proposed MXBean framework should mean that people no longer deal with CompositeData directly anyway. ###@###.### 2004-07-08 This support is not strictly necessary for MXBeans. MXBeans can use concrete Java classes for value types and they can add a @PropertyNames annotation (formerly @GetterNames) to more than one constructor. Evolution works as follows. The initial version of a value type has exactly one constructor with a @PropertyNames annotation. If a subsequent version adds further fields, then it adds another constructor with a @PropertyNames annotation mentioning the existing and new fields. The previous constructor retains its @PropertyNames annotation. When a class has more than one @PropertyNames constructor, it must be possible to order them such that the names for any constructor are a subset of the names for all subsequent constructors. When a CompositeData is to be converted into an instance of such a class, then the constructor to be used is the last one in the order just mentioned where all of the names are present in the CompositeData. For example, if we have this class: public class Thing { @PropertyNames({"a"}) Thing(int a) {...} @PropertyNames({"a", "b"}) Thing(int a, long b) {...} @PropertyNames({"a", "b", "c"}) Thing(int a, long b, String c) {...} } then a CompositeData with items "a" and "b" would use the second constructor, while a CompositeData with items "a", "b", and "c" would use the third. A CompositeData with items "a", "b", and "x" would also use the second constructor. This would imply that the CompositeData came from code where class Thing evolved differently. ###@###.### 2005-05-03 15:46:35 GMT

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mustang

PUBLIC COMMENTS Allow new items to be added to CompositeType as used in an information model.