Recently I had the opportunity to learn a bit about web services. I had never worked with them before, but naturally my first thought was to use Spring Integration’s web services support because Spring Integration just makes everything so much simpler to do.
One of my main goals was keeping things as simple as possible. That meant not having to get my hands too dirty converting objects to XML and XML to objects. So I needed to find an XML marshalling solution that was just plain simple. I didn’t have much experience with them in the past and I had tried DOM and SAX but found them too verbose. So I looked at the ones that Spring Integration supported. I finally settled on XStream because it’s annotation based configuration seemed so simple, and it was.
Before I go on, I should mention that I won’t be posting the full source of the project this tutorial is based on since it was for a client of mine.
Spring Integration configuration for starters
To begin, we’ll look at the Spring Integration configuration. We’ll first register an XStream marshaller which will convert objects to XML and XML to objects. Then I’ll define aliases to our objects as well as define which objects are annotated. The aliases you define make it easier for the XStream marshaller to unmarshall XML responses into specific objects. The alias or key is essentially the root element of the XML being unmarshalled. Next the same classes are defined as a list for the annotated classes property. Annotations that get added to elements of those classes assist XStream in making the XML output from marshalling look “prettier.” More on that in the next section.
Along with the XStream marshaller, I’ve defined a request gateway which will serve as the initial entry point for messages being sent to the web service. The service interface is just that, a Java interface that defines what kind of message or more specific, what kind of message payload will be sent to the gateway.
I’ve also defined a couple chains which simply encapsulate elements that share a common input channel but need to be invoked in specific order. There’s the request channel which receives the messages from the request gateway, which is then sent off on the the
<ws:outbound-gateway> element. That’s where the web service invocation actually takes place. Finally the error channel which I’ll use to send notification emails if an exception occurs. When errors occur in downstream elements, they will flow up to the request gateway which will send them out on the error channel.
Annotating objects for XStream marshalling and unmarshalling
The next step is annotating the classes that will be marshalled/unmarshalled. Let’s look at the Request and Response classes.
As you might have guessed, I used Spring Roo for this project. Spring Roo is just a really great tool. What I want you to pay attention to are the
@XStreamAlias annotations you see in a few places. You see it first at the type level on the
Request class and then at the member level too in both the
Response classes. You might have noticed I don’t have this annotation at the type level on the
Response class. This is because I’m never marshalling the
Response, I’m only ever unmarshalling the XML into a
Response object and the root element
response has already been defined as an alias for this class in the XStream marshaller in the previous section. The
@XStreamAlias annotation is what tells the marshaller what to use as the element name to make the XML look “prettier.” So the Request object would get marshalled into something like the following.
Another small thing you might have noticed is that I’ve annotated the
Request class with
@Component and I’ve annotated each member with
@Value. The reason for this is because the values come from a properties file and the class will be instantiated as a singleton upon container initialization. So then I can merely inject the Request instance where it’s needed. This is good if the initial request always needs to be the same.
@XStreamAlias annotation at the type level, you’d end up with a root element that looked more like
<com.example.Request> which is the fully qualified name of the class.
Invoking the web service
Now that we have our XStream marshaller setup, our Spring Integration configuration complete and our object classes annotated, lets invoke the web service.
This class is very simple. I’m injecting the request gateway and the request instance, then I’m merely submitting the request instance to the request gateway. The method
invoke was defined earlier on the
Handling the web service response
Now that we’ve made a request to the web service, we might need to handle some kind of response. That’s where the
responseServiceActivator defined in the
requestChannel chain comes into use.
This is a very simple use case where you simply handle the payload of the message returned from the web service. A method annotated with
@ServiceActivator can either accept a parameter of type
Response in our case. It’s just simpler to use
Response directly. In this method, I’m demonstrating how you might perform error handling if the web service you’re invoking does have the possibility of returning errors if something went wrong. In this case, we’re throwing a runtime exception which will be thrown up the chain to the initial request gateway. However you can take it a step further and create your own exception classes for specific errors being thrown. At that point the error will be sent to the
errorChannel and emailed out.
So I hope I’ve covered enough of the fundamentals so that you can apply Spring Integration web services support along with XStream marshalling to your next or even current application. The application this tutorial was based on had a few more web service requests in it. Mainly because after the initial request, I had to process the response and invoke a couple other web services based on the response. I had also implemented application specific error handling, instead of just throwing a basic runtime exception.
Btw, I think Spring Integration is the best thing since coffee!