![]() | ![]() | ![]() | ![]() | ![]() | ![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ![]() | ![]() | ![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ![]() | ![]() | ![]() | ![]() | ![]() | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() | ![]()
|
Castor XML Mapping 1 Introduction 2 Overview 2.1 Marshalling Behavior 2.2 Unmarshalling Behavior 3. The Mapping File 3.1 The 3.2 The 3.3 The 3.4 The 3.5 The 4. Usage Pattern 5. TODO 1 IntroductionAlthough 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 field information from the mapping file to determine if 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 find 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( 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 and expect an element/attribute named 'xxx-yyy'. The only handled collections for For primitive 3. The Mapping File3.1 The |
- | an optional description |
- | zero or more |
- | zero or more |
- | zero or more |
A mapping file look like this:
Description of the mapping ......... .........
The
Description of the attributes:
- | name: the name of the Java class that we want to map to. It should look like 'mypackage.myclass' |
- | extends: should be used _only_ if this class extends another class for which mapping information is provided. It should _not_ be used if the extended class is not used in the mapping file. |
- | depends: for more information on this fields, see JDO documentation. |
- | identity: for more information on this fields, see JDO documentation |
- | access: for more information on this fields, see JDO documentation |
- | key-generator: for more information on this fields, see JDO documentation |
Description of the content:
- | description: an optional |
- | cache-type: for more information on this field, see JDO documentation |
- | an optional |
- | field: zero or more |
If you want to map the following class into the element '':
package mypackage public class myclass { ... public int foo; ... public String getBar() ... public void setBar(String bar) ... }
Into an XML document like:
...
You might use the following mapping file:
... ...
- | for marshalling, infer the name of the element to be mapped from the name of the class: a Java class named 'XxxYyy' will be transformed into 'xxx-yyy'. |
- | for unmarshalling, infer the name of the class from the name of the element : for an element named 'test-element' Castor will try to use a class named 'TestElement' |
Description of the attributes:
- | xml: name of the element that the class is associated to. |
- | ns-uri: namespace URI |
- | ns-prefix: desired namespace |
- | ldap-dn: not used for XML |
- | ldap-oc: not used for XML |
- | its identity ('name') |
- | its type (infered from 'type' and 'collection') |
- | its access method (infered from 'direct', 'get-method', 'set-method') |
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
- | If there is no 'collection' attribute, the
Castor will try to cast the data in the XML file in the proper Java type. | |||||||||||||||||||||||||||||||||||||||||||||||||||
- | If there is a collection attribute, you can use the following table:
The type of the object inside the collection is For hashtable and map, Castor will add an object with put(object, object): the object is both the key and the value. This will be improved in the future. |
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;
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:
publicor();
public void( value);
If 'get-method' or 'set-method' attributes are not provided, Castor will try to find the following function:
publicorget ();
public void set( value);
The content of
Description of the attributes:
- | name: The field 'name' is required even if no such field exists in the class. If 'direct' access is used, 'name' should be the name of a public variable in the object we are mapping (The field must be public, not static and not transient). If no direct access and no 'get-/set-method' is specified, this name will be used to infer the name of the accessors methods. |
- | type: the Java type of the field. It is used to access the field. Castor will use this information to cast the XML information (like string into integer). It is also used to define the signature of the accessors method. If a collection is specified, this is used to specify the type of the object inside the collection. See description above for more details. |
- | required: the field can the optional or required |
- | direct: if true, Castor will expect a public variable in the object and will modify it directly |
- | collection: if a parent expects more than one occurrence of one of its element, it is necessary to specify which collection Castor will use to handle them. The type specified is used to define the type of the content inside the collection. |
- | get-method: optional name of the get method Castor should use. If this attribute is not set, Castor will try to guess the name with the algorithm described above. |
- | set-method: optional name of the set method Castor should use. If this attribute is not set, Castor will try to guess the name with the algorithm described above. |
- | create-method: Factory method for instantiation of FieldHandler |
Description of the content:
In the case of XML mapping, the content of a field element should be one and only one
Description of the attributes:
- | name: the name of the element or attribute |
- | type: xsi::type |
- | matches: not used |
- | node: indicates if the name corresponds to an attribute, an element, or text content. By default, primitive types are assumed to be an attribute otherwise the node is assumed to be an element |
Here 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:
- | MyOrder: represent an order |
- | Client: used to store information on the client |
- | Item: used to store item in an order |
The sources of these classes follow.
MyOrder.java |
---|
import java.util.Vector; import java.util.Enumeration; public class MyOrder { private String _ref; private ClientData _client; private Vector _items; private float _total; public void setReference(String ref) { _ref = ref; } public String getReference() { return _ref; } public void setClientData(ClientData client) { _client = client; } public ClientData getClientData() { return _client; } public void setItemsList(Vector items) { _items = items; } public Vector getItemsList() { return _items; } public void setTotal(float total) { _total = total; } public float getTotal() { return _total; } // Do some processing on the data public float getTotalPrice() { float total = 0.0f; for (Enumeration e = _items.elements() ; e.hasMoreElements() ;) { Item item = (Item) e.nextElement(); total += item._quantity * item._unitPrice; } return total; } } |
ClientData.java |
---|
public class ClientData { private String _name; private String _address; public void setName(String name) { _name = name; } public String getName() { return _name; } public void setAddress(String address) { _address = address; } public String getAddress() { return _address; } } |
Item.java |
---|
public class Item { public String _reference; public int _quantity; public float _unitPrice; } |
The XML document and the java object model can be connected by using the following mapping file:
mapping.xml |
---|
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.
main.java |
---|
import org.exolab.castor.mapping.Mapping; import org.exolab.castor.mapping.MappingException; import org.exolab.castor.xml.Unmarshaller; import org.exolab.castor.xml.Marshaller; import java.io.IOException; import java.io.FileReader; import java.io.OutputStreamWriter; import org.xml.sax.InputSource; public class main { public static void main(String args[]) { Mapping mapping = new Mapping(); try { // 1. Load the mapping information from the file mapping.loadMapping( "mapping.xml" ); // 2. Unmarshal the data Unmarshaller unmar = new Unmarshaller(mapping); MyOrder order = (MyOrder)unmar.unmarshal(new InputSource(new FileReader("order.xml"))); // 3. Do some processing on the data float total = order.getTotalPrice(); System.out.println("Order total price = " + total); order.setTotal(total); // 4. marshal the data with the total price back and print the XML in the console Marshaller marshaller = new Marshaller(new OutputStreamWriter(System.out)); marshaller.setMapping(mapping); marshaller.marshal(order); } catch (Exception e) { System.out.println(e); return; } } } |
Discuss about the use of XSI:type + xsi:type="java:xxx"