Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring WS and JAXB - Configuring SOAPMessageDispatcher, DefaultMethodEndpointAdapter and MarshallingPayloadMethodProcessor

When working with Spring-WS, the configuration is very minimal because i have always been using annotations. Recently i have been trying to test out how to include attachements in SOAP responses and to get it to work i ended up with the following configuration.

<bean id="messageReceiver"
    class="org.springframework.ws.soap.server.SoapMessageDispatcher">
    <property name="endpointAdapters">
        <list>
            <ref bean="defaultMethodEndpointAdapter" />
        </list>
    </property>
</bean> 

<bean id="defaultMethodEndpointAdapter"
    class="org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter">
    <property name="methodArgumentResolvers">
        <list>
            <!-- Be careful here! You might need to add more processors if you do 
                more than webservices! -->
            <ref bean="marshallingPayloadMethodProcessor" />
        </list>
    </property>
    <property name="methodReturnValueHandlers">
        <list>
            <ref bean="marshallingPayloadMethodProcessor" />
        </list>
    </property>
</bean>     

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
    <property name="contextPath" value="com.mypackage.ws" />
    <property name="mtomEnabled" value="true" />
</bean>

<bean id="marshallingPayloadMethodProcessor"
    class="org.springframework.ws.server.endpoint.adapter.method.MarshallingPayloadMethodProcessor">
    <constructor-arg ref="marshaller" />
    <constructor-arg ref="marshaller" />
</bean> 

With the above, i can generate a SOAP response with an attachment. The problem is that i don't really understand what is going on. (i.e. what is the above configuration doing that enables the MTOM attachments.

To enable attachments:

  • Why do i need to configure a JAXB marshaller? All the web services that do not use attachments work fine without this configuration. All i have to do is use the @EndPoint annotation. The request/response objects for the non attachment webservice are also JAXB based so this suggests that maybe i am not doing this right (Even though it works).

  • What is the purpose of the messageReceiver and defaultmethodEndpointAdapter beans shown in the above configuration? The non attachment Endpoints work fine without these.

  • And finally can any of the above configuration be annotated instead of XML? I noticed that JAX-WS has an @MTOM annotation but could not find an equivalent for Spring-WS

Even though the services work as i expect them i am a bit worried that maybe the configuration is not right. I would like to understand why these are required and thus maybe i can make a better decision as to whether what i am doing is right or wrong.

Thanks in advance

like image 324
ziggy Avatar asked Jul 08 '12 13:07

ziggy


2 Answers

Spring will automatically create these beans for you if you don't do it yourself. That's why you didn't have to before.

To enable mtom, you set mtomEnabled = true on the marshaller. Since you created the marshaller yourself, you have to create the beans that depend on it specifically because otherwise Spring wouldn't know about it.

I'm not 100% sure if the MarshallingPayloadMethodProcessor is created by default without defining it yourself, but I'm 100% sure the DefaultMethodEndpointAdapter is.

The job of the DefaultMethodEndpointAdapter is just there to map your endpoints, it's able to perform tasks like delegating to argument handlers before calling your endpoint, and taking the return value from it and turning it into an mtom message. That's what the MarshallingPayloadMethodProcessor does.

The above can be annotated as well. Take a look at the Spring WS mtom sample which is located here: https://github.com/spring-projects/spring-ws-samples/tree/master/mtom

To sum it up, the reason why you have to create all the extra beans is because you customized the marshaller. Since you did that, you have to create any bean that depends on it as well, passing in the dependency (unless it uses a bean name that Spring will just look up by convention (like messageSource).

like image 74
int21h Avatar answered Nov 10 '22 15:11

int21h


Spring has become so vast its hard to get correct information for all our problems. I have mainly faced issue with the messageReceiver where we create the bean for SoapMessageDispatcher. The example

https://github.com/spring-projects/spring-ws-samples/tree/master/mtom

I see works with that configuration but it fails with "No adapter for the endpoint error" when we add @SoapHeader annotations for the endpoints.

The only fix i see is to remove the messageReceiver bean from the configuration.

So your configuration is enough to invoke the webservice.

@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext context) {
    MessageDispatcherServlet servlet = new MessageDispatcherServlet();
    servlet.setApplicationContext(context);
    servlet.setTransformWsdlLocations(true);
    return new ServletRegistrationBean(servlet, "/ws/*");
}

@Bean(name = "studentDetails")
public Wsdl11Definition studentDefinition() {
  SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
  wsdl11Definition.setWsdl(new ClassPathResource("schema/studentDetails.wsdl"));
  return wsdl11Definition;
}


@Bean
public SaajSoapMessageFactory messageFactory() {
    SaajSoapMessageFactory s = new SaajSoapMessageFactory();
    s.setSoapVersion(SoapVersion.SOAP_12);
    return s;
}
like image 1
zee Avatar answered Nov 10 '22 16:11

zee