Uncategorized

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.

18 thoughts on “Spring WS and static wsdls

  1. 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.

  2. 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…

    1. 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

  3. I am new in Spring Ws .This is simple and effective quick tutorial it is .
    But where is the bean definition for <<>>

    1. Thank you, glad you found it useful.
      Your right, I have not included the bean definition for the MessageRouter. The definition of this bean depends on how your design is. In my case the Endpoint handles the incoming message and routes it to another class to process the order. This may involve communication with other systems or databases. So I didn’t include this because I suspected that it would clutter the example. The focus in this post is on Spring WS and in that respect the configuration of the servlet, payload endpoint mapping, the endpoint itself ++ are the most important aspects.

  4. Hi,
    Now, with spring-ws-2.0.2, the definition of a static WSDL is done with :

    where the id will be used when exposing the WSDL. The WSDL defined in the ‘Orders.wsdl’ file can then be accessed via GET requests to a URL of the following form (substitute the host, port and servlet context path as appropriate)
    http://localhost:8080/spring-ws/orders.wsdl

    Hope this helps
    Thanks for your article
    Ticker

    1. Hi,

      I could not publish the wsdl since this example was inspired by some work done at a client. I therefore had to anonymize the post.

  5. When I originally commented I clicked the “Notify me when new comments are added”
    checkbox and now each time a comment is added I get
    four emails with the same comment. Is there any way you can
    remove people from that service? Thanks!

  6. I have a wsdl from existing service and we have to create a new spring-ws and have to expose the same wsdl so that we dont have to change the clients. We may need to change only location URI. I have gone through this post and figured that there is no way to create web-service from wsdl in spring. you have to have a schema defined. In my case i have so many methods in my webservice, is there a way to create service without explicitely writting schema…

    thanks in advance

Leave a reply to ketiljensen Cancel reply