Posts Tagged ‘JAXB

12
Oct
13

Using JAXB To Unmarshal a SOAP Response

This page describes how to unmarshal a SOAP response using JAXB. This is useful when you have saved a SOAP response for later consumption. The application described here uses all the JAX-WS xml to bean mapping annotations that were generated using wsimport from the service WSDL file.

Requirements

Before you start please ensure you have generated all the web service client classes by using wsimport. Once this is done the generated classes will have all the annotations necessary for JAXB to use.

Use the example below as a guide for your own application.

The following is the SOAP Message we want to UN-marshal.

response.xml

<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
   <env:Header/>
   <env:Body>
      <ns2:getCustomerResponse xmlns:ns2="http://com/test/">
         <customer>
            <ns2:id>1</ns2:id>
         </customer>
         <customer>
            <ns2:id>5</ns2:id>
         </customer>
      </ns2:getCustomerResponse>
   </env:Body>
</env:Envelope>

The application below open the SOAP response xml from a file called response.xml. But your application can load the data from any input stream.

The app’s main method skips to the the getCustomerResponse tag within response.xml using a while loop. Once found it loads data into the GetCustomerResponse.class generated by the wsimport tool and simply prints the information to the console.

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;

import com.test.client.Customer;
import com.test.client.GetCustomerResponse;


public class App2 {
	private static final String FILE_NAME = "response.xml";

	public static void main(String args[]) throws Exception {
        getCustomerResponse();
	}

	protected static void getCustomerResponse() throws FactoryConfigurationError,
			XMLStreamException, JAXBException {
		XMLInputFactory xif = XMLInputFactory.newFactory();
		StreamSource xml = new StreamSource(FILE_NAME);
		XMLStreamReader xsr = xif.createXMLStreamReader(xml);
		xsr.nextTag(); // Advance to Envelope tag
		while (!xsr.getLocalName().equals("getCustomerResponse")) {
			xsr.nextTag();
		}

		JAXBContext jc = JAXBContext.newInstance(GetCustomerResponse.class);
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		JAXBElement<GetCustomerResponse> je = unmarshaller.unmarshal(xsr, GetCustomerResponse.class);

		for(Customer customer : je.getValue().getCustomer()) {
			System.out.println("customerId: " + customer.getId());
		}
	}

}

Appendix

The following is the WSDL file. It is not necessary for the application above to work. Its included here for reference purposes.

<definitions name='CustomerServiceImplService' targetNamespace='http://com/test/' xmlns='http://schemas.xmlsoap.org/wsdl/' xmlns:ns1='http://com/test/' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:tns='http://test.com/' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
 <types>
  <xs:schema targetNamespace='http://com/test/' version='1.0' xmlns:tns='http://com/test/' xmlns:xs='http://www.w3.org/2001/XMLSchema'>
   <xs:element name='customer' type='tns:customer'/>
   <xs:element name='getCustomer' type='tns:getCustomer'/>
   <xs:element name='getCustomerResponse' type='tns:getCustomerResponse'/>
   <xs:complexType name='getCustomer'>
    <xs:sequence>
     <xs:element minOccurs='0' name='arg0' type='xs:string'/>
    </xs:sequence>
   </xs:complexType>
   <xs:complexType name='getCustomerResponse'>
    <xs:sequence>
     <xs:element maxOccurs='unbounded' minOccurs='0' name='customer' type='tns:customer'/>
    </xs:sequence>
   </xs:complexType>
   <xs:complexType name='customer'>
    <xs:sequence>
     <xs:element form='qualified' minOccurs='0' name='id' type='xs:string'/>
     <xs:element form='qualified' minOccurs='0' name='name' type='xs:string'/>
    </xs:sequence>
   </xs:complexType>
  </xs:schema>
 </types>
 <message name='CustomerService_getCustomerResponse'>
  <part element='ns1:getCustomerResponse' name='getCustomerResponse'></part>
 </message>
 <message name='CustomerService_getCustomer'>
  <part element='ns1:getCustomer' name='getCustomer'></part>
 </message>
 <portType name='CustomerService'>
  <operation name='getCustomer' parameterOrder='getCustomer'>
   <input message='ns1:CustomerService_getCustomer'></input>
   <output message='ns1:CustomerService_getCustomerResponse'></output>
  </operation>
 </portType>
 <binding name='CustomerServiceBinding' type='ns1:CustomerService'>
  <soap:binding style='document' transport='http://schemas.xmlsoap.org/soap/http'/>
  <operation name='getCustomer'>
   <soap:operation soapAction=''/>
   <input>
    <soap:body use='literal'/>
   </input>
   <output>
    <soap:body use='literal'/>
   </output>
  </operation>
 </binding>
</definitions>
<definitions name='CustomerServiceImplService' targetNamespace='http://test.com/' xmlns='http://schemas.xmlsoap.org/wsdl/' xmlns:ns1='http://com/test/' xmlns:soap='http://schemas.xmlsoap.org/wsdl/soap/' xmlns:tns='http://test.com/' xmlns:xsd='http://www.w3.org/2001/XMLSchema'>
 <import location='http://localhost:8080/jax-ws-spring-jboss/customerService?wsdl&amp;resource=CustomerService_PortType7365405514847117757.wsdl' namespace='http://com/test/'></import>
 <service name='CustomerServiceImplService'>
  <port binding='ns1:CustomerServiceBinding' name='CustomerServiceImplPort'>
   <soap:address location='http://localhost:8080/jax-ws-spring-jboss/customerService'/>
  </port>
 </service>
</definitions>
01
Nov
09

Using JAXB to convert between XML and POJO’s

Introduction

There are many products out there that allow for conversions of XML to java and Back. One of the popular tools I have used in the past is Betwixt from the Apache commons project. Other tools out there include XStream. The following page describes how to use JAXB to convert xml to java and Java to XML. If you have used web services you know what I am talking about.

With the introduction of the Java 5 Annotations and the new JAX-WS standard I thought it would be a good idea to learn more about JAXB. Betwixt was great for small projects but some heavy weight stuff like web services I would use something like the following.

Example 1: Marshalling a simple Customer POJO

In this example we will marshal a customer pojo object from java to XML and un-marshal it from xml back to Java.

Start by creating a Customer.java class in the customer package.

package customerpackage;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

/**
 * Represents a customerpackage
 */
@XmlRootElement
public class Customer {
        private Integer id;
        private String firstName;
        private String lastName;
        private String SSN;

        public Integer getId() {
                return id;
        }
        public void setId(Integer id) {
                this.id = id;
        }
        @XmlElement(nillable=true)
        public String getFirstName() {
                return firstName;
        }

        public void setFirstName(String firstName) {
                this.firstName = firstName;
        }
        @XmlElement(nillable=true)
        public String getLastName() {
                return lastName;
        }
        public void setLastName(String lastName) {
                this.lastName = lastName;
        }
        @XmlElement(name="socialSecurityNumber")
        public String getSSN() {
                return SSN;
        }
        public void setSSN(String sSN) {
                SSN = sSN;
        }
        public String toString() {
                StringBuffer sb = new StringBuffer();
                sb.append("FirstName: " + this.firstName);
                sb.append("\nLastName: " + this.lastName);
                sb.append("\nSSN: " + this.SSN);
                return sb.toString();

        }
}

In order for the JAXB to work you need to have an ObjectFactory.java class in the customer package;

package customerpackage;

import javax.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public class ObjectFactory {

        public ObjectFactory() {
        }

        public Customer createCustomer() {
                return new Customer();
        }
}

Create a simple java main application to test.

package customerpackage;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * Simple java main class that runs our example
 *
 */
public class JAXApp {

        public static void main(String args[]) throws Exception {
                objectToXML();

                //xmlToObject();
        }

        /**
         * Marshall information into an xml file.
         */
        private static void objectToXML() throws Exception {
                JAXBContext jc = JAXBContext.newInstance( "customerpackage" );
                Customer cust = new Customer();
                cust.setId(1);
                cust.setFirstName("Neeraj");
                cust.setLastName("Verma");
                cust.setSSN("123-45-6789");
                Marshaller m = jc.createMarshaller();
                m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                m.marshal( cust, System.out );

        }

        private static void xmlToObject() throws Exception {
                JAXBContext jc = JAXBContext.newInstance( "customerpackage" );
                Unmarshaller u = jc.createUnmarshaller();
                Customer customer = (Customer)u.unmarshal( ClassLoader.getSystemResourceAsStream("customer.xml") );
                System.out.println(customer);
        }

}

Result

Running the above application should print something like this to the console.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <firstName>Neeraj</firstName>
    <id>1</id>
    <lastName>Verma</lastName>
    <socialSecurityNumber>123-45-6789</socialSecurityNumber>
</customer>

Example 2: Marshalling a POJO containing a list of Other Objects

In this example we will marshal a Manager object that contains a list of Employee’s.

Create a package named workpackage and put the following classes in it:

Manager.java

package workpackage;

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Manager {
        private Integer managerId;
        private String firstName;
        private String lastName;
        private List<Employee> employees = new ArrayList<Employee>();

        public Integer getManagerId() {
                return managerId;
        }
        public void setManagerId(Integer managerId) {
                this.managerId = managerId;
        }
        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 List<Employee> getEmployees() {
                return employees;
        }
        public void setEmployees(List<Employee> employees) {
                this.employees = employees;
        }

        public String toString() {
                StringBuffer buffer = new StringBuffer();
                buffer.append("Manager Name: " + firstName + "\n");
                buffer.append("employees: \n");
                buffer.append(employees);
                return buffer.toString();
        }
}

Employee.java

package workpackage;

public class Employee {
        private Integer id;
        private String firstName;

        public Employee() {
        }

        public Employee(Integer id, String firstName, String lastName) {
                this.id = id;
                this.firstName = firstName;
                this.lastName = lastName;
        }

        public Integer getId() {
                return id;
        }
        public void setId(Integer 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;
        }
        private String lastName;

        public String toString() {
                return "id: "+ id + " Name: " + firstName + " " + lastName;
        }
}

The following is the main application that is used to test. Be sure to enable the correct line in the main method.

ManagerApp.java

package workpackage;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class ManagerApp {
        public static void main(String args[]) throws Exception {
                // enable the next line to print xml to the console
                //objectToXML();

                // copy the output to the console to manager.xml

                // enable the following line to read from manager.xml in the root of the project.
                xmlToObject();
        }

        /**
         * Marshall information into an xml file.
         */
        private static void objectToXML() throws Exception {
                JAXBContext jc = JAXBContext.newInstance( "workpackage" );
                Manager manager = new Manager();
                manager.setManagerId(1);
                manager.setFirstName("Neeraj");
                manager.setLastName("Verma");
                manager.getEmployees().add(new Employee(1, "John", "Doe"));
                manager.getEmployees().add(new Employee(2, "Jane", "Doe"));

                Marshaller m = jc.createMarshaller();
                m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                m.marshal( manager, System.out );

        }

        private static void xmlToObject() throws Exception {
                JAXBContext jc = JAXBContext.newInstance( "workpackage" );
                Unmarshaller u = jc.createUnmarshaller();
                Manager manager = (Manager)u.unmarshal( ClassLoader.getSystemResourceAsStream("manager.xml") );
                System.out.println(manager);
        }

}

should print something like this on the console:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<manager>
    <employees>
        <firstName>John</firstName>
        <id>1</id>
        <lastName>Doe</lastName>
    </employees>
    <employees>
        <firstName>Jane</firstName>
        <id>2</id>
        <lastName>Doe</lastName>
    </employees>
    <firstName>Neeraj</firstName>
    <lastName>Verma</lastName>
    <managerId>1</managerId>
</manager>

The second method should print something like this to the console:

Manager Name: Neeraj
employees:
[id: 1 Name: John Doe, id: 2 Name: Jane Doe]

Excluding fields from the xml

If you don’t want some fields from your bean to show just use the following annotation.

        @XmlTransient
        public String getDontWantThis() {
                return dontWantThis;
        }

The above will exclude a field from the output.

Thats all for now!

This site is a collaborative effort! The complete text and sourcecode for this is available on GitHub. Corrections and enhancements are welcome, please make the change and submit a pull request in the comment area below.



Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 75 other followers

May 2017
S M T W T F S
« Mar    
 123456
78910111213
14151617181920
21222324252627
28293031  

Blog Stats

  • 813,721 hits