We have a legacy XML based configuration spring-ws application that contains endpointInterceptors that have DAOs injected to obtain configuration from the database. These DAOs have the hibernate sessionFactory injected.
When we have upgraded to spring 4.2.0.RELEASE (from spring 3.2.5.RELEASE) and spring-ws 2.2.1.RELEASE (from spring-ws 2.1.4.RELEASE) I noticed that the DAO was not a proxy object and it seemed that the intercetor was going to the AnnotationActionEndpointMapping class instead of the PayloadRootAnnotationMethodEndpointMapping class.
I therefore created a spring-boot version 1.3.0.RELEASE based example that outlines our legacy application and the problem is evident in both XML base configuration and annotation based configuration. Please note that annotation @EnableTransactionManagement exists within the example and that exists within the legacy application.
If you commented out the from the application context or @EnableWS from the @Congiuration object then the DAO was a proxy object, the interceptor seemed to be going to the correct endpoing (i.e PayloadRootAnnotationMethodEndpointMapping) and the unit test worked with no transaction error.
StackTrace when or EnableWS is not commented out.
org.springframework.ws.soap.client.SoapFaultClientException: Could not obtain transaction-synchronized Session for current thread
at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:38)
at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:830)
at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:624)
at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)
at hello.ApplicationTests.testSendAndReceive(ApplicationTests.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:254)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:193)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Extract of the XML configuration that causes the above exception :
<sws:annotation-driven>
<sws:interceptors>
<ref bean="loggingInterceptorAU"/>
</sws:interceptors>
<bean id="loggingInterceptorAU" class="hello.interceptor.LoggingEndpointInterceptor"/>
Extract of the annotation configuration that causes the above exception :
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/ws/*");
}
@Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
}
/**
* Declaring the loggingInterceptor.
* @return the new logging interceptor.
*/
@Bean
public LoggingEndpointInterceptor loggingInterceptor() {
LoggingEndpointInterceptor loggingEndpointInterceptor = new LoggingEndpointInterceptor();
return loggingEndpointInterceptor;
}
/**
* Adds interceptors.
* @param interceptors
*/
@Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
// if these rows are uncommented
// and payloadRootAnnotationMethodEndpointMapping method is commented you get
// Error: SoapFaultClientException: Could not obtain transaction-synchronized Session for current thread
interceptors.add(loggingInterceptor());
super.addInterceptors(interceptors);
}
/**
* Spring Boot with Plain Hibernate
* @see {https://github.com/mdeinum/samples/tree/master/spring-boot-plain-hibernate}
*
* Need to also set within application.properties.
* spring.jpa.properties.hibernate.current_session_context_class=org.springframework.orm.hibernate4.SpringSessionContext
* @return
*/
@Bean(name="sessionFactory")
public HibernateJpaSessionFactoryBean sessionFactory() {
return new HibernateJpaSessionFactoryBean();
}
}
After a closer inspection of the makeup of AnnotationActionEndpointMapping i have noticed that it implements BeanPostProcessor. The spring doco http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html suggests that “... Because AOP auto-proxying is implemented as a BeanPostProcessor itself, neither BeanPostProcessors nor the beans they reference directly are eligible for auto-proxying, and thus do not have aspects woven into them.” and therefore I understand that @Transactional will not work.
public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpointMapping implements BeanPostProcessor
My questions are : *what has changed that has caused spring-ws interceptors to be mapped by default to the AnnotationActionEndpointMapping class? * As per Spring documentation it is suggested that both and or @EnableWs and method addInterceptors are requred. Is there any impact if is commented out in our legacy application?
Please note we have interceptors that are only invoked for certain requests using the following and we do not want to specicially create a PayloadRootAnnotationMethodEndpointMapping bean with the list of interceptors to overcome this problem:
<sws:interceptors>
<sws:payloadRoot localPart="TestRequest" namespaceUri="http://www.test.com/test/request/1.0">
...