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)

Reply via email to