20

I am currently working on Spring soap server project. I started off with the Getting Started guide from Spring here http://spring.io/guides/gs/producing-web-service/ to build a basic SOAP service.

The default SOAP protocol is SOAP v1.1. Is there a way I could set the protocol to v1.2, possibly via annotations?

I tried @BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING) annotation on the @Endpoint class but it doesnt seem to work.

I also tried @Endpoint(value = SOAPBinding.SOAP12HTTP_BINDING) to set it, but this doesnt work either as seen in the logs on startup

INFO --- [nio-8080-exec-1] o.s.ws.soap.saaj.SaajSoapMessageFactory  :
 Creating SAAJ 1.3 MessageFactory with SOAP 1.1 Protocol

Ofcourse, if I post a SOAP request to the server, I get the following error

2015-01-19 15:50:17.610 ERROR 20172 --- [nio-8080-exec-1] c.sun.xml.internal.messaging.saaj.soap : SAAJ0533: Cannot create message: incorrect content-type for SOAP version. Got application/soap+xml;
 charset=utf-8, but expected text/xml
2015-01-19 15:50:17.611 ERROR 20172 --- [nio-8080-exec-1] c.sun.xml.internal.messaging.saaj.soap   :
 SAAJ0535: Unable to internalize message
2015-01-19 15:50:17.617 ERROR 20172 --- [nio-8080-exec-1] a.c.c.C.[.[.[.[messageDispatcherServlet] :
 Servlet.service() for servlet [messageDispatcherServlet] in context with path [] threw exception [R
equest processing failed; nested exception is org.springframework.ws.soap.SoapMessageCreationException: Could not create message from InputStream: Unable to internalize message; nested exception is com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl: Unable to internalize message] with root cause

com.sun.xml.internal.messaging.saaj.soap.SOAPVersionMismatchException: Cannot create message: incorrect content-type for SOAP version. Got: application/soap+xml; charset=utf-8 Expected: text/xml
        at com.sun.xml.internal.messaging.saaj.soap.MessageImpl.init(Unknown Source)
        at com.sun.xml.internal.messaging.saaj.soap.MessageImpl.<init>(Unknown Source)
        at com.sun.xml.internal.messaging.saaj.soap.ver1_1.Message1_1Impl.<init>(Unknown Source)
        at com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl.createMessage(Unknown Source)

Any help is appreciated.

Thanks!

Dexter
  • 1,621
  • 3
  • 18
  • 38

4 Answers4

40

You are mixing Spring-WS with annotations from JAX-WS (package javax.xml.ws). That won't work. To configure Spring-WS to use SOAP 1.2, add the following bean definition:

@Bean
public SaajSoapMessageFactory messageFactory() {
    SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
    messageFactory.setSoapVersion(SoapVersion.SOAP_12);
    return messageFactory;
}
Andreas Veithen
  • 8,868
  • 3
  • 25
  • 28
  • 5
    Just a quick note that might catch some people out, the message factory should be declared as a separate bean (using `@Bean`) as it has been here. It will not work if you construct it manually as it relies of the Spring lifecycle method `afterPropertiesSet()`being called to construct the internal message factory. It's a bit of a strange design and might catch you out. – Robert Hunt Aug 02 '16 at 09:19
  • 5
    I did it like this but when spring boot starts I still get o.s.w.s.saaj.SaajSoapMessageFactory.afterPropertiesSet - Creating SAAJ 1.3 MessageFactory with SOAP 1.1 Protocol – kenny Jun 07 '18 at 08:22
  • 2
    @kenny That means you are failed to register the bean. Make sure the bean is registered with name messageFactory as the method name implies in this answer. You can also choose to register the bean like so `@Bean(name= DEFAULT_MESSAGE_FACTORY_BEAN_NAME)`. Also make sure you are somehow not changing the default message factory name while registering the `messageDispatcherServlet` . The `MessageDispatcherServlet` has a method `setMessageFactoryBeanName()`, and if you are not registering a `MessageFactory` instance with name set here, you will get this error. Hope this helps someone. – alegria May 06 '21 at 21:16
2

If the messageFactory Bean is not in the singleton scope, then the afterPropertiesSet() method in the SaajSoapMessageFactory is not called on bean instantation.

The afterPropertiesSet() method sets up an internal message factory. So if your messageFactory bean has its own scope you need to set up the internal message factory like this:

@Bean
@Scope("custom-scope")
public SaajSoapMessageFactory messageFactory() {
    SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory();
    messageFactory.messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
    return messageFactory;
}
Joman68
  • 2,248
  • 3
  • 34
  • 36
2

As mentioned in the spring-ws issue 926, using a WebserviceGatewaySupport, the messageFactory @Bean injection does not work with many spring-ws versions because of the WebserviceTemplate encapsulation.

A workaround is both to set the SOAP version and affect the specific SOAPMessageFactory1_2Impl in order to send a proper SOAP 1.2 message :

WebServiceMessageFactory messageFactory = super.getWebServiceTemplate().getMessageFactory();
SaajSoapMessageFactory saajSoapMessageFactory = (SaajSoapMessageFactory)messageFactory;
saajSoapMessageFactory.setSoapVersion(SoapVersion.SOAP_12);
saajSoapMessageFactory.setMessageFactory(new SOAPMessageFactory1_2Impl());                super.getWebServiceTemplate().setMessageFactory(saajSoapMessageFactory);
super.getWebServiceTemplate().marshalSendAndReceive(message, soapActionHeader());
bdulac
  • 1,686
  • 17
  • 26
1

The messageFactory() @Bean is a necessary step, but isn't it also fundamental to add

wsdl11Definition.setCreateSoap12Binding(true); 

to the service definition, to generate the appropriate soap 1.2 binding?

Anyway, thanks to Andreas Veithen

rekotc
  • 595
  • 1
  • 10
  • 21