Category: Spring 2.5

Spring WS and JAXB without a Code Generator

2010-04-28

Note: although this post mostly talks about implementing web services, the manual object-XML mapping technique described here can also be applied to WS clients.

I’d like to start by confessing that I’m very picky about programming techniques that rely on source code generators. I’m also sceptical about other kinds of compile-time tools that generate artifacts like XML files. I had my share of bad experiences with these sorts of tools, not because they are buggy or badly designed, but simply because they are not perfect.

Well, nobody’s perfect, you say? True enough. IDE auto-formatters are not perfect either. The style of code that they produce often still requires manual formatting. But it’s not a bad thing, since as a programmer I always have the final word: if I don’t like the place where that curly brace was put, or the way that lengthy statement was wrapped, I go ahead and fix it manually.

Enter the Evil Code Generators

Now, what if I don’t like some artifact produced by a generator? It can be ugly, it can be slow, it can miss the point – oh, well, there’s nothing I can do about it, because all my efforts will be overwritten during the next generation. It may be suitable for 95% cases, but what about the remaining 5%? When these tools do the work for me, they do it their way, and they won’t let me have that small customization that I need. You see, that’s one problem with code generators. They assume too much.

In my book, generators are only suitable for one-shot spawning of artifacts, or for quickly creating some throw-away demos. In practice, however, these tools are often integrated into project build lifecycle, which is bad because:

  • Generated output cannot be manually edited,
  • Generated output cannot be version controlled (at least in a meaningful way),
  • You become dependent on the generator – without it, the source won’t even compile!
  • The thought that you are not in control of your code makes you feel dizzy.

When it comes to Web Services…

…developers choose to go either the “WSDL to Java” or “Java to WSDL” route. The “to” part is usually done with some sort of generator utility, which means losing control of either the WSDL contract or the Java code. What I’d like to show in this post is a simple setup of Spring Web Services and JAXB that does not involve compile-time generation of artifacts, so that when defining your service interface you can feel completely in charge of everything: the Java, the XML, and the binding between the two.

I chose Spring WS mostly because it promotes contract-first Web Services, and JAXB2 because it’s a popular (some would say “official”) XML data binding specification. I was tempted to skip the binding part entirely and just parse/build the darn XML messages with JDOM, but then I saw that it required too much effort, especially in prospect of growing the WS interfaces.

Although I do believe that JAXB was designed to be primarily used alongside code generators like wsimport (WSDL to Java), it also works without them. What we’re going to do is:

  1. Write XML Schema for our web service
  2. Write Java classes for XML binding, with JAXB annotations
  3. Implement the endpoint
  4. Assemble everything with Spring WS configuration

The XML Schema

Create a /WEB-INF/personService.xsd file where each request and response message is expressed by an <element> and each complex type (if we need deeper structures) is represented by a <complexType>. Let’s say that our service accepts some kind of person-ID and returns the person’s name and age, where name is a complex type that consists of firstName and lastName.

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:foo="http://bar.foo"
    targetNamespace="http://bar.foo" elementFormDefault="qualified">

    <element name="GetPersonRequest">
        <complexType>
            <sequence>
                <element name="id" type="string"/>
            </sequence>
        </complexType>
    </element>

    <element name="GetPersonResponse">
        <complexType>
            <sequence>
                <element name="name" type="foo:FullName"/>
                <element name="age" type="int"/>
            </sequence>
        </complexType>
    </element>

    <complexType name="FullName">
        <sequence>
            <element name="firstName" type="string"/>
            <element name="lastName" type="string"/>
        </sequence>
    </complexType>

</schema>

The Java classes for XML binding

Now for each XML request, XML response and XML complex type we create a corresponding Java class and put JAXB annotations to bind it to XML. The Java classes that map to personService.xsd schema look like this:

@XmlRootElement(name="GetPersonRequest", namespace="http://bar.foo")
@XmlType(name="", propOrder={"id"})
@XmlAccessorType(XmlAccessType.FIELD)
public class GetPersonRequest {

    @XmlElement(name="id", namespace="http://bar.foo")
    private String id;

    /* normal getters and setters */
}

////////////////////////////////////////////////

@XmlRootElement(name="GetPersonResponse", namespace="http://bar.foo")
@XmlType(name="", propOrder={"name", "age"})
@XmlAccessorType(XmlAccessType.FIELD)
public class GetPersonResponse {

    @XmlElement(name="name", namespace="http://bar.foo")
    private FullName name;

    @XmlElement(name="age", namespace="http://bar.foo")
    private int age;

    /* normal getters and setters */
}

////////////////////////////////////////////////

@XmlType(name="FullName", namespace="http://bar.foo", propOrder={"firstName", "lastName"})
@XmlAccessorType(XmlAccessType.FIELD)
public class FullName {

    @XmlElement(name="firstName", namespace="http://bar.foo")
    private String firstName;

    @XmlElement(name="lastName", namespace="http://bar.foo")
    private String lastName;

    /* normal getters and setters */
}

Some explanation:

  • each request and response element maps to @XmlRootElement class
  • each inner element maps to @XmlElement field
  • each complex type maps to @XmlType class, where propOrder sets the order of inner elements
  • since requests and responses are also anonymous complex types, they are annotated with a nameless @XmlType
  • @XmlAccessorType(XmlAccessType.FIELD) annotation tells JAXB to access field values directly

The endpoint implementation

It’s really up to you how you’re going to implement this part. Here’s just an example of using the @PayloadRoot annotation to map incoming XML request to a handler method:

@Endpoint
public class PersonEndpoint {

    @PayloadRoot(localPart = "GetPersonRequest", namespace = "http://bar.foo")
    public GetPersonResponse getPerson(GetPersonRequest request) {
        /* implementation code */
    }
}

The assembly

Define a Jaxb2Marshaller bean and set the classesToBeBound property to an array of all @XmlRootElement classes, so that they can be recognized by the marshaller.

DefaultWsdl11Definition can be used to publish WSDL definition based on personService.xsd, as long as we follow the convention of Request/Response suffixes in XML element names. And the rest are standard Spring WS affairs. A more or less complete setup may look like this:

<!-- the endpoint implementation -->
<bean class="foo.bar.PersonEndpoint"/>

<!-- publishes WSDL contract based on the given XML schema -->
<bean id="personService" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
    <property name="schema" ref="schema">
        <bean class="org.springframework.xml.xsd.SimpleXsdSchema">
            <property name="xsd" value="/WEB-INF/personService.xsd"/>
        </bean>
    </property>
    <property name="portTypeName" value="personInterface"/>
    <property name="locationUri" value="/ws/personService"/>
    <property name="targetNamespace" value="http://bar.foo"/>
</bean>

<!-- uses annotations to map XML requests to endpoint methods -->
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>

<!-- passes endpoint method arguments and returned objects to JAXB marshaller -->
<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
    <property name="marshaller" ref="jaxbMarshaller"/>
    <property name="unmarshaller" ref="jaxbMarshaller"/>
</bean>

<!-- uses JAXB annotations to marshall between XML messages and Java objects -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="classesToBeBound">
        <list>
            <value>foo.bar.GetPersonRequest</value>
            <value>foo.bar.GetPersonResponse</value>
        </list>
    </property>
</bean>

<!-- parses and builds SOAP messages -->
<bean class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory"/>

The dependencies

For the sake of completeness, here's a listing of relevant Maven dependencies that I used.

<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-ws-core</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-ws-core-tiger</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-xml</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-oxm</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.ws</groupId>
    <artifactId>spring-oxm-tiger</artifactId>
</dependency>

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
</dependency>
<dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
</dependency>
<dependency>
    <groupId>stax</groupId>
    <artifactId>stax-api</artifactId>
</dependency>

<dependency>
    <groupId>org.apache.ws.commons.axiom</groupId>
    <artifactId>axiom-api</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.ws.commons.axiom</groupId>
    <artifactId>axiom-impl</artifactId>
</dependency>
<dependency>
    <groupId>xml-apis</groupId>
    <artifactId>xml-apis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.ws.commons.schema</groupId>
    <artifactId>XmlSchema</artifactId>
</dependency>

For a similar no-generated-code technique applied to JAX-WS services, check out this post.

Inherit Spring Security Context in Child Threads

2010-04-04

By default, Spring Security context is bound to ThreadLocal, which may catch you by surprise in some cases involving spawned threads.

So I setup my security infrastructure to authenticate users, populate their details from database, grant them authorities, I configure AccessDecisionManager and put @Secured annotations on my business methods to assert those authorities, etc. It all works well until my business code evolves to include asynchronous invocations. Then I find myself wondering: why am I getting AuthenticationCredentialsNotFoundException in places where the user is obviously authenticated?

Turns out that when a new thread is started it knows nothing about the security context of its parent thread. So if AccessDecisionManager gets called (e.g. if a @Secured method is invoked) from within the child thread, you get a security exception.

To work around that, you should change the SecurityContextHolder strategy to use InheritableThreadLocal for storing the security context. You can do that in code:

SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL)

… or in XML configuration (which is better since you’ll only need to call the static method once during application startup):

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetClass"
        value="org.springframework.security.context.SecurityContextHolder"/>
    <property name="targetMethod" value="setStrategyName"/>
    <property name="arguments"><list><value>MODE_INHERITABLETHREADLOCAL</value></list></property>
</bean>

Note however, that you cannot share security context among sibling threads (e.g. in a thread pool). This method only works for child threads that are spawned by a thread that already contains a populated SecurityContext.

Access Spring WS MessageContext from anywhere

2009-11-07

UPDATE (2011-03-27): This article is relevant to those using the 1.5 version of Spring WS. Since version 2.0 it is trivial to access MessageContext by simply declaring it as one of the arguments in the handling method.

Spring Web Services framework has a special MessageContext class for holding request and response messages as well as arbitrary properties during the processing of a WS request. This class is especially useful if you are writing your own endpoint interceptors, because it allows you to do whatever you want with all incoming or outgoing web service messages, regardless of the endpoint in which they are processed.

There is certainly no problem getting to MessageContext in an EndpointInterceptor (all interface methods contain a MessageContext parameter), but what if you need to access it in your endpoint handler? For example, if you had to know the content type of all SOAP attachments that came in request, you would do it like this:

SoapMessage request = (SoapMessage) messageContext.getRequest();
for (Iterator it = request.getAttachments(); it.hasNext();) {
    Attachment attachment = (Attachment) it.next();
    System.out.println(attachment.getContentType());
}

You could do that in a MessageEndpoint, but not in a PayloadEndpoint where you have no access to MessageContext since it is not passed as parameter to your endpoint method.

Curiously, TransportContext does not have this limitation, as it is bound to current thread and accessible via TransportContextHolder.getTransportContext(). Users of Spring Security will remember that SecurityContext can be accessed in the same manner via SecurityContextHolder.getContext(). Notice a recurring theme here? What we lack in Spring WS is a “MessageContextHolder” class that would allow us to access MessageContext from anywhere in our code. Let’s go ahead and implement this missing utility.

MessageContextHolder is going to be a really simple utility class that can store and retrieve a reference to MessageContext in local thread.

public final class MessageContextHolder {

    private static ThreadLocal<MessageContext> threadLocal =
        new ThreadLocal<MessageContext>() {
            @Override
            protected MessageContext initialValue() {
                return null;
            }
        };

    private MessageContextHolder() {
    }

    public static MessageContext getMessageContext() {
        return threadLocal.get();
    }

    public static void setMessageContext(MessageContext context) {
        threadLocal.set(context);
    }

    public static void removeMessageContext() {
        threadLocal.remove();
    }
}

Next we need an endpoint interceptor that puts MessageContext to “Holder” before WS request is processed, and removes it when WS response (or fault) is about to be sent.

public class MessageContextHolderInterceptor implements EndpointInterceptor {

    public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
        MessageContextHolder.setMessageContext(messageContext);
        return true;
    }

    public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
        MessageContextHolder.removeMessageContext();
        return true;
    }

    public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
        MessageContextHolder.removeMessageContext();
        return true;
    }
}

Finally, we configure whatever EndpointMapping beans we use to include our interceptor:

<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping">
    <property name="interceptors">
        <list>
            <bean class="my.project.MessageContextHolderInterceptor"/>
        </list>
    </property>
</bean>

Now once this interceptor does its job upon each request, you can say MessageContextHolder.getMessageContext() and you’ll get current MessageContext whenever you need it.