Friday, December 24, 2021

Spring Object XML Mapping (OXM) Castor Example

In this post we’ll see how to serialize an object graph to XML (marshalling) and how to deserialize the XML to an object graph (unmarshalling) using Castor and Spring OXM module.

Spring Object-XML mapping support

Spring framework provides support for converting an XML document to/from an object using Spring-OXM module.

Spring-OXM provides abstractions to the O/X mapping frameworks through two interfaces.

  • Marshaller
  • Unmarshaller

These abstractions allow you to switch O/X mapping frameworks with relative ease, with little or no changes required on the classes that do the marshalling.

The implementation classes provided by Spring-OXM for these interfaces are-

  1. CastorMarshaller- For object-XML mapping using Castor.
  2. Jaxb2Marshaller- For object-XML mapping using JAXB. Refer Spring Object XML Mapping Support - JAXB Example to see an example of XML marshalling-unmarshalling in Spring using JAXB.
  3. JibxMarshaller- For object-XML mapping using JIBX.

Object to XML mapping using Castor – Spring Example

In this example we’ll see how to do XML marshalling and unmarshalling using Castor and Spring-OXM.

Maven dependencies

Along with Spring core dependencies you’ll need following maven dependencies for Castor and Spring-OXM.

<properties>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  <java.version>10</java.version>
  <spring.version>5.0.8.RELEASE</spring.version>
</properties>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-oxm</artifactId>
  <version>${spring.version}</version>
</dependency>
<dependency>
  <groupId>org.codehaus.castor</groupId>
  <artifactId>castor-core</artifactId>
  <version>1.4.1</version>
</dependency>
<dependency>
  <groupId>org.codehaus.castor</groupId>
  <artifactId>castor-xml</artifactId>
  <version>1.4.1</version>
</dependency>

Bean classes

Two classes are used in this XML marshalling and unmarshalling example, User class whose objects are returned in the XML form and UserListContainer class which contains the List of objects of type User.

User.java

public class User {
  private int id;
  private String firstName;
  private String lastName;
  private String email;
  public User() {
    
  }
  public User(int id, String firstName, String lastName, String email) {
    this.id = id;
    this.firstName = firstName;
    this.lastName = lastName;
    this.email = email;
  }
  public int getId() {
    return id;
  }
  public void setId(int id) {
    this.id = id;
  }

  public String getFirstName() {
    return firstName;
  }
  public void setFirstName(String firstName) {
    this.firstName = firstName;
  }
  public String getLastName() {
    return lastName;
  }
  public void setLastName(String lastName) {
    this.lastName = lastName;
  }
  public String getEmail() {
    return email;
  }
  public void setEmail(String email) {
    this.email = email;
  }
  @Override
  public String toString() {
  
    return "id- " + getId() + " First Name- " + getFirstName() + 
    " Last Name- " + getLastName() + " Email- " + getEmail();
  }
}

UserListContainer.java

public class UserListContainer {
  private List<User> userList;

  public List<User> getUserList() {
    return userList;
  }

  public void setUserList(List<User> userList) {
    this.userList = userList;
  }
}

Spring XML Configuration for CastorMarshaller

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:task="http://www.springframework.org/schema/task"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/task
    http://www.springframework.org/task/spring-task.xsd">


  <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
    <property name="targetPackage" value="org.netjs.model" />
    <property name="mappingLocation" value="classpath:mapping.xml" />
  </bean>  
  <bean id="objXmlmapper" class="org.netjs.service.ObjXMLMapper">
    <property name="marshaller" ref="castorMarshaller" />
    <property name="unmarshaller" ref="castorMarshaller" />
  </bean>
</beans>

With CastorMarshaller bean you can define the target classes which are used in Marshalling or you can define the package where the POJOs reside.

Mapping information for the object fields to XML element or attribute conversion can be provided using a Castor mapping file that information is provided to the CastorMarshaller bean using the mappingLocation property.

Since CastorMarshaller class implements both the Marshaller and Unmarshaller interfaces so the same bean is provided as reference for both marshaller and unmarshaller properties in ObjXMLMapper bean.

ObjXMLMapper.java

This is the class where marshalling and unmarshalling is done using the CastorMarshaller class in Spring-OXM. In the class Marshaller and Unmarshaller interfaces are used which are set to CastorMarshaller instance using the Spring configuration.
public class ObjXMLMapper {
  private static final String FILE_NAME = "users.xml";
  private Marshaller marshaller;
  private Unmarshaller unmarshaller;
  public void setMarshaller(Marshaller marshaller) {
    this.marshaller = marshaller;
  }
  public void setUnmarshaller(Unmarshaller unmarshaller) {
    this.unmarshaller = unmarshaller;
  }
  // Converting object graph to XML (marshalling)
  public void objToXML() throws IOException {
    // call to get object graph
    UserListContainer userList = getUsers();
    try (FileOutputStream os = new FileOutputStream(FILE_NAME)) {            
      this.marshaller.marshal(userList, new StreamResult(os));        
    } 
  }
  // Converting XML to an object graph (unmarshalling) 
  public void XMLToObj() throws IOException {
    UserListContainer userList = new UserListContainer();
    try (FileInputStream is = new FileInputStream(FILE_NAME)) {            
      userList = (UserListContainer)this.unmarshaller.unmarshal(new StreamSource(is));        
    } 
    userList.getUserList().forEach(System.out::println);
  }
    
  public UserListContainer getUsers(){
    List<User> users = getListOfUsers();
    UserListContainer userList = new UserListContainer();
    userList.setUserList(users);
    return userList;
  }
  // Dummy method for adding List of Users
  private List<User> getListOfUsers() {
    List<User> users = new ArrayList<User>();
    users.add(new User(1, "Jack", "Reacher", "abc@xyz.com"));
    users.add(new User(2, "Remington", "Steele", "rs@cbd.com"));
    users.add(new User(3, "Jonathan", "Raven", "jr@sn.com"));
    return users;
  }
}

Castor mapping file (Mapping.xml)

In order to have more control over how the object to/from XML conversion happens a mapping file is provided which Castor uses as a reference.

<?xml version="1.0" encoding="UTF-8"?>
<mapping>
  <class name="org.netjs.model.UserListContainer">   
    <map-to xml="Users"  />     
    <field name="userList" type="org.netjs.model.User" collection="arraylist">
      <bind-xml name="user" node="element" />
    </field>
  </class>
  <class name="org.netjs.model.User">
    <field name="id" type="integer">
         <bind-xml name="id" node="attribute" />
    </field>    
    <field name="firstName" type="string" />
    <field name="lastName" type="string" />
    <field name="email" type="string" />
  </class>
</mapping>

Since we want a parent element as Users which holds the list of users so two class definitions are given in castor mapping file. First class definition is for UserListContainer, which tells that the it contains elements of type User in an ArrayList which are to be bound as User element in XML.

Second class definition is for User type, it tells how fields of User are to be mapped.

Class used to run the application

public class App {
  public static void main( String[] args ){  
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext
                                               ("appcontext.xml");
    ObjXMLMapper objXMLMapper = context.getBean("objXmlmapper", ObjXMLMapper.class);

    try {
      objXMLMapper.objToXML();
      objXMLMapper.XMLToObj();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    context.close();
  }
}
On running you get the XML as follows after the object graph is serialized to XML-
<?xml version="1.0" encoding="ISO-8859-1"?>
<Users>
  <user id="1">
    <first-name>Jack</first-name>
    <last-name>Reacher</last-name>
    <email>abc@xyz.com</email>
  </user>
  <user id="2">
    <first-name>Remington</first-name>
    <last-name>Steele</last-name>
    <email>rs@cbd.com</email>
  </user>
  <user id="3">
    <first-name>Jonathan</first-name>
    <last-name>Raven</last-name>
    <email>jr@sn.com</email>
  </user>
</Users>

Deserializing the XML to object graph displays the object fields on the console-

id- 1 First Name- Jack Last Name- Reacher Email- abc@xyz.com
id- 2 First Name- Remington Last Name- Steele Email- rs@cbd.com
id- 3 First Name- Jonathan Last Name- Raven Email- jr@sn.com

That's all for this topic Spring Object XML Mapping (OXM) Castor Example. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Spring Tutorial Page


Related Topics

  1. Spring MVC Generate Response as XML Example
  2. Spring Transaction Management JDBC Example Using @Transactional Annotation
  3. Spring Web Reactive Framework - Spring WebFlux Tutorial
  4. Spring Thread Pooling Support Using TaskExecutor
  5. Spring Email Scheduling Example Using Quartz Scheduler

You may also like-

  1. Spring Component Scan Example
  2. @Import Annotation in Spring JavaConfig
  3. Spring Bean Life Cycle
  4. How to Inject Prototype Scoped Bean in Singleton Bean
  5. Java ScheduledThreadPoolExecutor - Task Scheduling in Java
  6. Functional Interfaces in Java
  7. Java Exception Handling Interview Questions And Answers
  8. How to Create PDF in Java Using OpenPDF

No comments:

Post a Comment