venerdì 19 luglio 2013

Castor data binding framework mapping XMLGregorianCalendar

Castor data binding framework mapping XMLGregorianCalendar

The goal of this article is to show how to carry out complex castor mapping and to share a knowledge that I've just gained on how to map javax.xml.datatype.XMLGregorianCalendar within castor.
Castor supports lots of system types except javax.xml.datatype.XMLGregorianCalendar.

So, how can I tackle this issue?
I've started thinking on how I can provide a mecchanism to make this javax.xml.datatype.XMLGregorianCalendar date field work in castor context mapping?

The answer was YES

In effect, this is not what I consider a proper article, but a sort of hand to those who might go through this kind of issue.
Well, to give a hand to those who might face this issue, I have built a simple eclipse project to make this solution easier to comprehend.

Components that make up this small but working solution

@XmlType

org.sample.castor.Customer
org.sample.castor.Order
org.sample.castor.OrderResponse
org.sample.castor.Orders

#Manipolatore (Handler) del campo data javax.xml.datatype.XMLGregorianCalendar
org.sample.castor.handler.OrderDateHandler

org.sample.castor.util.DateUtil
#Main class nel package di default

default/OrderManager
# Mapping file

mapping.xml

#Main class
import java.io.InputStream;
import java.io.StringReader;
import java.util.List;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;
import org.exolab.castor.xml.XMLContext;
import org.sample.castor.Order;
import org.sample.castor.OrderResponse;
import org.sample.castor.Orders;
import org.xml.sax.InputSource;

public class OrderManager {

    private static StringBuffer message;

    static{
        message = new StringBuffer();
        message.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        message.append("<ns2:orderResponse xmlns:ns2=\"http://org.sample.castor\">\n");
        message.append("   <customer>\n");
        message.append("       <id>101</id>\n");
        message.append("       <name>Paolo</name>\n");
        message.append("       <surname>Rossi</surname>\n");
        message.append("       <address>Via della Giustiniana, 71</address>\n");
        message.append("       <email>p.rossi@gmail.com</email>\n");
        message.append("   </customer>\n");
        message.append("   <orders>\n");
        message.append("         <order>\n");
        message.append("          <id>701</id>\n");
        message.append("          <description>Order 701</description>\n");
        message.append("          <orderDate>2013-03-23T00:00:00+02:00</orderDate>\n");
        message.append("         </order>\n");     
        message.append("         <order>\n");
        message.append("          <id>702</id>\n");
        message.append("          <description>Order 702</description>\n");
        message.append("          <orderDate>2013-07-23T00:00:00+02:00</orderDate>\n");
        message.append("         </order>\n");
        message.append("   </orders>\n");
        message.append("</ns2:orderResponse>\n");

    } 

 

    public static void main(String[] args) throws MappingException, MarshalException, ValidationException {     

        InputStream istream = OrderManager.class.getResourceAsStream("mapping.xml");
        System.out.println(message.toString());
        InputSource is = new InputSource(istream);

        // Load Mapping
        Mapping mapping = new Mapping();
        mapping.loadMapping(is);

        // initialize and configure XMLContext
        XMLContext context = new XMLContext();
        context.addMapping(mapping);

        // Create a new Unmarshaller
        Unmarshaller unmarshaller = context.createUnmarshaller();
        unmarshaller.setClass(OrderResponse.class);     

        is.setCharacterStream(new StringReader(message.toString()));     
        OrderResponse orderResponse = (OrderResponse)unmarshaller.unmarshal(is); 

        System.out.println(orderResponse);
        System.out.println(orderResponse.getCustomer().getId());
        System.out.println(orderResponse.getCustomer().getName());
        System.out.println(orderResponse.getCustomer().getSurname());
        System.out.println(orderResponse.getCustomer().getAddress());
        System.out.println(orderResponse.getCustomer().getEmail());

     
        Orders orders = orderResponse.getOrders();
        for(Order order : orders.getOrders()){
            System.out.println(order.getId());
            System.out.println(order.getOrderDate());
            System.out.println(order.getDescription());
        }
    }
}

#Simple dto/xsd

package org.sample.castor;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "customer", namespace="http://org.sample.castor", propOrder = {
    "id",
    "name",
    "surname",
    "address",
    "email"
})
public class Customer implements Serializable{

    private long id;
    private String name;
    private String surname;
    private String address;
    private String email;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

#Simple dto/xsd

package org.sample.castor;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.datatype.XMLGregorianCalendar;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "order", namespace="http://org.sample.castor", propOrder = {
    "id",
    "orderDate",
    "description"
})

public class Order implements Serializable{

    private long id;
    private XMLGregorianCalendar orderDate;
    private String description;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public XMLGregorianCalendar getOrderDate() {
        return orderDate;
    }

    public void setOrderDate(XMLGregorianCalendar orderDate) {
       this.orderDate = orderDate;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}

#Simple dto/xsd

package org.sample.castor;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)

@XmlType(name = "orderResponse", namespace="http://org.sample.castor", propOrder = {
    "customer", 
    "orders"
})

public class OrderResponse implements Serializable{

    private Customer customer;
    private Orders orders;

    public Orders getOrders() {
        return orders;
    }

    public void setOrders(Orders orders) {
        this.orders = orders;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }
}

#Simple dto/xsd

package org.sample.castor;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "orders", namespace="http://org.sample.castor", propOrder = {
    "orders"
})

public class Orders {

    private List<Order> orders; 

    public List<Order> getOrders() {
        if (orders == null) {
            orders = new ArrayList<Order>();
        }
        return this.orders;
    } 
}

#Handler

package org.sample.castor.handler;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.datatype.DatatypeConfigurationException;
import org.exolab.castor.mapping.FieldHandler;
import org.exolab.castor.mapping.ValidityException;
import org.sample.castor.Order;
import org.sample.castor.util.DateUtil;

public class OrderDateHandler implements FieldHandler{

    private static final String FORMAT = "yyyy-MM-dd";

    /**
     * Creates a new OrderDateHandler instance
     */

    public OrderDateHandler() {
        super();
    }

    public Object getValue(final Object object) throws IllegalStateException {

        Order root = (Order)object;
        Date value = new Date(); //root.getDate();

        if (value == null) return null;

        SimpleDateFormat formatter = new SimpleDateFormat(FORMAT);
        Date date = (Date)value;
        return formatter.format(date);
    }

    public void setValue(Object object, Object value)

       throws IllegalStateException, IllegalArgumentException {
    
        Order root = (Order)object;
        SimpleDateFormat formatter = new SimpleDateFormat(FORMAT);
        Date date = null;

        try {
            date = formatter.parse((String)value);
        }

        catch(ParseException px) {
            throw new IllegalArgumentException(px.getMessage());
        }

        try {
            root.setOrderDate(DateUtil.toXMLGregorianCalendar(date));
        } catch (DatatypeConfigurationException e) {
       e.printStackTrace();  
    }
    }

    public Object newInstance(Object parent) throws IllegalStateException {

        //-- Since it's marked as a string...just return null,
        //-- it's not needed.
        return null;
    }



    public void resetValue(Object object) throws IllegalStateException, IllegalArgumentException {
        ((Order)object).setOrderDate(null);
    }

    @Override
    public void checkValidity(Object arg0) throws ValidityException,
            IllegalStateException {
        // TODO Auto-generated method stub
    }

}

#utility class

package org.sample.castor.util;

import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class DateUtil {

        public static XMLGregorianCalendar toXMLGregorianCalendar(Date date) throws DatatypeConfigurationException {
            GregorianCalendar c = new GregorianCalendar();
            c.setTime(date);
            XMLGregorianCalendar xmlGreCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(c); 
            return xmlGreCal;
        }

        public static XMLGregorianCalendar toXMLGregorianCalendar(String date)
            throws DatatypeConfigurationException {        

            XMLGregorianCalendar xmlGCal = null;
            try {
                   xmlGCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(date);
            } catch (DatatypeConfigurationException ex) {
                ex.printStackTrace();
            }

            return xmlGCal;
        }
}

#castor file mapping.xml

<?xml version="1.0"?>

<mapping>

  <class name="org.sample.castor.OrderResponse" type="org.sample.castor.OrderResponse">
     <map-to xml="orderResponse"/>
     <field name="customer"
           type="org.sample.castor.Customer">
          <bind-xml name="customer" node="element"/>
     </field>
     <field name="orders"
           type="org.sample.castor.Orders">
          <bind-xml name="orders" node="element"/>
     </field>
  </class>

  <class name="org.sample.castor.Orders" type="org.sample.castor.Orders">
     <map-to xml="orders"/>
     <field name="orders"
           type="org.sample.castor.Order" collection="arraylist">
          <bind-xml name="orders" node="element"/>
     </field>  
  </class>

  <class name="org.sample.castor.Order" type="org.sample.castor.Order">
     <map-to xml="order"/>
     <field name="id"
           type="java.lang.Long">
          <bind-xml name="id" node="element"/>
     </field>
     <field name="orderDate"
           type="java.lang.String" handler="org.sample.castor.handler.OrderDateHandler">
          <bind-xml name="orderDate" node="element"/>
     </field>
     <field name="description"
           type="java.lang.String">
          <bind-xml name="description" node="element"/>
     </field>
  </class>

  <class name="org.sample.castor.Customer" type="org.sample.castor.Customer">
     <map-to xml="customer"/>
     <field name="id"
           type="java.lang.Long">
          <bind-xml name="id" node="element"/>
     </field>
     <field name="name"
           type="java.lang.String">
          <bind-xml name="name" node="element"/>
     </field>    
     <field name="surname"
           type="java.lang.String">
          <bind-xml name="surname" node="element"/>
     </field>
     <field name="address"
           type="java.lang.String">
          <bind-xml name="address" node="element"/>
     </field>
     <field name="email"
           type="java.lang.String">
          <bind-xml name="email" node="element"/>
     </field>
  </class> 


</mapping>

libraries:

castor-1.3.1-xml.jar
castor-core-1.3.2.jar

In case the blogging system might not support attachments, you could email me at doviche@gmail.com and I will reply with a rar or zip file, containing both jar files.


Thanks for reading



Douglas Oviche

Nessun commento:

Posta un commento