Monday, August 12, 2013

Simple java XML web services using Jaxb & Play2

Simple java XML services using Jaxb & Play2

Developing simple java XML services needs
  • Data definition (XSD)
  • Service interface (POST URL)
  • Service body (Method implementing Post)
  • Unmarshalling logic (XML -> object)
Data definition is used as an agreement between client and server. Client developer uses agreed xsd, defines xjb bindings for jaxb generation, and generate java classes which can be used to build request. Request is then sent to public interface of server on payload of http post request.
Posting single xml document

Server developer uses shared xsd, but can have different bindings and thus also different jaxb data model generated. Incoming post request is routed to controller, where xml is unmarshalled to jaxb model. Model can be from this on used as desired.

Data definition: Manual XSD-design 

My personal preference is to write XSD first and then generate java classes for client or server. In this way information structures are clean and client development is easy.

With JDK's basic tools one can easily get from XSD to java classes. Generation can be customized with configuration file. Your preferred IDE has most probably integrated generation to make this really simple.

Data definition: Russian Doll 

I selected Russian Doll XSD design. This is most simple way of designing XSD, but doesn't allow reusing of types as all types are embedded and local.

With Venetian Blind I needed to define XML root element using annotations on java code, which was to me undesired. If generation is one time operation this might not be problem, but to me it was.
If you aim to develop self contained services whose interfaces are decoupled from database design and domain objects Russian Doll might be design choice for you.

I wanted to keep services separate and simple, but if you are doing complex SOA integrations you might prefer Salami Slices, Garden of Eden or Chameleon design patterns, i.e. reusing type definitions and overriding namespaces.

Java classes: JAXB generation

Jaxb generation is simple. In Eclipse just select File / New / Jaxb / Classes from schema and give schema file, package name and bindings file.

Customizing generation is part of basic process which is well supported and has bells and whistles more than simple use case needs.

Getting temporal datatypes "right" can be can be done by adjusting generation with external binding file. If you use Jodatime types conversion goes like below.

<!-- Transforms xml dates and dateTimes to Jodatime objects -->
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
jaxb:extensionBindingPrefixes="xjc">

<jaxb:globalBindings mapSimpleTypeDef="false"
choiceContentProperty="true">

<jaxb:javaType xmlns="http://java.sun.com/xml/ns/jaxb"
name="org.joda.time.LocalDate" xmlType="xs:date"
parseMethod="org.joda.time.LocalDate.parse" printMethod="java.lang.String.valueOf" />

<jaxb:javaType xmlns="http://java.sun.com/xml/ns/jaxb"
name="org.joda.time.LocalTime" xmlType="xs:time"
parseMethod="org.joda.time.LocalTime.parse" printMethod="java.lang.String.valueOf" />

<jaxb:javaType xmlns="http://java.sun.com/xml/ns/jaxb"
name="org.joda.time.DateTime" xmlType="xs:dateTime" parseMethod="org.joda.time.DateTime.parse"
printMethod="java.lang.String.valueOf" />

</jaxb:globalBindings>
</jaxb:bindings>

Post interface: url

Here's play2 definition for route from external interface (url) to implementation (java method).

POST    /metrics/entity       controllers.MetricsEntityController.saveXml()

Play2 is full stack framework, and this is really all you need. No web.xml, no servlets, no..

Post method: signature and implementation

Here's play2 for java method, which is extracting org.w3c.dom.Document from http request.

@Of(Xml.class)
public static Result saveXml() {
Document xml = request().body().asXml();
...

Mime type on request needs to be 'text/xml' for asXml method to work. If you can't ensure right mime type is used TolerantXml allows relaxing checks here.

XML to Java implemenentation: Jaxb unmarshal

To unmarshall xml with jaxb you need to set up context and marshaller. Context is thread safe, so it can be initialized on static constructor.

// inits
static JAXBContext context;
static {
try {
// init jaxb
context = JAXBContext.newInstance(Result.class);
Logger.info("Jaxb initialized");

} catch (JAXBException jaxbe) {
Logger.error("Jaxb initialization failed", jaxbe);
throw new RuntimeException(jaxbe);
}
}

Unmarshalling is done on per request basis.

// results deserialization
Unmarshaller unmarshaller = context.createUnmarshaller();
computationResult = (Result) unmarshaller.unmarshal(xml);

At this point you have Jaxb object tree, which you can use to browse content of xml. What you do with it is up to you.

Conclusions

Java standard libraries with open source libraries and tools like jodatime allow straightforward java xml service development. Play2 is clean, simple and easy to use web development stack. Together Jaxb, Jodatime and Play2 provide all one needs to get from xml to java objects in plain http services.

http://www.playframework.com

No comments: