Thursday, October 8, 2015

EJB vs. Spring: Simple Soap Services

This is the second article in the EJB3 vs Spring series. I will be focused on the differences between Spring and EJB3 when exposing a simple SOAP service. In case you missed it, there is an explanation of my maven project layout in my first article, EJB3 vs Spring: Rest Services. As always, all of the source code is available for your perusal on github at https://github.com/jgitter/fwc. In order to get the most out of this article, you'll want to be familiar with SOAP and JAX-WS. Two good places to get started are http://www.soapuser.com/basics1.html and http://docs.oracle.com/javase/7/docs/technotes/guides/xml/jax-ws/.

If you wish to test out any of the services mentioned for yourself, there are two ways to do so. Simply clone the git repository, run a maven build, and deploy it to a EJB3-enabled container of your choice (some assembly may be required for your container of choice). I have supplied a web interface which can be reached at http:///fwc where you can run all 4 versions of the findInstitutions service and examine the results and I have also committed a SoapUI (5.0.0) project in the parent module that has a request defined for each.

Note that I am using WSDL version 1.1, not the newer 1.2/2.0 due to the general lack of adoption and tool support.

Contract-First or Code-First?


I was hoping to avoid this question when I undertook writing this article since I'm not interested in taking part in a holy war. I wanted to use a code-first approach for my examples simply because I am more comfortable defining my service contract in code. There are several tools available for generating a wsdl from service code, with Apache CXF likely emerging as the best of those tools, though it does much more than that. I completed the JEE version of this service using this approach quite effectively. Then I turned my attention to Spring-WS only to be greeted with the following statement in their reference documentation (http://docs.spring.io/spring-ws/docs/2.2.0.RELEASE/reference/htmlsingle/#why-contract-first):
When creating Web services, there are two development styles: Contract Last and Contract First. When using a contract-last approach, you start with the Java code, and let the Web service contract (WSDL, see sidebar) be generated from that. When using contract-first, you start with the WSDL contract, and use Java to implement said contract.

Spring-WS only supports the contract-first development style, and this section explains why.

This seems like an odd place for Spring to choose to take a stance on how something must be done, when from what I've seen they are usually aggressively flexible. However, let it be known that in my examples I used a code-first approach for the JEE implementation. I then lifted the generated schema in that wsdl to generate the Spring wsdl so I could come as close to a code-first approach as possible. While not the most correct of approaches, I believed I was able to achieve my goal.

After I was finished, it was brought to my attention that I wasn't truly comparing apples to apples. To that end, in my github project I have shown how to configure a maven project to use the CXF codegen plugin to build a service implementation from a static wsdl. If you run 'mvn generate-sources' on the fwc-ejb-web module, the generated classes will appear in the target/generated-sources folder. You would then update the service implementation class to add your implementation to any service methods that were stubbed out there. On the flip-side of that coin, I have also set up the cxf java2wsdl plugin to show an example of how you can generate a wsdl from an implementation. I'm not using the results of either of these, but hopefully they can be educational.

Taking advantage of JBoss


I'm going to be taking advantage of some of the features offered by the JBoss Application Server so, as promised, I intend to highlight those features to prevent skewing the analysis toward one framework or the other. Specifically, in my EJB3 annotated SOAP services, I'm letting the container generate my wsdl for me. It does this by using the aforementioned Apache CXF under the hood.

Alternatively, it is possible to generate your own wsdl and host it. As I mentioned earlier, my project in github shows an example of how this would be done in the plugin configuration for the fwc-ejb-web module. During the generate-resources phase it generates a wsdl from a service implementation and places it in the generated-resources directory. Then, during the compile phase you could copy that wsdl into the WEB-INF directory via the maven resources plugin. It can be referenced from there in the wsdlLocation attribute of the @WebService annotation on the service implementation. I left the sample generation there for instructive purposes, but I'm not using it.

Another way JBoss is also helping me out by rewriting the soap:address in the wsdl when it is requested. This is done by setting to true in the jboss configuration under the webservices subsystem. The Spring container is also doing this for me, but it requires a little more work, which I'll describe in detail.

EJB3 / JAX-WS SOAP Services


For a SOAP service created with JAX-WS annotations, no real configuration is necessary. For my JBoss EAP container, I only need to have the webservices sub-system enabled which uses Apache CXF to publish your service endpoints. Your classpath will be scanned for any classes annotated with @WebService and, in my case, also generates the wsdl as I mentioned above. Here is my service implementation.

SOAP Service Implementation
//snip - not all imports shown here
import javax.ejb.Stateless;
import javax.inject.Inject;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
 
@Stateless
@WebService(name = "InstitutionService", serviceName = "soap-institution",
        targetNamespace = InstitutionSoapService.TARGET_NAMESPACE)
public class InstitutionSoapServiceImpl implements InstitutionSoapService {
 
    @Inject
    private InstitutionService service;
 
    @Override
    @WebMethod
    @WebResult(targetNamespace = InstitutionSoapService.TARGET_NAMESPACE,
            name = FindInstitutionsResponse.NAME)
    public FindInstitutionsResponse findInstitutions(
            @WebParam(
                    targetNamespace = InstitutionSoapService.TARGET_NAMESPACE,
                    name = FindInstitutionsRequest.NAME)
                    FindInstitutionsRequest request) {
 
        FindInstitutionsResponse response = new FindInstitutionsResponse();
 
        // snip
 
        return response;
    }
}

A breakdown of the annotations:
  • The @Stateless annotation marks this as a stateless session bean
  • The @WebService annotation is required on any Service Endpoint Implementation or endpoint interface. It informs the container that it is a JAX-WS endpoint.
    • The 'name' attribute specifies the name of the web service and is used as the name of the portType in the wsdl.
    • The 'serviceName' attribute specifies the service name of this web service and is used as the name of the wsdl:service in the wsdl. It is also used as the url prefix to access methods defined on this service: //fwc-ejb/soap-institution/InstitutionService
    • The 'targetNamespace' attribute specifies the namespace of the service which must match the namespace on any incoming requests
  • The @Inject annotation comes from CDI and injects a @RequestScoped service bean for me as discussed in my Rest Service article and is not relevant to the subject at hand
  • The @WebMethod annotation marks a method to be exposed on a @WebService endpoint.
  • The @WebResult annotation describes the SOAP response, which in this case is the FindInstitutionsResponse
    • The 'name' attribute specifies the name of the xml element for the response object
    • The 'targetNamespace' attribute specifies the namespace of the xml element for the response object
  • The @WebParam annotation describes the expected SOAP request, which will be matched against any incoming requests on this endpoint. The 'name' and 'targetNamespace' attributes work exactly the same for this annotation as they do for the @WebResult annotation. If the incoming request does not contain the exact same elements and namespaces, the request will be rejected.

There is slightly more to it yet, as I still need to define my request and response objects. If you're looking for them in the code, you'll find them in the fwc-common module. When a request comes in, the XML request will be unmarshaled to the FindInstitutionsRequest object, and the response XML is obtained by marshaling the FindInstitutionsResponse back to XML. The names and namespaces of the elements is specified via JAXB annotations. They are fairly self-explanatory so I won't go into detail describing them.

Transfer Objects

@XmlRootElement(namespace = "http://fwc.gitter.org/services/")
@XmlType(name = "findInstitutionsRequest")
public class FindInstitutionsRequest {
    public static final String NAME = "findInstitutionsRequest";
 
    private String keyword;
 
    @XmlElement(name = "keyword")
    public String getKeyword() {
        return keyword;
    }
 
    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }
}

//----------------------------------------------------------------

@XmlRootElement(namespace = "http://fwc.gitter.org/services/")
@XmlType(name = "institutionList")
public class FindInstitutionsResponse {
    public static final String NAME = "institutionList";
 
    private List institutions;
 
    @XmlElement(name = "institution")
    public List getInstitutions() {
        return institutions;
    }
 
    public void setInstitutions(List institutions) {
        this.institutions = institutions;
    }
}
 
//----------------------------------------------------------------
 
public class Institution {
    private Map<String, String=""> institutionData;
    @XmlElement
    public String getAddress() {
        // I'm cheating - normally you wouldn't do this in a transfer object,
        // but I wanted the SOAP response to be aesthetically pleasing and
        // haven't implemented a domain layer.
        return new StringBuilder()
                .append(institutionData.get("ADDR")).append(" ")
                .append(institutionData.get("CITY")).append(", ")
                .append(institutionData.get("STABBR")).append(" ")
                .append(institutionData.get("ZIP")).toString();
    }
    @XmlTransient
    public Map<String, String=""> getInstitutionData() {
        return institutionData;
    }
    @XmlElement
    public String getInstitutionName() {
        return institutionData.get("INSTNM");
    }
    public void setInstitutionData(Map<String, String=""> institutionData) {
        this.institutionData = institutionData;
    }
}


As an example, if I send this request:

SOAP Request
<!-- HTTP headers omitted -->
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <fwc:findInstitutions xmlns:fwc="http://fwc.gitter.org/services/">
            <fwc:findInstitutionsRequest>
                <keyword>Milwaukee WI</keyword>
            </fwc:findInstitutionsRequest>
        </fwc:findInstitutions>
    </soap:Body>
</soap:Envelope>


I should receive a response like this:

SOAP Response
<!-- HTTP headers omitted -->
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <ns2:findInstitutionsResponse xmlns:ns2="http://fwc.gitter.org/services/">
      <ns2:institutionList>
        <institution>
          <address>500 Silverspring Rd Ste K340 Glendale, WI 53217</address>
          <institutionName>Bryant & Stratton College-Bayshore</institutionName>
        </institution>
        <institution>
          <address>10950 W Potter Road Wauwatosa, WI 53226</address>
          <institutionName>Bryant & Stratton College-Wauwatosa</institutionName>
        </institution>
        <institution>
          <address>4425 N Port Washington Rd Glendale, WI 53212</address>
          <institutionName>Columbia College of Nursing</institutionName>
        </institution>
        <!-- snip ... -->
      </ns2:institutionList>
    </ns2:findInstitutionsResponse>
  </soap:Body>
</soap:Envelope>


If you have deployed the application, the wsdl will be visible at URL http:///fwc-ejb/soap-institution/InstitutionService?wsdl. If you look at the soap:address of the wsdl:service, you'll notice what I was mentioning earlier. That address will be rewritten by the JBoss webservices subsystem to point at the exposed host and port binding for your server. This allows you to use the same WSDL for multiple servers, for example in a clustered environment, without having to know where it will be deployed at compile time.

Spring SOAP Services with Spring-WS


For this example, I'm using spring-ws (2.2.0). As opposed to the EJB3 and JAX-WS method, which is ultimately published by Apache CXF in JBoss, Spring SOAP Services are published by the Spring Container. This also means that the JBoss webservices subsystem is completely unaware of my deployed Spring-WS soap services. In other words, I can't depend on JBoss to generate my wsdls, or rewrite the soap:address for me as above automagically. The first thing we have to do is add a mapping for the Soap requests to the spring-ws dispatcher servlet in the web.xml deployment descriptor.

web.xml
<web-app>
    <!-- snip -->
    <servlet>
        <servlet-name>webservices</servlet-name>
        <servlet-class>
            org.springframework.ws.transport.http.MessageDispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>true</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>webservices</servlet-name>
        <url-pattern>/soap/*</url-pattern>
    </servlet-mapping>
</web-app>


The transformWsdlLocations parameter informs Spring-WS that we wish for the soap:address to be rewritten to the current binding address. This performs the same job for us as the JBoss webservices subsystem as laid out above. In addition to mapping the SpringWS dispatcher servlet, we will have to configure the application context.

applicationContext.xml
<beans>
    <!-- snip -->
    <sws:annotation-driven />
 
    <sws:dynamic-wsdl id="InstitutionService"
        portTypeName="InstitutionService"
        serviceName="InstitutionService"
        locationUri="/soap/institution/InstitutionService">
        <sws:xsd location="/schemas/InstitutionService.xsd" />
    </sws:dynamic-wsdl>
</beans>


The allows me to configure my endpoint via annotations. In addition to this, I need to setup the wsdl generation via the configuration. This is where you configure the name for the portType and serviceName as well as the endpoint URL. I also had to configure the static location to a schema document that is used to generate the wsdl. I built this schema document myself rather than generating it, but there are numerous tools you can use to accomplish this. In fact, I cheated and simply copied the schema that was produced by CXF from my EJB3 example. There is a warning in the Spring-WS documentation about the use of the dynamic-wsdl configuration. Since the generation of wsdls from one version of Spring to the next is not guaranteed to be the same, they recommend that you only use it in development. Once you're ready to release, they hint that you should copy the generated wsdl and place it in your project to use with the static-wsdl configuration to prevent unintentional changes to your wsdl contract.

That is enough to configure a simple web service. The rest of the configuration is in the service implementation itself.

SOAP Service Implementation
/* snip - not all imports shown */
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;
 
@Endpoint
public class InstitutionSoapServiceImpl implements InstitutionSoapService {
 
    private InstitutionService service;
 
    @Autowired
    public InstitutionSoapServiceImpl(InstitutionService service) {
        this.service = service;
    }
 
    @Override
    @PayloadRoot(localPart = "findInstitutionsRequest",
            namespace = InstitutionSoapService.TARGET_NAMESPACE)
    public @ResponsePayload FindInstitutionsResponse findInstitutions(
            @RequestPayload FindInstitutionsRequest request) {
        FindInstitutionsResponse response = new FindInstitutionsResponse();
 
        /* snip */
 
        return response;
    }
}


Here is a breakdown of the annotations:
  • The @Endpoint annotation acts similarly to the @Component annotation, marking this class a service endpoint implementation and is picked up thanks to the sws:annotation-driven configuration element. It is analagous to the @WebService annotation.
  • The @Autowired annotation configures the injection point for the context InstitutionService bean
  • The @PayloadRoot annotation is the counterpart to the JAX-WS @WebMethod annotation. Similarly, it sets up the namespace and name of the expected type for a request.
  • The @ResponsePayload annotation indicates that the method's return value should be bound to the response payload.
  • The @RequestPayload annotation indicates that a method parameter should be bound to the request payload.


As you may have noticed, this service uses the same transfer objects as it's EJB3/JAX-WS cousin. It is therefore using the same JAXB configuration for marshaling the request and response payloads. This, then, is all that is needed. Here is an example request and response for this Spring-WS service.

Request
<!-- HTTP Headers omitted -->
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <fwc:findInstitutionsRequest
                xmlns:fwc="http://fwc.gitter.org/services/">
            <fwc:keyword>Milwaukee WI</fwc:keyword>
        </fwc:findInstitutionsRequest>
    </soap:Body>
</soap:Envelope>


Response
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <ns3:findInstitutionsResponse xmlns:ns3="http://fwc.gitter.org/services/" xmlns="">
      <institution>
        <address>500 Silverspring Rd Ste K340 Glendale, WI 53217</address>
        <institutionName>Bryant & Stratton College-Bayshore</institutionName>
      </institution>
      <institution>
        <address>10950 W Potter Road Wauwatosa, WI 53226</address>
        <institutionName>Bryant & Stratton College-Wauwatosa</institutionName>
      </institution>
      <institution>
        <address>4425 N Port Washington Rd Glendale, WI 53212</address>
        <institutionName>Columbia College of Nursing</institutionName>
      </institution>
      <!-- Snip ... -->
    </ns3:findInstitutionsResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>


Analysis


There are some notable things missing from this article, including some of the reasons that would compel you to use SOAP services instead of REST in the first place. This includes the entire WS-* stack: reliable messaging, use of transports other than HTTP, support for signed/encrypted/authenticated service calls, and transactionality of service calls. I decided to break these concepts out into separate articles so I could do them justice. I'm not sure the gap between EJB3/JAX-WS and Spring-WS is wide enough for the configuration of a simple SOAP service to enable us to make a decision on this alone. However, I did notice a couple things that are at least worth pointing out.

First, I have a confession. When I initially wrote the code for the Spring-WS service, I spent several frustrated hours trying to hammer out a working service, specifically when trying to write up a service implementation that would work with the WSDL that I had cobbled together. My frustration was really due to two things. First, I chose not to do "Contract-First" service development, which would have, more or less, guaranteed that the implementation would have matched the WSDL. Second, my lack of experience with Spring-WS configuration had me battling myself for the first few hours. When I finished getting the service to work, I went through several more passes to understand how the moving parts of Spring-WS were working together and slowly trimmed my configuration down to just the pieces that were necessary to make it work, discovering that some of what I had done was unnecessary or redundant. So hopefully my analysis remains untainted from my early frustrations.

I noticed that configuring the URL of the endpoint in Spring appeared to be more flexible. This may differ slightly when using other containers, but the endpoint of my EJB3/JAX-WS service was /// or /fwc-ejb/soap-institution/InstitutionService. Initially, my serviceName was soap/Institution, but that is not a legal name for a wsdl:service in the WSDL. I got away with it in JBoss, but it would have failed validation, so I changed it. On the other hand, all the Spring SOAP calls were getting routed through the Spring-WS MessageDispatcherServlet which allows any service endpoint mappings you want. I mapped the servlet to "/soap/*" and then in my application context, mapped my wsdl endpoint to "/soap/institution/InstitutionService". What seemed to be a point for Spring-WS turned out to be a side-effect of my choice to use "Contract-Last" development, so it wasn't enough to sway me. If I had generated the wsdl myself, I could have set the endpoint to whatever I wanted.

So which is better? There really weren't any notable differences in the two versions of the implementation. While Spring-WS is certainly a viable option, I was very put off by the fact that my desired Code-First approach wasn't supported. This alone might make me choose to go with JEE. In fact, if you choose to use Spring for other reasons, it is possible to plug in Apache CXF to publish your Soap Services and host the JAX-WS service implementation in the first example via CXF in the Spring container. Honestly, I wasn't expecting to notice any great divergence yet, but I anticipate that I will begin to see some major differences as I delve deeper down the rabbit hole.

EJB3 vs. Spring: Rest Services


Which framework is better?


If you anyone has ever asked you if you prefer pizza or ice cream, you probably answered “Well… it depends”.  While frustrating, this is often the correct answer when asking which software framework is “better”.  So it is when comparing the Spring Framework with the capabilities provided by an EJB3 container.  I have decided to start exploring this question myself, in particular the functionality where EJB3 and the various Spring modules overlap.

Clearly this is not a small task, particularly since I am not intimately familiar with all the possibilities offered by the Spring framework.  To ease my pain, I am going to break this analysis up into a series of posts, each building upon the last.  It is unlikely that any of these posts will be truly exhaustive in content, but I will do my best to represent the “80%”.

Getting started


I will keep my code as platform independent as I am able.  Knowing how minor nuances in containers can affect the behavior of deployed Enterprise Applications, I will divulge that I am deploying my application to JBoss EAP 6.3 for testing.  If I do happen to include any JBoss proprietary deployment descriptors or configurations, I will call them out and explain the approach.
The Framework Comparison Application (FWC) is a maven project organized into several modules.  All of the source code is available for your perusal on github at https://github.com/jgitter/fwc.  The modules are as follows:
  • fwc: The parent POM module
  • fwc-ear: The EAR enterprise application module
  • fwc-common: Java module that contains common code such as interfaces, exceptions and transfer objects
  • fwc-dao: EJB module containing the DAO layer, accessible to all web applications deployed to the EAR
  • fwc-web: WAR module that contains the front-end application used for illustration
  • fwc-ejb-web: WAR module that contains the EJB services.  The intent is to encapsulate the EJB3-specific implementations for the purposes of comparison
    • fwc-ejb-services: EJB module that implements the actual EJB services
  • fwc-spring-web: WAR module that contains the Spring services and Spring framework libs.  The intent is to encapsulate the Spring-specific implementations for the purposes of comparison
    • fwc-spring-services: Java module that implements the actual Spring services

EJB3 and Spring Configuration


One of the myths that seems to persist is the idea that EJB3 uses primarily annotation-based configuration and is therefore, somehow, superior to Spring which uses primarily XML-based configuration.  There are two fallacies in this statement that I would like to overcome.

The first fallacy is that annotations are superior to XML for configuration, or vice versa.  In fact, it depends highly upon how they are being used, what they are configuring, and ultimately, some level of aesthetics.  For instance, I personally think that transaction management, cross-cutting concerns, or web service endpoint configuration is perfect fit for configuration via annotations.  It provides clear definition of behavior, is self-documenting, and easy to change.  Furthermore, these types of configurations should not be subject to change lightly and may require a redesign of a system, or part of a system.  On the other hand, I believe JPA mapping configuration is a great fit for XML configuration.  It keeps all traces of your data sources out of your code allowing you to cleanly separate the two distinct activities of data mapping and data access.

Second, it isn’t true that either EJB3 or Spring lends itself to be primarily one or the other.  Both offer options for most configurations to be handled via either XML or annotation.  I will attempt to show both options for configuration in my service examples.

Restful EJB3 Service


In order for a Restful JAX-RS service to work, we need to map the javax.ws.rs.core.Application to a URL pattern.  There are two ways to achieve this.  The first method is via a servlet-mapping definition in your deployment descriptor (web.xml) and should look pretty familiar.

XML Configuration via web.xml:
<web-app>
    <!-- snip -->
    <servlet>
        <servlet-name>javax.ws.rs.core.Application</servlet-name>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>javax.ws.rs.core.Application</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>

The second way to achieve the same result is to use the @ApplicationPath annotation on a POJO.  This annotation is discovered upon startup and the container will map the Application servlet for you.

Java Configuration via annotation:
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/rest")
public class FwcApplication extends Application {}

Note that the path is "/rest" and not "/rest/*" as in the web.xml above.  These two configurations are equivalent and result in all calls to /<context-root>/rest/* to be routed through the JAX-RS Application servlet.

There are additional options and behaviors that can be configured but I will not cover those here.  This is enough to give us basic JAX-RS services.  Here is the EJB3 web service implementation:

The EJB3 service implementation:
@Path("/institution")
@Stateless
public class InstitutionRestController {

    @Inject
    private InstitutionService service;

    @GET
    @Path("{keyword}")
    @Produces(MediaType.APPLICATION_JSON)
    public List<Map<String, String>> findInstitutions(
            @PathParam("keyword") String keyword) {
        return service.findInstitutions(keyword);
    }
}

There are a few things happening here.
  1. The @Path annotation provides the relative path to make calls to the exposed methods of this restful service.  Notice that annotation is on the class as well as the method itself.  For this example, the path to the findInstitutions service method is /<context_root>/fwc-ejb/rest/institution/{keyword} where \{keyword\} is any non-null string containing a search term.
  2. The @Inject is a CDI annotation.  Dependency Injection is not the subject of this article, so I will just say that this annotation can be used to inject any CDI bean into a container-managed resource.  In this case, InstitutionService is a POJO decorated with the CDI annotation @RequestScoped.  See the CDI documentation for more information on the subject.
  3. The @GET annotation informs the JAX-RS implementation that this method can only be accessed via the HTTP GET method.
  4. The @Produces annotation informs the JAX-RS implementation that this method will result in a response that contains JSON data.  JBoss will uses Resteasy under the hood, which will transform the returned object to JSON.
  5. The @PathParam annotation informs the JAX-RS implementation that the keyword parameter should be parsed from the URL path wherever the \{keyword\} path is configured.
And that's all there is to it.  This is enough to expose a simple Restful web service.  I did not mention the @Stateless annotation, which marks this service as a Stateless EJB3 Session Bean.  This is not necessary to expose this as a service, but comes with a few benefits.  For instance, the container will create a pool of reusable service objects for handling requests, enables injection since the bean is container-managed, and exposes the bean through JNDI for local service calls.  Simply adding an @Remote interface would also expose it for remote invocation.

Restful Spring Service


Configuring a container for Spring Web MVC Restful services is very similar to the previous example.  The first step is to map the Spring DispatcherServlet, which acts as the top-level controller for your services, much as the Application servlet did for the JAX-RS implementation.  This is done via the deployment descriptor (web.xml).

Spring DispatcherServlet mapping:
 <web-app>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

This will map all requests to /<context_root>/rest/* through the DispatcherServlet.  Unlike the previous example, we aren't done configuring the container here since the Spring container still needs to be made aware of your service controllers.  There are a number of ways to do this, however the easiest way to handle this is by updating your the configuration for your context.  The ContextLoaderListener will bootstrap your application context upon startup of the container which will look for the applicationContext.xml.  You can configure this here.

applicationContext.xml:
<beans>
    <mvc:annotation-driven />
    <context:component-scan base-package="org.gitter.fwc" />
    <!-- snip -->
</beans>

This can be a little deceptive as there is a lot going on here. The <mvc:annotation-driven> tag enables annotation configuration for your Restful Controllers via the @Controller, @RestController, @RequestMapping, and @ExceptionHandler annotations and provides the standard conversion service for serializing your data for transfer.  It also sets up the HttpMessageConverter which takes care of your @RequestBody and @ResponseBody annotations.  In short, one line turns on all of your Spring Web MVC annotations.  Alternatively I could leave this off and configure my entire controller via xml, however I consider that configuration to be somewhat tedious and counter-productive, so I'm not going to show it here.

The <context:component-scan> tag activates all of your Spring beans, as well as scans the package indicated for any bean annotations to be registered automatically, such as @Component, @Service, @Repository, etc.  This is a shortcut that allows you to skip the tedious, manual creation of xml configuration for registering simple beans.  For example, I don't need to register my InstitutionService.

 Not Needed:
<beans>
    <!-- snip -->
    <bean name="institutionService" class="org.gitter.fwc.InstitutionService">
        <property name="dao" ref="institutionDAO" />
    </bean>
</beans>

As promised, here is an annotation configuration alternative to the applicationContext.xml configuration above.

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "org.gitter.fwc" })
public class WebMvcConfiguration {}

Now that everything is configured, we just need a service implementation.

Spring Rest Service Implementation:
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/institution")
public class InstitutionRestController {

    @Autowired
    private InstitutionService service;

    @RequestMapping(value = "/{keyword}", method = RequestMethod.GET)
    public @ResponseBody List<Map<String, String>> find(
            @PathVariable("keyword") String keyword) {
        return service.findByKeyword(keyword);
    }
}

Here's the breakdown
  1. The @Controller annotation marks it as a Web MVC Controller and is picked up by the context component scan so it can be registered as a Spring bean.
  2. The @RequestMapping annotation allows us to set a URL mapping to our web methods.  This is analogous to the @Path annotation in JAX-RS.  In addition, we are mapping the GET method via the method attribute of this annotation, as opposed to the @GET annotation in JAX-RS.
  3. The @Autowired annotation is used to inject one Spring resource into another.  Again, Dependency Injection is not the subject of this article, so I won't go into detail.  However, my InstitutionService is marked as a @Component so it was picked up by the context component scan and registered as a spring bean, enabling it for auto wired injection.
  4. The @ResponseBody annotation activates the HttpMessageConverter when encountered during a service method call to convert the returned object to an HTTP response.  Alternatively, as of Spring 4, you can put @ResponseBody on the class level, or use @RestController instead of @Controller.  Either of these will cause the HttpMessageConverter to be invoked for all of the service methods so you don't have to annotate each method.
  5. The @PathVariable annotation is analogous to the @PathParam JAX-RS annotation and simply maps the parameter to a URL path variable named "{keyword}".

Analysis


One topic I did not cover is the customization for handling of request and response objects.  However, most JAX-RS implementations and Spring will use 3rd party libraries for marshaling and unmarshaling that data anyway.  Suffice to say, it is possible to do this using either method through fairly simple configuration so I'm not going to go into detail for sake of brevity.

Another topic not addressed in the examples is that of bean scope.  It can be advantageous to scope a bean's lifecycle to a user's HTTP Session, instead of to the request itself.  The ubiquitous example is the shopping cart.  You don't want to have to recreate the entire cart each time the user adds an item, nor do you want to have to serialize and pass that entire cart back and forth from server to client or store it on the client.  There are many ways to preserve the state of this cart, but one easy way to handle this is through the use of a bean scoped to the HTTP Session.  Again, there is no clear advantage.  Spring offers the ability to scope your beans via the scope attribute of the bean tag in xml or via the @Scope annotation on your beans, though you must use a web-aware application context such as the XmlWebApplicationContext or ClassPathXmlApplicationContext.  While EJB 3 itself does not do this, you can achieve this through the use of the @SessionScoped annotation from CDI on CDI beans which can be injected into your services.

So which is better?  I set out to elaborate upon the cliché "it depends" answer, but I have ironically arrived back at the same conclusion.  In short, while Spring Web MVC is easy to learn and even fun to use it offers no clear advantage.  It is my opinion that you don't choose to build a web application with Spring to get Web MVC.  However, if you've already chosen to use Spring and want to add restful web services, Web MVC is probably the way to go.  If you're adding Spring to an existing application with restful web services, you may actually be better served to hook the existing framework (e.g. Resteasy or Jersey) into the Spring Web module instead of reconfiguring everything for Web MVC.  This idea is discussed in Spring's documentation at http://docs.spring.io.