Friday, April 18, 2008

EclipseLink MOXy in Spring-WS

I was reminded that I'd promised an example of how to use EclipseLink MOXy in Spring Web Services so here we go. Fortunately this isn't hard to do as Spring-WS abstracts the concept of a Marshaller and an Unmarshaller so you can plug in various diverse technologies. One of those technologies supported "out of the box" is JAXB 2, and since EclipseLink MOXy implements JAXB 2 all we have to worry about is Spring configuration and just a little code.

I've adapted one of the Oracle TopLink 11g JAXB demos to use Spring for configuration and Spring-WS interfaces for marshalling/unmarshalling. That demo describes how the code works so, for brevity, I'll assume you've read it. A link to the source for this updated demo is at the bottom of this posting.

Marshalling/Unmarshalling is something you can do in a number of context in Spring-WS including handling WebService and JMS message payloads so once you see how MOXy JAXB is configured in this simple example you can use this knowledge in any Spring application that works with XML.

Configuration--Spring applicationContext.xml

Since this is Spring we need an applicationContext.xml file in which to
layout all your bean config. At the bottom of the file (below) I
declare two beans: marshallExample and unmarshallExample.
marshallExample has a marshaller injected, and unmarshallExample has
both a marshaller and unmarshaller injected. Notice that the bean
refs for both the marshaller and unmarshaller is the same bean
"jaxbMarshaller"--I'll get to that in a moment.

<?xml version="1.0" encoding="UTF-8"?>

    <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
        <property name="contextPath" value="examples.jaxb.generated"/>

    <bean id="marshallExample" class="examples.jaxb.marshall.MarshallGenerated">
        <property name="marshaller" ref="jaxbMarshaller"/>
    <bean id="unmarshallExample" class="examples.jaxb.unmarshall.UnmarshallGenerated">
        <property name="unmarshaller" ref="jaxbMarshaller"/>
        <property name="marshaller" ref="jaxbMarshaller"/>

At the top of the file I declare "jaxbMarshaller" as an instance of the
Spring-WS Jaxb2Marshaller class. And I pass the property
"contextPath" to it so that it knows what classes it is responsible for
handing. In this case "examples.jaxb.generated". If you
look in that package in the example source you'll see a
file. The file can be used to specify the JAXB
implementation to use. In this case the file
contains the single line:

javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory

This is how we plug in EclipseLink MOXy as the JAXB implementation to
use. The file is standard JAXB, not Spring.
If you take a look back at the OTN example you'll see the same
file. What Spring-WS adds is the Jaxb2Marshaller class and the
generic interfaces it implements. Unlike in JAXB where you obtain
a JAXB Marshaller or Unmarshaller from a JAXBContext, Spring-WS does
this behind the scenes. Rather than exposing the objects it
instead exposes marshall and unmarshall methods. By not exposing
these objects it makes it possible to swap out a JAXB marshaller for
another kind of marshaller. And this is why jaxbMarshaller is used as
both marshaller and unmarshaller in the unmarshallExampleBean.

Bootstrapping Your Application

To use these beans you use the standard Spring bean lookup method, e.g.:

        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        MarshallGenerated marshallGenerated = (MarshallGenerated) applicationContext
           .getBean("marshallExample", MarshallGenerated.class);

If you've got your applicationContext.xml right then the instance of
MarshallGenerated that you get from Spring will be fully configured
with an instance of Jaxb2Marshaller injected.

To marshall or unmarshall you use the Spring Jaxb2Marshaller methods. However the arguments to those methods are slightly different than those of a JAXB Marshaller or Unmarshaller and use javax.xml.transform.Source and javax.xml.transform.Result. This is a pretty minor difference and was an easy change to the application code.

Running the Example

To run the example you just need to download, unzip, and edit the environment variables eclipselink.home, spring.home, and spring-ws.home at the top of the ANT build.xml file. Once you have those set you can run ANT to build and run.

No comments: