XmlBeans Binding Config File
Again, sketches and thoughts. For context see XmlBeansV2BindingArch
The actual schema for binding config will certainly differ from this doc in details; if the copy checked into cvs differs from the doc, trust cvs. (a pointer to a place in cvs will be needed here).
This is NOT the binding configuration file that users typically work with unless they are starting from both Java and XML. Other binding configuration files (JSR 109 jaxrpc-mapping.xml, or JAXB's configuration file) are translated into binding-config.xml.
This config file does represent all the capabilities of the v2 binding framework. It is the configuration file used when starting from both-java-and-schema. So we will be treating it as a public format, carefully specifying and documenting it, even though it is "for advanced users only".
The binding config file is organized as follows:
Top level structure
At the top-level, it is organized as three things:
a list of binding types <binding-types>
a list of schema components <schema-components>
a list of java classes <java-types>
Binding-types list
The binding-types list describes all the bindings that can be done. There are different kinds of bindings, structured as follows:
- Each binding type describes the correspondence between a Java class and an XML Schema component. A Schema component may be a type, element, particle, (or other component).
- The type pair (Java class, Schema component) for each binding type is unique. If multiple binding config files are being used (e.g., arranged on the classpath), then there is a path searching algorithm and the first found entry masks the others for a given type pair.
- Nested inside each binding type is arbitrary configuration information specific to the kind of binding type. The information may in turn refer to other binding types e.g., via a "property"; references to other binding types are done by referring to the unique type (J,X) type pair.
Schema components list
The schema-components list describes the primary binding to use for any given schema component (we will describe mappings only for types and global elements). These primiary bindings are used at compiletime when generating Java for a given schema, and at runtime when interpreting wildcards and xsi:types.
- Each entry maps a schema component to either, or both, a pojo and an xmlobj style java class.
- Each entry must map a unique schema component.
If multiple binding config files are used, schema component entries are masked componentwise. For example, a schema component entry for a pojo style binding only will mask the pojo style binding for that schema component entry in another file, but will not mask the xmlobj style binding in that file.
Java-types list
The java-types list describes the primary binding to use for any given java class or interface. These primiary bindings are used at compiletime when generating schema for a given Java class, and at runtime when interpreting instances of subclasses where getClass() is more specific than the declared signature.
- Each entry maps a java class to a schema component.
- The java class entries must be unique.
Builtins
The system will have a set of binding-types, schema components, and java types that are built-in. For example, it knows that xs:string corresponds to java.lang.String (pojo) as well as org.apache.xmlbeans.XmlString (xmlobj). In principle the user can override these settings by placing their own configuration first on the compiletime and deploymenttime classpath.
An example:
<bind:binding-config xmlns:bind="http://apache.org/xmlbeans/binding-config">
{{{ <bind:binding-types>
<bind:binding-type xsi:type="bind:jaxb-bean">
<javatype>com.myco.mypack.CustRecord</javatype>
<xmlcomponent>T=CustomerRecord@http://www.myco.com/schemas</xmlcomponent>
... etc ...
</bind:binding-type>
<bind:binding-type xsi:type="bind:by-name-bean" xmlobj="true">
... etc ...
</bind:binding-type>
</bind:binding-types>
<bind:xml-components>
<bind:schema-component xmlcomponent="T=CustomerRecord@http://www.myco.com/schemas" pojotype="com.myco.mypack.CustRecord"/>
<bind:schema-component .../>
... etc ...
</bind:xml-componnets>
<bind:java-types>
<bind:schema-component javatype="com.myco.mypack.CustRecord" xmlcomponent="T=CustomerRecord@http://www.myco.com/schemas"/>
<bind:schema-component .../>
... etc ...
</bind:java-types> </bind:binding-config>
- }}}
Therefore, this specification will outline
- Information common to all binding types
- A catalog of specific kinds of binding types
Kinds of Binding Types
Base Binding-Type
There is a base binding-type that represents all the information that all the kinds of binding types have in common. Here is the schema declaration: basically, all binding types have a javatype, a corresponding xmlcomponent, and some information about the Java such as how to instantiate it, whether or not it inherits from XmlObject, and whether or not it is an interface.
<xs:complexType name="binding-type" abstract="true">
<xs:sequence>
<xs:element name="javatype" type="tns:java-class-name"/>
<xs:element name="instancetype" type="tns:java-class-name" minOccurs="0"/>
<xs:element name="xmlcomponent" type="tns:xml-signature"/>
</xs:sequence>
<xs:attribute name="xmlobj" type="xs:boolean"/>
<xs:attribute name="interface" type="xs:boolean"/>
</xs:complexType>
ByNameBean
A "by-name bean binding" is superficially similar only permits "qname-properties".
An example by-name-bean configuration:
<binding-type xsi:type="content-model-bean">
<javatype>com.myco.mypack.CustRecord</javatype>
<xmlcomponent>T=CustomerRecord@http://www.myco.com/schemas</xmlcomponent>
<!-- example of a by-name property -->
<property xsi:type="by-name-property">
<javatype>java.lang.String</javatype>
<xmlcomponent>T=string@http://www.w3.org/2001/XMLSchema</xmlcomponent>
<getter>getFirstName</getter>
<setter>setFirstName</setter>
<qname>myco:first-name</qname>
</property>
<!-- example of a by-name property -->
<property xsi:type="by-name-property">
<javatype>java.lang.String</javatype>
<xmlcomponent>T=string@http://www.w3.org/2001/XMLSchema</xmlcomponent>
<getter>getLastName</getter>
<setter>setLastName</setter>
<qname>myco:last-name</qname>
</property>
<!-- example of a by-name property -->
<property xsi:type="by-name-property">
<javatype>java.util.Calendar</javatype>
<xmlcomponent>T=string@http://www.w3.org/2001/XMLSchema</xmlcomponent>
<getter>getBirthday</getter>
<setter>setBirthday</setter>
<qname>myco:birthday</qname>
</property>
</binding-type> When serialzing a by-name-bean, any properties that are present are simply serialized in the order in which they are described in the binding config. An extensibility model might be worked out to allow a coder to specify order in a programmable way.
Here is the schema for the by-name-bean type:
<xs:complexType name="by-name-bean">
<xs:complexContent>
<xs:extension base="tns:binding-type">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="qname-property" type="tns:qname-property"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType> It might look like it should be a restriction of the jaxb-bean type, but they are not semantically related in that way.
The qname-property contains the same information as a qname-property that is used in the content-model-bean type, so it is exactly the same type (until we convince ourselves that it is not).
JaxbBean
A "Jaxb bean binding" binds a JavaBean-style class with getters and setters to an XML component (which may be a type, an element, a model group, or a subparticle of a content model).
It has any number of "binding properties". A binding property is something that binds some kind of XML into a JavaBean style property (get/set or field). The Java type of the property may be just about anything, i.e., doesn't need to itself be a jaxb-bean type.
There are two kinds of binding properties which can be used inside a content model bean:
{{{ 1. A by-name property. This binds a QName of an element (or attribute)
- to a Java getter/setter. Deserialization of a by-name property is easy. Serialization requires that the content model tree be "solved", i.e., analyzed to see which properties are present and absent so we know which branch of each nested choice is being followed. Note that one name can appear more than once in a content model, so that's what makes serialzation "sovling" interesting.
- A by-particle property. This binds a specific particle in the
- content model tree (can't be the root; that's us...) to a Java getter/setter. Deserialization is driven by a content model "validator state machine". Serialization is also done by "solving" the content model tree, but in this case, since a particle can appear exactly in place in a content model, the contribution to the "solver" is less intrciate. Note that a general-content property is just a by-particle property whose type happens to bind a specific particle in the content model tree (can be the root, right?) to a Java getter/setter whose Java type is a List or [] of javax.xml.bind.Elemnts that is bound in general-content style. }}}
Although it is possible to have a jaxb-bean that has only by-name properties, this case should not be confused with the by-name-bean, because serailization and deserialization in the JAXB case is aware of the content model even in the simple case.
{{{ 1. Deserialization does depend on using the content model validator.
- In particular, unbounded choice groups cannot be deserialized in a "order-doesn't-matter" using a jaxb-bean, although they can be deserialized that way using a by-name-bean.
- Serialization participates in "solving". Rather than inferring a
- simple order from the order of the properties in the binding config as is done in the by-name-bean, the order is inferred by solving the content model based on the properties that are present in the instance. }}}
JAXB will not, by default, produce ByNameBean bindings. However, it would make sense to supply a compiletime option to our JAXB compiler to ask it to "optimize" similar ContentModelBindings to faster (but slightly different) ByNameBean bindings.
An example jaxb-bean configuration:
<binding-type xsi:type="jaxb-bean">
<javatype>com.myco.mypack.CustRecord</javatype>
<xmlcomponent>T=CustomerRecord@http://www.myco.com/schemas</xmlcomponent>
<!-- example of a by-name property -->
<property xsi:type="by-name-property">
<type>builtin:dateTimeToCalendar</type>
<getter>getBirthday</getter>
<setter>setBirthday</setter>
<qname>myco:birthday</qname>
</property>
<!-- example of a by-particle property -->
<property xsi:type="by-particle-property">
<javatype>ZipCodeOrState</javatype>
<xmlcomponent>T=zipCodeOrState@somenamespace</xmlcomponent>
<getter>getZipCodeOrState</getter>
<setter>setZipCodeOrState</setter>
<particle>P=choice.3|P=sequence.0</particle>
</property>
<!-- example of a general-content property -->
<property xsi:type="by-particle-property">
<javatype>javax.xml.bind.Element</javatype>
<xmlcomponent>P=choice.1|T=CustomerRecord@somenamespace</xmlcomponent>
<getter>getRelatives</getter>
<collection>java.util.List</collection>
<particle>P=choice.5|P=sequence.0</particle>
</property>
<!-- example of a general-content property in array style with indexed setters -->
<property xsi:type="by-particle-property">
<javatype>javax.xml.bind.Element</javatype>
<xmlcomponent>P=choice.1|T=CustomerRecord@somenamespace</xmlcomponent>
<getter>getRelatives</getter>
<setter>setRelatives</setter>
<collection>array</collection>
<indexed-setter>setRelativesAt</indexed-setter>
<particle>P=choice.5|P=sequence.0</particle>
</property>
</binding-type>
What follows is the schema type definition for content-model-bean. Note that it can have any nubmer of properties of either qname-property or particle-property type.
<xs:complexType name="jaxb-bean">
<xs:complexContent>
<xs:extension base="tns:binding-type">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="binding-property" type="tns:binding-property"/>
<xs:element name="qname-property" type="tns:qname-property"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType> What follows is the schema type definition for the base class for binding-property. A property, for us, is any binding strategy that binds to a JavaBean getter/setter/field or static. The different subtypes of binding properties indicate different ways of locating data in the XML.
<xs:complexType name="binding-property" abstract="true">
<xs:sequence>
<xs:element
<xs:choice>
<xs:sequence>
<xs:element name="getter" type="tns:java-property-name"/>
<xs:element name="setter" type="tns:java-property-name" minOccurs="0"/>
</xs:sequence>
<xs:element name="field" type="tns:java-field-name"/>
<xs:element name="static" type="tns:java-field-name"/>
</xs:choice>
<xs:element name="collection" type="tns:java-class-name" minOccurs="0"/>
<xs:element name="has-is-set" type="xs:boolean" minOccurs="0" default="false"/>
</xs:sequence>
</xs:complexType> The first subtype of binding-property, here, extracts data from XML based on QName. It can point to either element or attribute qnames, and it can be configured to withstand elements that are repeatable, optional, or nillable.
<xs:complexType name="qname-property">
<xs:complexContent>
<xs:extension base="tns:binding-property">
<xs:sequence>
<xs:element name="qname" type="xs:QName"/>
<xs:element name="attribute" type="xs:boolean" default="false"/>
<xs:element name="multiple" type="xs:boolean" default="false"/>
<xs:element name="nillable" type="xs:boolean" default="false"/>
<xs:element name="optional" type="xs:boolean" default="false"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType> The second subtype of binding-property, here, extracts data from XML based on its location in a validated particle tree. To identify the particle being bound, we use a tns:xml-signature which is specified elsewhere (XmlSignature to be written). The idea is basically to provide a path to the particle by navigating the content tree.
<xs:complexType name="particle-property">
<xs:complexContent>
<xs:extension base="tns:binding-property">
<xs:sequence>
<xs:element name="particle" type="tns:xml-signature"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
JaxbList
Generic content models in JAXB do not map to JavaBeans. Rather they map to Lists or arrays of javax.xml.bind.Element.
In order to deserialize these lists, we need to know the set of elements that are expected. In particular, we need to make sure we can differentiate between global elemements that are allowed (e.g., via wildcard) and local elements.
Here is how it works:
<binding-type xsi:type="jaxb-list">
<javatype>java.util.List</javatype>
<xmlcomponent>P=choice.3|etc.</xmlcomponent>
<!-- example of set of element bindings to expect -->
<expect type="bind:fatherToFatherElement"/>
<expect type="bind:motherToMotherElement"/>
<expect type="bind:sisterToSisterElement"/>
<expect type="bind:brotherToBrotherElement"/>
<expectMixedContent/>
<expectWildcardElement/>
</binding-type> The only kinds of types that can appear in the list are types that bind to global or local element definitions. Mixed content and wildcard bindings are dealt with separately.
Simple-Custom-Codec
Example:
<binding-type xsi:type="simple-type">
<javatype>com.myco.mypack.MySpecialDate</javatype>
<xmlcomponent>T=my-date-type@http://www.myco.com/schemas</xmlcomponent>
<parse>com.myco.mypack.Utils.parseMySpecialDate</parse>
<print>com.myco.mypack.Utils.parseMySpecialDate</print>
</binding-type> For well-known types (implementation dependent) there are special entries that do not specify a codec, and builtin behavior is used.
<binding-type xsi:type="simple-type">
<javatype>java.lang.String</javatype>
<xmlcomponent>T=string@http://www.w3.org/2001/XMLSchema</xmlcomponent>
</binding-type> Note: sort of want these physically inside xmlbeans.jar so that if they put a typelib jar before ours on the classpath, they can override us, but if they put theirs after, we can override them.