Version 3

    Using default and non-default constructors during unmarshalling

     

    Talking about object creation during unmarshalling, there are two questions to answer:

     

    1. How objects are created during unmarshalling?

    2. When objects are created during unmarshalling?

     

    To answer the first question, during unmarshalling, objects can be created using default no-arg or non-default constructors. What constructor is chosen to create an instance when both no-arg and non-default constructors are available is controlled by the 'useNoArgCtorIfFound' property in SchemaBinding. The default value of the property is false, meaning that the preference is given to a non-default constructor even if the default one is present.

     

    To answer the second question, an object can be created when parsing of the element just started (in other words, startElement callback is called if SAX parser is used) or when parsing of the element is finished (endElement callback is called), i.e. the contents of the element is parsed and unmarshalled.

     

    Obviously, we can't create an object using non-default constructor not having the arguments ready, i.e. to use non-default constructor we have to unmarshal the element's content first and create an instance after the element with its content is parsed.

    In case of the default constructor though, we can create an object before element is parsed and set unmarshalled content values on the object during element parsing.

     

    Setting the 'useNoArgCtorIfFound' property on SchemaBinding instance to true will make the unmarshaller to always use the default no-arg constructor (if the one is defined in the class) and create an instance before parsing of the element is complete. If there is no default constructor in the class though, we will fallback to non-default constructor.

     

    Using no-arg constructor as the first choice doesn't always work. For example, class java.lang.Exception has default constructor and constructors with message and cause parameters. There is no way the message and/or cause can be set on an instance of the java.lang.Exception after it is created.

     

    If the option 'useNoArgCtorIfFound' is set to false (which is the default), the unmarshaller will not create an object at the beginning of element parsing even if the default no-arg constructor is available. Instead, it will collect element's unmarshalled content values and at the end of the element parsing will try to find the "best-match" constructor to create an instance.

     

    How is the "best-match" constructor chosen?

     

    At the end of element parsing we have a collection of values that represent unmarshalled element's content including attributes, text content and child elements. These values are organized in a list in the order they were unmarshalled.

    To find the best constructor, we iterate through the declared constructors and choose the one that can accept the biggest number of unmarshalled content values. (Note, we still might actually end up using no-arg constructor here).

    If there are two (or more) constructors with equal number of parameters then the one with its parameter types closer to actual argument types in the class hierarchy is chosen.

    For example, if we need to create an instance of the following class

     

    public class MyClass
    {
       public String field1;
       public String field2;
    
       MyClass() {}
       MyClass(Object o) {this.field1 = (String)o;}
       MyClass(String s) {this.field1 = s;}
       MyClass(Object o1, Object o2) {this.field1 = (String)o1; this.field2 = (String)o2;}
       MyClass(String s1, String s2) {this.field1 = s1; this.field2 = s2;}
    }
    

     

    having two arguments of type java.lang.String, the last constructor with two parameters of type java.lang.String will be chosen.

     

    Values that couldn't be passed as arguments into the constructor will be set as property values on the instance using binding metadata if available.

     

    Repeatable particles and collection types

     

    Value of a repeatable particle (element, model group or wildcard that can appear more than once in XML content) is stored internally as an instance of java.util.Collection. What if the corresponding constructor parameter (or property) is of an array type or a different collection type? In this case, the unmarshaller will try to convert the collection value to the parameter (or property) type required.