JPA & Spring & Spring-WS : impossible d'avoir une transaction
Bonjour à tous, je suis débutant en Spring. Je tente de créer un web service permettant d’interagir avec une base de donnée.
Pour cela je dispose de :
- MySQL
- Hibernate 3.6.6
- Spring 3.0.5.RELEASE
- Spring-WS 2.0.2.RELEASE
- Tomcat 7
J'ai configuré Spring pour utiliser JPA.
spring.xml
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
|
<beans>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" />
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml" />
<property name="dataSources">
<map>
<entry key="localDataSource" value-ref="dataSource" />
</map>
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:annotation-config />
<context:component-scan base-package="fr.company.compta.business" />
</beans> |
persistence.xml
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
<persistence>
<persistence-unit name="compta-business" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
...
<class>fr.company.compta.business.data.entity.Thirdparty</class>
...
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="compta"/>
<property name="hibernate.connection.password" value="compta"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/compta"/>
<property name="hibernate.hbm2ddl.auto" value="validate" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence> |
Mon point d'entrée est un web service, d'où la présence d'un web.xml
web.xml
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
<web-app>
<display-name>Compta Business</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/META-INF/spring.xml</param-value>
</context-param>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
</web-app> |
Je tente d'appeler un service pour insérer un objet en base. Pour cela le endpoint appelle une classe service gérant les transactions, cette dernière appelle une DAO, qui elle appelle une DAO générique.
Et bien sûr cette dernière utilise l'entityManager configuré.
Endpoint : appel de "createThirdpartyRequest" via SOAP UI
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
@Endpoint
public class BasicEndpoint {
private static final String NAMESPACE_URI = "http://company.fr/compta/schemas";
private XPath nameExpression;
private ThirdpartyService thirdpartyService;
@Autowired
public BasicEndpoint(ThirdpartyService thirdpartyService)
throws JDOMException {
this.thirdpartyService = thirdpartyService;
Namespace namespace = Namespace.getNamespace("x", NAMESPACE_URI);
nameExpression = XPath.newInstance("//x:Name");
nameExpression.addNamespace(namespace);
}
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "CreateThirdpartyRequest")
public void createThirdpartyRequest(
@RequestPayload Element createThirdpartyRequest) throws Exception {
String name = nameExpression.valueOf(createThirdpartyRequest);
thirdpartyService.createThirdparty(name);
}
} |
Service
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
@Service("ThirdpartyService")
@Transactional
public class ThirdpartyServiceImpl implements ThirdpartyService {
@Autowired
private ThirdpartyDao thirdpartyDao;
@Override
@Transactional(readOnly = false)
public void createThirdparty(String name) {
Thirdparty thirdparty = new Thirdparty(name);
thirdpartyDao.create(thirdparty);
}
} |
DAO
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
@Service("ThirdpartyDao")
public class ThirdpartyDaoImpl implements ThirdpartyDao {
@Autowired
private GenericDao dao;
@Override
public void create(Thirdparty thirdparty) {
dao.create(thirdparty);
}
...
} |
DAO générique
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
@Repository("GenericDao")
@Transactional(propagation=Propagation.MANDATORY)
public class GenericDaoImpl implements GenericDao {
@PersistenceContext
private EntityManager em;
@Override
@Transactional(propagation=Propagation.REQUIRED, readOnly=true)
public <T> T create(T t) {
em.persist(t);
em.flush();
em.refresh(t);
return t;
}
...
} |
Le WSDL est bien généré et j'appelle le service "CreateThirdpartyRequest" avec SoapUI en précisant un paramètre "name".
Or une exception est générée :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
|
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:792)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at $Proxy240.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at $Proxy232.flush(Unknown Source)
at fr.company.compta.business.data.access.impl.GenericDaoImpl.create(GenericDaoImpl.java:25)
at fr.company.compta.business.data.access.impl.ThirdpartyDaoImpl.create(ThirdpartyDaoImpl.java:21)
at fr.company.compta.business.service.logic.impl.ThirdpartyServiceImpl.createThirdparty(ThirdpartyServiceImpl.java:25)
at fr.company.compta.business.web.endpoint.BasicEndpoint.createThirdpartyRequest(BasicEndpoint.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.ws.server.endpoint.MethodEndpoint.invoke(MethodEndpoint.java:132)
at org.springframework.ws.server.endpoint.adapter.DefaultMethodEndpointAdapter.invokeInternal(DefaultMethodEndpointAdapter.java:229)
at org.springframework.ws.server.endpoint.adapter.AbstractMethodEndpointAdapter.invoke(AbstractMethodEndpointAdapter.java:53)
at org.springframework.ws.server.MessageDispatcher.dispatch(MessageDispatcher.java:231)
at org.springframework.ws.server.MessageDispatcher.receive(MessageDispatcher.java:172)
at org.springframework.ws.transport.support.WebServiceMessageReceiverObjectSupport.handleConnection(WebServiceMessageReceiverObjectSupport.java:88)
at org.springframework.ws.transport.http.WebServiceMessageReceiverHandlerAdapter.handle(WebServiceMessageReceiverHandlerAdapter.java:57)
at org.springframework.ws.transport.http.MessageDispatcherServlet.doService(MessageDispatcherServlet.java:222)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:851)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:257)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:1764)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662) |
:P
Je pense avoir mal configuré le transactionManager ou bien mal annoté mes classes et méthodes ... Qu'en pensez vous ?
Merci à vous