Monday, May 31, 2010

Spring 3: OXM... Castor, JAXB, JibX and xmlBeans (And XStream)

Updated to include XStream

Another reason to love Spring... OXM...

Basically there are 5 common Object to XML mapping projects out there... Castor, JaxB, XStream ,JibX and xmlBeans. Since I am lazy an a fan of reuse I won't be going into JibX as this other blogger (Guido Schumtz) did it quite nicely:
JibX Maven Spring OXM

I won't describe xmlBeans either, 'cause as soon as I saw that the objects need to extend XmlObject I lost interest... I don't wanna have to change my class hierarchy just to do mappings, that is so very 90's.

I did however slap together a quick Castor, JaxB and XStream example:
You need a bean that you want to map in and out of xml in this case (ClassToXMLMap.java)
package javaitzen.spring.oxm;

import javax.xml.bind.annotation.XmlRootElement;
import com.thoughtworks.xstream.annotations.XStreamAlias;

@XmlRootElement(name="ClassToXMLMap")
@XStreamAlias( "ClassToXMLMap" )
public class ClassToXMLMap {
 private String data;
 private String history;
 
 public String getData() {
  return data;
 }
 
 public void setData(String data) {
  this.data = data;
 }
 
 public String getHistory() {
  return history;
 }
 
 public void setHistory(String history) {
  this.history = history;
 } 
}


Then a class to use the Spring marshallers:
package javaitzen.spring.oxm;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

public class OXMarshall {
    
    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public void setMarshaller(Marshaller marshaller) {
        this.marshaller = marshaller;
    }

    public void setUnmarshaller(Unmarshaller unmarshaller) {
        this.unmarshaller = unmarshaller;
    }

    public void saveXML(ClassToXMLMap message, String fileName) throws IOException {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(fileName);
            this.marshaller.marshal(message, new StreamResult(fos));
        } finally {
            if (fos != null) {
                fos.close();
            }
        }
    }

    public ClassToXMLMap loadXML(String fileName) throws IOException {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(fileName);
            return (ClassToXMLMap) this.unmarshaller.unmarshal(new StreamSource(fis));
        } finally {
            if (fis != null) {
                fis.close();
            }
        }
    }    
}


The JUnit Test:
package javaitzen.spring.oxm;

import static org.junit.Assert.assertNotNull;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(locations={"/javaitzen/spring/oxm/applicationContext.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class OXMTest {

 @Autowired
 OXMarshall castor;
 
 @Autowired
 OXMarshall jax;

 @Autowired
 OXMarshall xtream;
 
 ClassToXMLMap message;
 
 @Before
 public void setup(){
     message = new ClassToXMLMap();
     message.setData("I am data");
     message.setHistory("in the past");
 }
 
 @Test
 public void testCastor() throws Exception{
  String castorFile = "castor.xml";
  castor.saveXML(message, castorFile);
        assertNotNull(castor.loadXML(castorFile));
 }
 
 @Test
 public void testJaxB() throws Exception{
  String jaxbFile = "jaxb.xml";
     jax.saveXML(message,jaxbFile);
        assertNotNull(jax.loadXML(jaxbFile));
 }

 @Test
 public void testXStream() throws Exception{
        String xtreamFile = "xtream.xml";
        xtream.saveXML(message,xtreamFile);
        assertNotNull(xtream.loadXML(xtreamFile));
    }
 
}


The mapping file for Castor:



The application context for the Test:


Hint: If you want to use xmlBeans or JibX there are tags defined for them by Spring, and you will be able to substitute them for the ones in my example.



Last but not least the Maven pom file:

9 comments:

  1. If applying contract first development style to webservices or any other XML based integration kind of work, and your contract is a set of XSDs, and you're applying castor as OXM provider, then there's no need to create DTOs and mapping manually. See example here.

    ReplyDelete
  2. Very nice, I will keep that in mind, my current applications were already using the objects before needing the mapping, but when starting via XSD's, your example is definitely a nice way to go, thanks.

    ReplyDelete
  3. cool. i would also like to share a spoon-feed tutorial on serializing and deserializing java objects/XML using Spring OXM and Castor O/X Mapping Framework. You can find it here:

    http://www.adobocode.com/spring/marshallingunmarshalling-java-objects-into-xml-file-using-spring-oxm

    hope this helps others too...

    ReplyDelete
  4. http://www.adobocode.com/spring/marshallingunmarshalling-java-objects-into-xml-file-using-spring-oxm

    Link is broken

    ReplyDelete
  5. Not much I can do about a broken link in comments from someone else... besides delete the comments :)

    ReplyDelete
  6. I don't think we need to extend any class to use xmlBeans with spring-ws! am i wrong?

    ReplyDelete
  7. Thanks, nice post

    ReplyDelete

Popular Posts

Followers