I am making some additions to the serialize method of SerializationContext. (I will commit the changes after I do some more testing.)
I thought it would be a good idea to explain why the additions are useful. So here is the new serialize method signature. (The old signature is retained and delegates to the new method). public void serialize(QName elemQName, Attributes attributes, Object value, Class javaType, QName xmlType, // new boolean sendNull, // new boolean sendType) // new Here is a description of the old parameters: elemQName - This is the name of the element. Nothing fancy here. attributes - These are additional attributes that are to be serialized on the element. Normally one would pass in null. The serialize method is in charge of adding attributes to deal with types, null values and multi-ref values. value - This is the value to be serialized. Note that it is an Object, so if the value that you want serialized is a primitive it must be wrapped. javaType - This is a parameter that I added several months ago. The javaType is the class of the value. Why not just do a value.getClass()? Well...the value could be null or the value could be a wrapped primitive. So the javaType is necessary to know the class of the value and is very useful for distinguishing between actual primitives and wrappers. ------------------------ Problem 1: Isn't there something missing ? How does the serializer know what QName to use for the xsi:type attribute ? Prior to my change, it used the javaType information to get a type QName from the TypeMappingRegistry. However this algorithm has its flaws. For example a javaType=String.class actually has 2 type QNames (xsd:string and soapenc:string). The runtime will always pick xsd:string. This may cause a remote service to fail if it was expecting a soapenc:string. Solution 1: A new xmlType parameter: xmlType - This new parameter is the preferred type QName. If present, the serialize method will use the (javaType, xmlType) pair to find the appropriate serializer. If a serializer is not found, the code uses the old serializer search algorithm. This allows a custom serializer or meta data aware serializer to give the serialize method the proper xmlType from the wsdl/xml schema. Pretty cool! ------------------------ Problem 2: XML has two ways of dealing with missing information. 1) An element could be defined with the attribute xsi:nillable="true", which means that if the value is missing, the element should be serialized with the xsi:nil="true" flag. 2) An element could be defined with the attribute minOccurs="0", which means that if the value is missing, don't serialize it at all. The runtime (before my change) treats everything as (1). Solution 2: sendNull - The sendNull flag indicates how null values should be processed. The default (true) handles situation (1). And sendNull=false handles situation (2). This allows a custom serializer or meta data aware serializer to tell the serialize method how to deal with null values. --------------- Problem 3: Ever notice that xsi:types are serialized on every single element. It looks pretty silly to see an array that has arrayType="xsd:string[100]" followed by 100 items that each have xsi:type="xsd:string". There needs to be a way to turn off the xsi:type in a reasonable way. (Aside: I know there is a sendXSIType global property. But this doesn't cut the mustard. There are a number of problems with using the sendXSIType property: 1) When serialize is called, is the value serialized ? Uh No. If the item is an object it is simply stored away and serialized later. So toggling sendXSIType doesn't help much here. 2) We really want to only send the xsi:type when it is necessary. Lets say that we have an array with arrayType="my:Foo[100]". The xsi:type setting is not necessary for the array elements that are of type "my:Foo". However the xsi:type setting is necessary for the array elements that are derived from "my:Foo". ) Solution 3: sendType - The sendType flag works with the xmlType parameter. The default, sendType=true, is the current behavior, which cause xsi:type to be set for everything. The setting sendType=false, indicates that the xsi:type should not be sent if a serializer was found for the (javaType, xmlType) pair (i.e. if the value is not serialized in the expected way, attach an xsi:type.) I changed the ArraySerializer to use sendType=true so that it only uses xsi:type for array elements when truly necessary. Cool! There are other reasons to set sendType=true. i) Elements with anonymous types don't have a type QName. Axis sends a make-believe type qname over the wire in such cases. It would be nice to turn off this behavior! ii) The BeanDeserializer deserializes property values even if the xsi:type is not set. It automatically deserializes into the property type. So it might be an improvement to not serialize the xmi:types for bean properties when the javaType matches the bean property type. Aside: I ran the interop tests to verify my ArraySerializer changes. All of the remote services correctly handled the StringArray and IntegerArray without the xsi:types. However, some of the services could not handle StructArray...perhaps because the Struct array items are treated as multiref elements. So I made a small change to SerializationContext to make sure xsi:types are generated for multiref elements. ---------------------- Rich Scheuerle XML & Web Services Development 512-838-5115 (IBM TL 678-5115)