In the previous post, I introduced the design goals behind the Spring Web Services SOAP framework. In this post, I describe how one would go about implementing a Web service with Spring-WS. Please note that any code shown in this post is non-final, and only reflects the current design we have.
Before you implement your service, there are some design choices you need to make. These are important choices, but you can reuse these for every service.
How many classes?
First, there is the choice whether you want to implement a service endpoint in a single class, or in separate classes. Traditionally, Web services are just single classes, with every method representing an operation. This can result in large classes, and thus code smell. Within Spring-WS, there is the option to implement a service operation as separate class, just as you would implement a single Controller class when using a Web UI framework such as Spring-MVC. If you prefer to use a single class, however, that is also possible, but we will cover the single-class case in this post.
Message or payload?
Within a service endpoint, you have to choose whether you are interested in the complete message, or just the contents of the message body (i.e. the message payload). If you want the complete message, you implement the MessageEndpoint interface, which contains just one method:
SOAPMessage invoke(SOAPMessage request) throws Exception;
The SOAPMessage used here is the standard, SAAJ javax.xml.soap.SOAPMessage.
However, it is much more likely that you are interested in the message payload, because that contains the interesting bits.
If you want the message payload, you implement the Spring-WS interface PayloadEndpoint, which also contains one method:
Source invoke(Source request) throws Exception;
The Source used here is a javax.xml.transform.Source, a XML input abstraction. The PayloadEndpoint interface has convenience subclasses which allow you to use DOM, SAX, or StAX directly1
Within your endpoint, you read the XML, invoke a few business methods on your middle tier, and formulate a reply, if desired. Presto!
XML Marshalling?
Of course, you can use Object-XML mapping in your endpoint if you want to, making the handling of XML somewhat easier. We’ll cover the O/X Mapping support of Spring-WS in a future post, but suffice it to say that Spring-WS offers an abstraction which makes it easier to switch from one OXM implementation to another. Also, the exceptions thrown by these marshalling frameworks are all converted to runtime exceptions, and unified to a single hierarchy, just like in Spring’s data access and ORM support.
When the endpoint is done, you need to decide how it is mapped to a request. This topic is also reserved for a future post, but basically, all standard mapping techniques (URL-based, SOAPAction-based, and message-based), are supported. You can even write your own mapping logic if nothing suits you.
<hr/>
1 - Both MessageEndpoint and PayloadEndpoint can be compared with JAX-WS, which defines the Provider interface. By setting the enumerated value for a @ServiceMode annotation on the generic Provider, you can accomplish the same thing, though it’s a bit too Java 5-heavy for my taste.