| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Castor XML Mapping 1 Introduction 2 Overview 2.1 Marshalling Behavior 2.2 Unmarshalling Behavior 3. The Mapping File 3.1 The <mapping> element 3.2 The <class> element 3.3 The <map-to> element 3.4 The <field> element 3.5 The <bind-xml> element 4. Usage Pattern 5. xsi:type 6. Location attribute 7. Tips 7.1 Automatically create a mapping file 7.2 Create your own FieldHandler 7.3 Mapping constructor arguments 7.4 Preventing Castor from checking for a default constructor 7.5 Type safe enumeration mapping 1 IntroductionCastor XML mapping is a way to simplify the binding of java classes to XML document. It allows to transform the data contained in a java object model into/from an XML document. Although it is possible to rely on Castor's default behavior to marshal and unmarshal Java objects into an XML document, it might be necessary to have more control over this behavior. For example, if a Java object model already exists, Castor XML Mapping can be used as a bridge between the XML document and that Java object model. Castor allows one to specify some of its marshalling/unmarshalling behavior using a mapping file. This file gives explicit information to Castor on how a given XML document and a given set of Java objects relate to each other. A Castor mapping file is a good way to dissociate the changes in the structure of a Java object model from the changes in the corresponding XML document format. 2 OverviewThe mapping information is specified by an XML document. This document is written from the point of view of the Java object and describes how the properties of the object have to be translated into XML. One constraint for the mapping file is that Castor should be able to infer unambiguously from it how a given XML element/attribute has to be translated into the object model during unmarshalling. The mapping file describes for each object how each of its fields have to be mapped into XML. A field is an abstraction for a property of an object. It can correspond directly to a public class variable or indirectly to a property via some accessor methods (setters and getters). It is possible to use the mapping and Castor default behavior in conjunction: when Castor has to handle an object or an XML data but can't find information about it in the mapping file, it will rely on its default behavior. Castor will use the Java Reflection API to introspect the Java objects to determine what to do. Note: Castor can't handle all possible mappings. In some complex cases, it may be necessary to rely on an XSL transformation in conjunction with Castor to adapt the XML document to a more friendly format. 2.1 Marshalling BehaviorFor Castor, a Java class has to map into an XML element. When Castor marshals an object, it will:
or
It will then use the fields information from the mapping file to determine how a given property of the object has to be translated into one and only one of the following:
This process will be recursive: if Castor finds a property that has a class type specified elsewhere in the mapping file, it will use this information to marshal the object. By default, if Castor finds no information for a given class in the mapping file, it will introspect the class and apply a set of default rules to guess the fields and marshal them. The default rules are as follows:
2.2 Unmarshalling BehaviorWhen Castor finds an element while unmarshalling a document, it will try to use the mapping information to determine which object to instantiate. If no mapping information is present, Castor will use the name of the element to try to guess the name of a class to instantiate (for example, for an element named 'test-element', Castor will try to instantiate a class named 'TestElement' if no information is given in the mapping file). Castor will then use the field information of the mapping file to handle the content of the element. If the class is not described in the mapping file, Castor will instrospect the class using the Java Reflection API to determine if there is any function of the form getXxxYyy()/setXxxYyy(<type> x). This accessor will be associated with XML element/attribute named 'xxx-yyy'. In the future, we will provide a way to override this default behavior. Castor will introspect object variables and use direct access _only_ if no get/set methods have been found in the class. In this case, Castor will look for public variables of the form: public <type> xxxYYY; and expect an element/attribute named 'xxx-yyy'. The only handled collections for <type> are java.lang.Vector and array. (up to version 0.8.10) For primitive <type>, Castor will look for an attribute first and then an element. If <type> is not a primitive type, Castor will look for an element first and then an attribute. 3. The Mapping File3.1 The <mapping> element<!ELEMENT mapping ( description?, include*, class*, key-generator* )> The <mapping> element is the root element of a mapping file. It contains:
A mapping file look like this: <?xml version="1.0"?> <!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD Version 1.0//EN" "/mapping.dtd"> <mapping> <description>Description of the mapping</description> <include href="other_mapping_file.xml"/> <class name="A"> ......... </class> <class name="B"> ......... </class> </mapping> 3.2 The <class> element<!ELEMENT class ( description?, cache-type?, map-to?, field+ )> <!ATTLIST class name ID #REQUIRED extends IDREF #IMPLIED depends IDREF #IMPLIED auto-complete ( true |false ) "false" identity CDATA #IMPLIED access ( read-only | shared | exclusive | db-locked ) "shared" key-generator IDREF #IMPLIED > The <class> element contains all the information used to map a Java class into an XML document. The content of <class> is mainly used to describe the fields that will be mapped. Description of the attributes:
The auto-complete attributes is interesting as it allow a fine degree of control of the introspector: it is possible to specifiy only the fields whose Castor default behavior does not suite our needs. These feature should simplify the handling of complexe class containing many fields. Description of the content:
If you want to map the following class into the element '<data>': package mypackage public class myclass { ... public int foo; ... public String getBar() ... public void setBar(String bar) ... } Into an XML document like: <data foo-like="12"> <something> ... </something> </data> You might use the following mapping file: <mapping> ... <class name="mypackage.myclass"> <map-to xml="data"/> <field name="foo" direct="true" .... > <bind-xml name="foo-like" node="attribute"/> </field> </field name="bar" .... > <bind-xml name="something" node="element"/> </field> </class> ... </mapping> 3.3 The <map-to> element<!ELEMENT map-to EMPTY> <!ATTLIST map-to table NMTOKEN #IMPLIED xml NMTOKEN #IMPLIED ns-uri NMTOKEN #IMPLIED ns-prefix NMTOKEN #IMPLIED ldap-dn NMTOKEN #IMPLIED ldap-oc NMTOKEN #IMPLIED> <map-to> is used to specify the name of the element that should be associated with the given class.<map-to> is only used for the root class. If this information is not present, Castor will:
Description of the attributes:
3.4 The <field> element<!ELEMENT field ( description?, sql?, bind-xml?, ldap? )> <!ATTLIST field name NMTOKEN #REQUIRED type NMTOKEN #IMPLIED handler NMTOKEN #IMPLIED required ( true | false ) "false" direct ( true | false ) "false" lazy ( true | false ) "false" transient ( true | false ) "false" get-method NMTOKEN #IMPLIED set-method NMTOKEN #IMPLIED create-method NMTOKEN #IMPLIED collection ( array | vector | hashtable | collection | set | map ) #IMPLIED> <field> is used to describe a property of a Java object we want to marshal/unmarshal. It gives:
From this information, Castor is able to access a given property in the Java class. In order to determine the signature that Castor expects, there are two easy rules to apply. 1. Determine <type>.
It is necessary to use a collection when the content model of the element expects more than one element of the specified type. 2. Determine the signature of the function If 'direct' is set to true, Castor expects to find a class variable with the given signature: public <type> <name>; If 'direct' is set to false or omitted, Castor will access the property though accessor methods. Castor determines the signature of the accessors as follow: If the 'get-method' or 'set-method' attributes are supplied, it will try to find a function with the following signature: public <type> <get-method>();or public void <set-method>(<type> value); If 'get-method' and 'set-method' attributes are not provided, Castor will try to find the following function: public <type> get<capitalized-name>();or public void set<capitalized-name>(<type> value); <capitalized-name> means that Castor takes the <name> attribute and put its first letter in uppercase without modifying the other letters. The content of <field> will contain the information on how to map this given field to SQL, XML, ... Description of the attributes: Description of the content: In the case of XML mapping, the content of a field element should be one and only one <xml> element describing how this given field will be mapped into the XML document. 3.5 The <bind-xml> element<!ELEMENT bind-xml (class?, property*)> <!ATTLIST bind-xml name NMTOKEN #IMPLIED type NMTOKEN #IMPLIED location CDATA #IMPLIED matches NMTOKENS #IMPLIED QName-prefix NMTOKEN #IMPLIED reference ( true | false ) "false" node ( attribute | element | text ) #IMPLIED auto-naming ( deriveByClass | deriveByField ) #IMPLIED transient ( true | false ) "false"> <bind-xml> is used to describe how a given Java field should appear in an XML document. It is used both for marshalling and unmarshalling. Description of the attributes:
4. Usage PatternHere is an example of how Castor Mapping can be used. We want to map an XML document like the following one (called 'order.xml'). model.
Into the following object model composed of 3 classes:
The sources of these classes follow.
The XML document and the java object model can be connected by using the following mapping file:
The following class is an example of how to use Castor XML Mapping to manipulate the file 'order.xml'. It unmarshals the document 'order.xml', computes the total price, sets the total price in the java object and marshals the object model back into XML with the calculated price.
5. xsi:typeOrdinarily, a mapping will only reference types that are concrete classes (i.e. not interfaces nor abstract classes). The reason is that to unmarshal a type requires instantiating it and one cannot instantiate an interface. However, in many real situations, object models depend on the use of interfaces. Many class properties are defined to have interface types to support the ability to swap implementations. This is often the case in frameworks. The problem is that a different mapping must be used each time the same model is to be used to marshal/unmarshal an implementation that uses different concrete types. This is not convenient. The mapping should represent the model and the specific concrete type used to unmarshal a document is a configuration parameter; it should be specified in the instance document to be unmarshalled, not the mapping. For example, assume a very simple object model of an engine that has one property that is a processor: public interface IProcessor { public void process(); } .. public class Engine { private IProcessor processor; public IProcessor getProcessor() { return processor; } public void setProcessor(IProcessor processor) { this.processor = processor; } } A typical mapping file for such a design may be: <mapping> <class name="Engine"> <map-to xml="engine" /> <field name="processor" type="IProcessor" required="true"> <bind-xml name="processor" node="element" /> </field> </class> </mapping> It is possible to use such a mapping and still have the marshal/unmarshal process work by specifying the concrete implementation of IProcessor in the document to be unmarshalled, using the xsi:type attribute, as follows: <engine> <processor xsi:type="java:com.abc.MyProcessor" /> </engine> In this manner, one is still able to maintain only a single mapping, but vary the manner in which the document is unmarshalled from one instance document to the next. This flexibility is powerful because it enables the support of polymorphism within the castor xml marshalling framework. Suppose we wanted the following XML instead: <engine> <myProcessor/> </engine> In the above output our XML name changed to match the type of the class used instead of relying on the xsi:type attribute. This can be achieved by modifying the mapping file as such: <mapping> <class name="Engine"> <map-to xml="engine" /> <field name="processor" type="IProcessor" required="true"> <bind-xml auto-naming="deriveByClass" node="element" /> </field> </class> <class name="MyProcessor"> <map-to xml="myProcessor" /> </class> </mapping> 6. Location attributeSince 0.9.5 The location attribute allows the user to map fields from nested elements or specify a wrapper element for a given field. Wrapper elements are simply elements which appear in the XML instance, but do not have a direct mapping to an object or field within the object model. For example to map an instance of the following class: One would use the following mapping: 7. TipsSome helpful hints... 7.1 Automatically create a mapping fileCastor comes with a tool that can automatically create a mapping from class files. Please see the XML FAQ for more information. 7.2 Create your own FieldHandlerSometimes to handle complex situations you'll need to create your own FieldHandler. Normally a FieldHandler deals with a specific class and field, however generic, reusable FieldHandlers can also be created by extending org.exolab.castor.mapping.GeneralizedFieldHandler or org.exolab.castor.mapping.AbstractFieldHandler. The FieldHandler can be specified on the <field> element. 7.3 Mapping constructor argumentsSince: 0.9.5You may map any attributes to constructor arguments. Mapping elements to constructor arguments is not yet supported. For more information on how to map constructor arguments see the information available in the section on set-method above. 7.4 Preventing Castor from checking for a default constructorSince: 0.9.5Sometimes it's useful to prevent Castor from checking for a default constructor, such as when trying to write a mapping for an interface or type-safe enum. You can use the "undocumented" verify-constructable="false" attribute on the <class> element to prevent Castor from looking for the default constructor. 7.5 Type safe enumeration mappingSince: 0.9.5While you can always use your own custom FieldHandler for handling type-safe enumeration classes, Castor does have a built-in approach to dealing with these types of classes. If the type-safe enum class has a public static <type> valueOf(String) method Castor will call that method so that the proper instance of the enumeration is returned. Note: You'll also need to disable the default constructor check in the mapping file (see section 7.4 above to see more on this). | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||