Binding Restful XML Parameter

Today i want to share how to Binding Restful XML Parameter using jersey, JAXB and MOXy library. Before we start please update your pom with this dependencies:

1. Binding Restful XML Parameter – Dependencies

<dependencies>
   <dependency>
      <groupId>org.glassfish.jersey.containers</groupId>
      <artifactId>jersey-container-grizzly2-http</artifactId>
   </dependency>
   <dependency>
      <groupId>org.glassfish.jersey.media</groupId>
      <artifactId>jersey-media-moxy</artifactId>
   </dependency>
</dependencies>

We will create simple rest server that receive request and send response with XML data representation. The request xml will automatically bind to pojo class. For the example we will create rest service that manipulate customer data, the service contains two function inquiry, and update customer data.

The customer data structure is shown bellow:

    <customer>
      <personal-info>
        <name>Jane Doe</name>
      </personal-info>
      <contact-info>
        <address>
          <city>My Town</city>
          <street>123 Any Street</street>
        </address>
        <phone-number type="work">613-555-1111</phone-number>
        <phone-number type="cell">613-555-2222</phone-number>
      </contact-info>
    </customer>

First, we need to create the pojo class and base on above XML, we need to create customer class, that have address and multiple phone number. So, we have three class: Customer, Address, PhoneNumber:

Binding Restful XML Parameter – POJO

The First Pojo is Customer.java

@XmlRootElement
@XmlType(propOrder = {"name", "address", "phoneNumbers"})
public class Customer {

    private String name;
    private Address address;
    private List<PhoneNumber> phoneNumbers;

    public Customer() {
        phoneNumbers = new ArrayList<PhoneNumber>();
    }

    @XmlPath("personal-info/name/text()")
    public String getName() {
        return name;
    }

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

    @XmlPath("contact-info/address")
    public Address getAddress() {
        return address;
    }

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

    @XmlPath("contact-info/phone-number")
    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Customer other = (Customer) obj;
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        if (this.address != other.address && (this.address == null || !this.address.equals(other.address))) {
            return false;
        }
        if (this.phoneNumbers != other.phoneNumbers && (this.phoneNumbers == null || !this.phoneNumbers
                .equals(other.phoneNumbers))) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0);
        hash = 97 * hash + (this.address != null ? this.address.hashCode() : 0);
        hash = 97 * hash + (this.phoneNumbers != null ? this.phoneNumbers.hashCode() : 0);
        return hash;
    }
}

The Second Pojo is Address.java

public class Address {

    private String street;
    private String city;

    public Address(){}

    public Address(String street, String city) {
        this.street = street;
        this.city = city;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Address other = (Address) obj;
        if ((this.street == null) ? (other.street != null) : !this.street.equals(other.street)) {
            return false;
        }
        if ((this.city == null) ? (other.city != null) : !this.city.equals(other.city)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 29 * hash + (this.street != null ? this.street.hashCode() : 0);
        hash = 29 * hash + (this.city != null ? this.city.hashCode() : 0);
        return hash;
    }
}

And finally PhoneNumber.java

public class PhoneNumber {

    private String type;
    private String value;

    public PhoneNumber() {}

    public PhoneNumber(String type, String value) {
        this.type = type;
        this.value = value;
    }

    @XmlAttribute
    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @XmlValue
    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final PhoneNumber other = (PhoneNumber) obj;
        if ((this.type == null) ? (other.type != null) : !this.type.equals(other.type)) {
            return false;
        }
        if ((this.value == null) ? (other.value != null) : !this.value.equals(other.value)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + (this.type != null ? this.type.hashCode() : 0);
        hash = 59 * hash + (this.value != null ? this.value.hashCode() : 0);
        return hash;
    }
}

So, We have three pojo with JAXB xml mapping that represent the xml structure. Here, we wouldn’t discuss about JAXB mapping but you can find a lot of tutorial about JAXB xml mapping on google.

At last but not least, we will create the service controller named CustomerResource.java. This class will receive http request with url http://yourdomain:port/customer. If the request method is GET, then it will perform inquiry, and if the request method is POST it will update current data. We use dummy data here, on actual implementation you have to get data by querying to database or other system.

@Path("/customer")
public class CustomerResource {

    private static Customer customer = createInitialCustomer();

    @GET
    @Produces(MediaType.APPLICATION_XML)
    public Customer getCustomer() {
        return customer;
    }

    @POST
    @Consumes(MediaType.APPLICATION_XML)
    public String setCustomer(final Customer c) {
        setCustomerToStatic(c);
        return "Success";
    }

    private static Customer createInitialCustomer() {
        final Customer result = new Customer();

        result.setName("Jane Doe");
        result.setAddress(new Address("123 Any Street", "My Town"));
        result.getPhoneNumbers().add(new PhoneNumber("work", "613-555-1111"));
        result.getPhoneNumbers().add(new PhoneNumber("cell", "613-555-2222"));

        return result;
    }

    private static void setCustomerToStatic(final Customer customer) {
        CustomerResource.customer = customer;
    }
}

And the last thing, we have to create main class that start the service: App.java.

public class App {

    private static final URI BASE_URI = URI.create("http://localhost:8080/xml-moxy/");

    public static void main(String[] args) {
        try {
            System.out.println("XML with MOXy Jersey Example App");

            final HttpServer server = GrizzlyHttpServerFactory.createHttpServer(BASE_URI, createApp());
            Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
                @Override
                public void run() {
                    server.shutdownNow();
                }
            }));
            server.start();

            System.out.println(String.format("Application started.%nTry out %s%nStop the application using CTRL+C",
                    BASE_URI + "/customer"));

            Thread.currentThread().join();
        } catch (IOException | InterruptedException ex) {
            Logger.getLogger(App.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public static ResourceConfig createApp() {
        return new ResourceConfig().packages("org.glassfish.jersey.examples.xmlmoxy").register(new MoxyXmlFeature());
    }
}

Now, please start your App and then try to send request using your favourite RestClient plugins. Please note that we register MoxyXmlFeature to our resource config.
And Bellow is the screen shoot for testing this code.

Binding Restful XML Parameter
Binding Restful XML Parameter

You can download the example code by click link below:
Download

Leave a Reply

Your email address will not be published. Required fields are marked *