Spring WS and static wsdls

I’ve been using Spring WS for a while now and come to learn that the dynamic wsdl generarion is functioning quite well. A couple of days ago I was however forced to explore the static wsdl part of the framework as we needed to make a component backward compatible with an earlier version written using Tibco. Luckily, I found what I needed in the Spring WS reference guide
(http://static.springframework.org/spring-ws/sites/1.5/reference/html/server.html)…

I placed the wsdl in a wsdl folder under the WEB-INF directory of the web application and added the following bean definition in the spring beans config:

<bean id="Order_v1_0" class="org.springframework.ws.wsdl.wsdl11.SimpleWsdl11Definition">
   <constructor-arg value="WEB-INF/wsdl/Order_v1_0.wsdl"/>
</bean>

This will let you look up the wsdl on the web server. In addition I found that to make the wsdl accesible on the same url as before, I needed to add a servlet mapping in web.xml:

<servlet-mapping>
   <servlet-name&gt;spring-ws&lt;/servlet-name/>
   <url-pattern>/Services/OrderDomain</url-pattern>
</servlet-mapping>

Assume the web server is running on port 9090 on localhost, we can now access the wsdl on the following url:

http://localhost:9090/Services/OrderDomain/Order_v1_0.wsdl

There are a few more things we need to set up in the spring config in order to get the web service up and running, these are:

  1. Create an endpoint class which are to handle incoming web service requests
  2. Add the required spring configuraion

The following class shows the OrderServiceEndpoint class.

@Endpoint
public class OrderV10Endpoint {
   private OrderV1Router messageRouter;   

   @PayloadRoot(localPart = "StartOrderRequest", namespace="http://jensen.com/order/v1_0")
   public StartOrderResponse startOrder(StartOrderRequest startOrderRequest){
      return startOrder(this.messageRouter.orderSimCard (startOrderRequest));
   }   

   public void setMessageRouter(OrderV1Router messageRouter){
      this.messageRouter = messageRouter;
   }
}

There are especially two things worth noticing:

  1. The class must be annotated with the @Endpoint annotation for the Spring ws framework to pick it up
  2. In our case we must also annotate the method with a PayloadRoot annotation. The arguments to this is the type of object in the request (payload) and the namespace. It is important that these two arguments are correct.

2. Add required Spring configuration

First thing to do is to add a bean definition for our new Endpoint class:

<bean id="order1_0_Endpoint" class="com.jensen.OrderV10Endpoint"/>
   <property name="messageRouter" ref="messageRouter" />
</bean>

Nothing fancy here, just wire up the endpoint with dependencies set, in this case we are just passing the message through a message router.

In addition to this, you need a marshallingEndpointAdapter (with a marshaller set up – we usually use JaxB for this purpose) and a PayloadRootAnnotationMethodEndpointMapping. The following xml snippets shows an example:

<!--Payload endpoint mapping bean set up. -->
<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping" </bean>

<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
   <property name="contextPath" value="com.jensen.order.version1:com.jensen.common"/>
   <property name="schemas">
     <list>
        <value>classpath:/Resources/order-schema.xsd</value>
        <value>classpath:/Resources/Common.xsd</value>
     </list>
   </property>
</bean>

<!-- Marshaller for unmarshalling incoming xml objects to POJOs-->
<bean class="org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter">
   <constructor-arg ref="jaxb2Marshaller" />
</bean>

The first two bean definitions are straight forward, Spring WS offer other endpoint mapping strategies so feel free to explore.
The third one, the Jaxb2Marshaller, requires you to configure a context path, this will be the package names of the generated Jaxb2 objects, and a reference to the schemas where the definitions xsd elements reside. The important thing here is of course that Resources is on the class path.

Word of advice

As I’ve worked through the process of making this work, I’ve come to realize that there really isn’t much difference between the static wsdl approach and the “dynamically generated wsdl from xsd approach”. Actually, I feel that the static wsdl approach is simpler when you already have this, from say a “legacy” web service. If you, on the other hand, are creating the web service from scratch I think that the generation from xsd is a better approach.

6 Responses to “Spring WS and static wsdls”

  1. Prasenjit Says:

    It was good quick reference and worked well for me.
    Thanks!

  2. ketiljensen Says:

    Thanks, glad you found it useful.

  3. Ah Says:

    Good article.
    I need to convert legacy web services to Spring WS.I used this post as reference, i was able to create a web service and deploy it.WSDL is accessible through web server.

    One last issue i had is testing the web service it self.I tried several different URLs ,none of them worked.Any thoughts ?
    Iam able to access wsdl from
    http://locasthost:8080/MyWeb/services/Myservice.wsdl

    But i’m not able to test the actually methods using the same URL.

  4. ketiljensen Says:

    Hi, glad you found it useful.
    How do you test the web service? If you write a spring ws client then it should be accessible on http://localhost:8080/MyWeb/services

    If you need additional input on how to use spring ws on the client you can have a look at http://static.springsource.org/spring-ws/sites/1.5/reference/html/client.html

  5. Nommi Says:

    hello
    i working on spring ws service it is very intrsting to create ws using spring.. i having some problem is there any way that u can mapp multiple xsd schema to generate one complete wsdl…

    please exaplain it…

    • ketiljensen Says:

      I believe you can use the CommonXsdSchemaCollection to achieve this. From the spring ws documentation (tutorial) – http://static.springsource.org/spring-ws/sites/1.5/reference/html/server.html#server-automatic-wsdl-exposure

      “If you want to use multiple schemas, either by includes or imports, you might want to use the CommonsXsdSchemaCollection, and refer to that from the DefaultWsdl11Definition, like so:

      <bean id="schemaCollection" class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
          <description>
              This bean wrap the messages.xsd (which imports types.xsd), and inlines them as a one.
          </description>
          <property name="xsds">
              <list>
                  <value>/WEB-INF/xsds/Orders.xsd</value>
                  <value>/WEB-INF/xsds/Customers.xsd</value>
              </list>
          </property>
          <property name="inline" value="true"/>
      </bean>
      

      Hope this helps

Leave a Reply