Dans le billet précédant [step17] nous avons mis en place JPA avec Spring en utilisant LocalEntityManagerFactoryBean avec l’implémentations JPA JPA/Eclipselink et les 2 bases de données H2 et Derby. Nous avons vu que le support Spring ORM nous permet de gérer JPA dans un conteneur (Spring) JPA ce qui permet de:
- gérer les ouvertures/fermetures des EntityManager.
- gérer les ouvertures/fermetures des EntityTransaction (commit/rollback) via l’annotation Spring org.springframework.transaction.annotation.@Transactionnal
A ce stade nous avons déclaré un persistence-unit par implémentation JPA et par base de données, ce qui engendre une duplication de déclaration XML (« provider », « propertes », et « class ») . Par exemple si on souhaite utiliser 2 base de données pour une même implémentation JPA, l’information « provider » est dupliquée 2 fois dans le fichier persistence.xml mais pire la déclaration des éléments « class » est aussi dupliquée. Lorsque l’on souhaite gérer une nouvelle classe Java domain persistente, l’élément « class » doit être ajouté dans les 2 déclaration des persistence-unit. Si on ajoute à ça une autre implémentation JPA, ceci signifie que l’on a 2 (implémentation JPA) * 2 (base de données) = 4 déclarations de persistence-unit.
L’idéal serait d’avoir 1 seule déclaration persistence-unit qui gère tous les cas. Le support de Spring ORM permet de gérer ce cas-ci en déléguant les informations de « provider » et de « properties » à des bean Spring en utilisant LocalContainerEntityManagerFactoryBean. LocalContainerEntityManagerFactoryBean permet d’avoir une seule déclaration persistence-unit pour n’importe quelle implémentation JPA et base de données :
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="dynaresume" transaction-type="RESOURCE_LOCAL"> <class>org.dynaresume.domain.User</class> </persistence-unit> </persistence>
C’est ce que nous allons effectuer dans ce billet en mettant en place JPA avec LocalContainerEntityManagerFactoryBean en utilisant JPA/Hibernate et JPA/Eclipselink avec les 2 bases de données H2 et Derby.
Vous pouvez télécharger le zip org.dynaresume_step18.zip qui contient les projets expliqués ci dessous:
- org.dynaresume.test.jpa_lfb : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaEntityManagerFactoryBean.
- org.dynaresume.test.jpa_lcfb_1 : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean. Dans ce projet l’implémentation JPA/Eclipselink ne fonctionne pas du au problème de LoadTimeWeaver (pour JPA/Hibernate le problème ne se pose pas).
- org.dynaresume.test.jpa_lcfb_withoutLTW : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean. Dans ce projet l’implémentation JPA/Eclipselink fonctionne en désactivant le LoadTimeWeaver.
- org.dynaresume.test.jpa_lcfb_withLTW : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean. Dans ce projet l’implémentation JPA/Eclipselink fonctionne en utilisant l’agent Spring.
- org.dynaresume.test.jpa_lcfb_2 : projet avec 2 implémentations JPA JPA/Eclipselink et JPA/hibernate avec 2 bases de données H2 et Derby qui utilise LocaContainerEntityManagerFactoryBean et qui délègue les informations provider et properties à des bean Spring.
- org.dynaresume.test.jpa_lcfb_3 : projet identique au projet org.dynaresume.test.jpa_lcfb_2 mais qui « splitte » la déclaration des bean en plusieurs fichier XML Spring applicationContext qui définiront dans le prochain billet nos bundles OSGi.
- org.dynaresume.test.jpa_lcfb_4 : projet identique au projet org.dynaresume.test.jpa_lcfb_3 mais qui utilise org.springframework.beans.factory.config.PropertyPlaceholderConfigurer pour définir les propriétés de la base de données dans un fichier de propriétés.
- spring-target-platform-dao : projet qui contient toutes les librairies nécessaires à la couche DAO.
Pré-requis
Avant de démarrer ce billet vous devez avoir :
- créé la base de données H2 et copié la base H2 dynaresume.data.db dans C:/db/h2. Pour vérifier que la base H2 est bien installée, je vous conseille de tester la base H2.
- créé la base de données Derby et copié la base Derby (répertoire dynaresume ) dans le répertoire C:/db/derby. Pour vérifier que la base Derby est bien installée, je vous conseille de tester la base Derby.
Téléchargez le zip spring-target-platform-dao.zip qui contient les librairies JARs JPA, JPA/Hibernate,… récupérés via Maven dans le billet [step14] puis importez le projet spring-target-platform-dao dans votre workspace.
REMARQUE : nous avons créé la base de données via des scripts mais JPA est capable de générer la base de données en utilisant les informations de mapping.
org.dynaresume.test.jpa_lfb
Dans cette section nous allons créer le projet org.dynaresume.test.jpa_lfb qui utilise LocaEntityManagerFactoryBean avec les 2 implémentation JPA JPA/Hibernate et JPA/EclipseLink avec les 2 bases de données H2 et Derby. Ici je ne vais pas détaillé le code JPA car celui-ci est déjà expliqué dans les billets précédants.
Créez le projet Java org.dynaresume.test.jpa_lfb.
Librairies
Ajoutez au projet les librairies provenant du projet spring-target-platform-dao :
- API JPA & Transaction stockés dans le répertoire : lib/javax.
- les 2 Implémentation JPA :
- JPA/Hibernate : stockés dans le répertoire : lib/jpa-hibernate.
- JPA/EclipseLink: stockés dans le répertoire : lib/jpa-eclipselink.
- le support de Spring ORM : stockés dans le répertoire : lib/spring-orm.
- l’implémentation SL4J avec log4j stocké dans le répertoire : lib/slf4j-log4j.
- 2 bases de données :
- Derby : stockés dans le répertoire : lib/derby. Le JAR com.springsource.org.apache.derby.client-10.5.1000001.764942.jar n’est pas nécéssaire.
- H2: stockés dans le répertoire : lib/h2
log4j.properties
L’implémentation JPA/Hibernate utilise SL4J. Nous utilisons l’implémentation log4j de SL4J et pour cela créez le ficher log4j.properties dans le répertoire src du projet :
log4j.rootLogger=info, con log4j.appender.con=org.apache.log4j.ConsoleAppender log4j.appender.con.layout=org.apache.log4j.PatternLayout log4j.appender.con.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
Domain – User
Créez la classe org.dynaresume.domain.User avec le mapping JPA comme suit :
package org.dynaresume.domain; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "T_USER") public class User { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "USR_ID_N") private long id; @Column(name = "USR_LOGIN_C") private String login; @Column(name = "USR_PASSWORD_C") private String password; public User() { } public User(String login, String password) { setLogin(login); setPassword(password); } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getLogin() { return login; } public void setLogin(String login) { this.login = login; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
persistence.xml
Ici nous allons créer le fichier persistence.xml qui déclare les persistence-unit pour chacune des implémentation JPA et base de données soit 2 (implémentation JPA) * 2 (base de données) = 4 persistence-unit. Créez le fichier persistence.xml dans le répertoire META-INF que vous devez créer dans le répertoire src (et pas à la racine du projet comme les bundles OSGi). En effet ce fichier doit se retrouver après compilation du projet dans le répertoire bin. Créez le fichier persistence.xml avec le contenu suivant :
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="dynaresume-hibernate-h2" transaction-type="RESOURCE_LOCAL"> <provider> org.hibernate.ejb.HibernatePersistence </provider> <class>org.dynaresume.domain.User</class> <properties> <property name="hibernate.connection.driver_class" value="org.h2.Driver" /> <property name="hibernate.connection.url" value="jdbc:h2:C:/db/h2/dynaresume" /> <property name="hibernate.connection.username" value="sa" /> <property name="hibernate.connection.password" value="" /> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" /> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit> <persistence-unit name="dynaresume-hibernate-derby" transaction-type="RESOURCE_LOCAL"> <provider> org.hibernate.ejb.HibernatePersistence </provider> <class>org.dynaresume.domain.User</class> <properties> <property name="hibernate.connection.driver_class" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="hibernate.connection.url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="hibernate.connection.username" value="" /> <property name="hibernate.connection.password" value="" /> <property name="hibernate.dialect" value="org.hibernate.dialect.DerbyDialect" /> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit> <persistence-unit name="dynaresume-eclipselink-h2" transaction-type="RESOURCE_LOCAL"> <provider> org.eclipse.persistence.jpa.PersistenceProvider </provider> <class>org.dynaresume.domain.User</class> <properties> <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:h2:C:/db/h2/dynaresume" /> <property name="javax.persistence.jdbc.user" value="sa" /> <property name="javax.persistence.jdbc.password" value="" /> <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.H2Platform" /> <property name="show-sql" value="true" /> </properties> </persistence-unit> <persistence-unit name="dynaresume-eclipselink-derby" transaction-type="RESOURCE_LOCAL"> <provider> org.eclipse.persistence.jpa.PersistenceProvider </provider> <class>org.dynaresume.domain.User</class> <properties> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="javax.persistence.jdbc.user" value="" /> <property name="javax.persistence.jdbc.password" value="" /> <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.DerbyPlatform" /> <property name="show-sql" value="true" /> </properties> </persistence-unit> </persistence>
Comme vous pouvez le constater l’élément « class » se retrouve 4 fois déclarés. Les élements « provider » sont dupliqués 2 fois (2 implémentation JPA).
DAO – UserDAO/UserDAOJpa
Interface UserDAO
Créez l’interface org.dynaresume.dao.UserDAO comme suit :
package org.dynaresume.dao; import java.util.Collection; import org.dynaresume.domain.User; public interface UserDAO { Collection<User> findAllUsers(); User saveUser(User user); }
Implémentation UserDAOJpa
Créez l’implémentation JPA de UserDAOJpa avec la classe org.dynaresume.dao.jpa.UserDAOJpa comme suit :
ackage org.dynaresume.dao.jpa; import java.util.Collection; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import javax.persistence.Query; import org.dynaresume.dao.UserDAO; import org.dynaresume.domain.User; public class UserDAOJpa implements UserDAO { @PersistenceContext private EntityManager entityManager; public Collection<User> findAllUsers() { Query query = entityManager.createQuery("select u from " + User.class.getSimpleName() + " u"); return query.getResultList(); } public User saveUser(User user) { entityManager.persist(user); return user; } }
Service – UserService/UserServiceImpl
Ici nous allons mettre en place la couche Service avec l’interface UserService et son implémentation UserServiceImpl qui va utiliser l’interface UserDAO (et pas l’implémentation direct). On parle de Dépendance d’Injection.
Interface UserService
Créez l’interface org.dynaresume.services.UserService comme suit :
package org.dynaresume.services; import java.util.Collection; import org.dynaresume.domain.User; public interface UserService { Collection<User> findAllUsers(); }
Implémentation UserService
Créez l’implémentation du service UserService avec la classe org.dynaresume.services.impl.UserServiceImpl comme suit :
package org.dynaresume.services.impl; import java.util.Collection; import org.dynaresume.dao.UserDAO; import org.dynaresume.domain.User; import org.dynaresume.services.UserService; import org.springframework.transaction.annotation.Transactional; @Transactional(readOnly=true) public class UserServiceImpl implements UserService { private UserDAO userDAO; public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } public Collection<User> findAllUsers() { return userDAO.findAllUsers(); } @Transactional public User createUser(String login, String password) { User user = new User(login, password); return userDAO.saveUser(user); } }
Test JPA
Test JPA/EclipseLink
Test JPA/EclipseLink – Derby
Créez le fichier XML Spring applicationContext-eclipselink-derby.xml dans le package org.dynaresume comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume-eclipselink-derby" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-eclipselink-derby de persistence.xml.
FindAllUserDynaresumeDerbyEclipseLink
Créez la classe org.dynaresume.test.jpa.eclipselink.derby.FindAllUserDynaresumeDerbyEclipseLink qui permet d’afficher la liste des User de la table T_USER de la base Derby via JPA/Eclipselink :
package org.dynaresume.test.jpa.eclipselink.derby; import java.util.Collection; import org.dynaresume.domain.User; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class FindAllUserDynaresumeDerbyEclipseLink { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-eclipselink-derby.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); Collection<User> users = userService.findAllUsers(); for (User user : users) { System.out.println("User [id=" + user.getId() + " login=" + user.getLogin() + ", password=" + user.getPassword() + "]"); } } }
Lancez cette classe et la console affiche la liste des User de la table T_USER de la base Derby.
CreateUserDynaresumeDerbyEclipseLink
Créez la classe org.dynaresume.test.jpa.eclipselink.derby.CreateUserDynaresumeDerbyEclipseLink qui permet de créer un User dans la table T_USER de la base Derby via JPA/Eclipselink :
package org.dynaresume.test.jpa.eclipselink.derby; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class CreateUserDynaresumeDerbyEclipseLink { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-eclipselink-derby.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); userService.createUser("jpa-user (EclipseLink-Derby)", ""); } }
Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeDerbyEclipseLink pour constater que le User a bien été inséré.
Test JPA/EclipseLink – H2
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume-eclipselink-h2" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-eclipselink-h2 de persistence.xml.
FindAllUserDynaresumeH2EclipseLink
Créez la classe org.dynaresume.test.jpa.eclipselink.h2.FindAllUserDynaresumeH2EclipseLink qui permet d’afficher la liste des User de la table T_USER de la base H2 via JPA/Eclipselink :
package org.dynaresume.test.jpa.eclipselink.h2; import java.util.Collection; import org.dynaresume.domain.User; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class FindAllUserDynaresumeH2EclipseLink { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-eclipselink-h2.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); Collection<User> users = userService.findAllUsers(); for (User user : users) { System.out.println("User [id=" + user.getId() + " login=" + user.getLogin() + ", password=" + user.getPassword() + "]"); } } }}
Lancez cette classe et la console affiche la liste des User de la table T_USER de la base H2.
CreateUserDynaresumeH2EclipseLink
Créez la classe org.dynaresume.test.jpa.eclipselink.h2.CreateUserDynaresumeH2EclipseLink qui permet de créer un User dans la table T_USER de la base H2 via JPA/Eclipselink :
package org.dynaresume.test.jpa.eclipselink.h2; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class CreateUserDynaresumeH2EclipseLink { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-eclipselink-h2.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); userService.createUser("jpa-user (EclipseLink-H2)", ""); } }
Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeH2EclipseLink pour constater que le User a bien été inséré.
Test JPA/Hibernate
Test JPA/Hibernate – Derby
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume-hibernate-derby" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-hibernate-derby de persistence.xml.
FindAllUserDynaresumeDerbyHibernate
Créez la classe org.dynaresume.test.jpa.hibernate.derby.FindAllUserDynaresumeDerbyHibernate qui permet d’afficher la liste des User de la table T_USER de la base Derby via JPA/Hibernate:
package org.dynaresume.test.jpa.hibernate.derby; import java.util.Collection; import org.dynaresume.domain.User; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class FindAllUserDynaresumeDerbyHibernate { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-hibernate-derby.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); Collection<User> users = userService.findAllUsers(); for (User user : users) { System.out.println("User [id=" + user.getId() + " login=" + user.getLogin() + ", password=" + user.getPassword() + "]"); } } }
Lancez cette classe et la console affiche la liste des User de la table T_USER de la base Derby.
CreateUserDynaresumeDerbyHibernate
Créez la classe org.dynaresume.test.jpa.hibernate.derby.CreateUserDynaresumeDerbyHibernate qui permet de créer un User dans la table T_USER de la base Derby via JPA/Hibernate:
package org.dynaresume.test.jpa.hibernate.derby; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class CreateUserDynaresumeDerbyHibernate { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-hibernate-derby.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); userService.createUser("jpa-user (Hibernate-Derby)", ""); } }
Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeDerbyHibernate pour constater que le User a bien été inséré.
Test JPA/Hibernate – H2
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <h2>org.dynaresume.test.jpa_lfb</h2> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume-hibernate-h2" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Ici, la déclaration du bean Spring entityManagerFactory utilise le persistence-unit dynaresume-hibernate-h2 de persistence.xml.
FindAllUserDynaresumeH2Hibernate
Créez la classe org.dynaresume.test.jpa.hibernate.h2.FindAllUserDynaresumeH2Hibernate qui permet d’afficher la liste des User de la table T_USER de la base H2 via JPA/Hibernate:
package org.dynaresume.test.jpa.hibernate.h2; import java.util.Collection; import org.dynaresume.domain.User; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class FindAllUserDynaresumeH2Hibernate { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-hibernate-h2.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); Collection<User> users = userService.findAllUsers(); for (User user : users) { System.out.println("User [id=" + user.getId() + " login=" + user.getLogin() + ", password=" + user.getPassword() + "]"); } } }
Lancez cette classe et la console affiche la liste des User de la table T_USER de la base H2.
CreateUserDynaresumeH2Hibernate
Créez la classe org.dynaresume.test.jpa.hibernate.h2.CreateUserDynaresumeH2Hibernate qui permet de créer un User dans la table T_USER de la base H2 via JPA/Hibernate:
package org.dynaresume.test.jpa.hibernate.h2; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class CreateUserDynaresumeH2Hibernate { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( "org/dynaresume/applicationContext-hibernate-h2.xml"); UserService userService = (UserService) applicationContext .getBean("userService"); userService.createUser("jpa-user (Hibernate-H2)", ""); } }
Lancez cette classe pour insérer un nouveau User puis lancez FindAllUserDynaresumeH2Hibernate pour constater que le User a bien été inséré.
org.dynaresume.test.jpa_lcfb_1
Le projet org.dynaresume.test.jpa_lcfb que nous venons de créer montre bien le problème de duplication des élements « class » et « provider » dans le fichier persistence.xml. Pour régler ce problème nous allons utiliser LocalContainerEntityManagerFactoryBean qui permet de gérer via des bean Spring les informations « provider » et « properties » et qui permet d’utiliser un seul fichier persistence.xml qui déclare uniquement les élements « class ». Dans cette section nous allons simplement remplacer dans nos fichiers XML Spring l’utilisation de LocalEntityManagerFactoryBean en LocalContainerEntityManagerFactoryBean.
Copiez collez le projet org.dynaresume.test.jpa_lfb et renommez le en org.dynaresume.test.jpa_lcfb_1.
Dans les 4 fichiers XML Spring applicationContext-*.xml remplacez org.springframework.orm.jpa.LocalEntityManagerFactoryBean par org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean. Voici l’exemple de la déclaration de l’entityManagerFactory du fichier applicationContext-eclipselink-derby.xml :
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume-eclipselink-derby" /> </bean>
Test JPA
Test JPA/Hibernate
Si vous relancez les classes de tests JPA/Hibernate contenu dans le package org.dynaresume.test.jpa.hibernate, vous pourrez constater qu’il n’y a aucun problème.
Test JPA/EclipseLink
Si vous relancez les classes de tests JPA/Eclipselink contenu dans le package org.dynaresume.test.jpa.eclipselink, l’erreur suivante s’affiche dans la console .
Caused by: java.lang.IllegalStateException: Cannot apply class transformer without LoadTimeWeaver specified
at org.springframework.orm.jpa.persistenceunit.SpringPersistenceUnitInfo.addTransformer(SpringPersistenceUnitInfo.java:78)
...
Cette erreur est du au LoadTimeWeaver qui n’a pas été paramétré. Avant d’expliquer comment résoudre ce problème de LoadTimeWeaver dans la section EclipseLink/Load Time Weaver, je vais tenter d’expliquer en quoi consiste le LoadTimeWeaver via des exemples simples, mais ce sujet mériterait un billet dédié.
LoadTimeWeaver & Lazy loading
Dans la documentation de Eclipselink, la section Using_EclipseLink_JPA_Weaving parle du sujet LoadTimeWeaver et indique que le weaving est notamment utilisé pour le « lazy loading ».
Dans une API d’ORM et notemment une implémentation JPA comme JPA/Hibernate ou JPA/EclipseLink, le « lazy loading » est géré. Si vous ne connaissez pas le « lazy loading », imaginez que vous ayez une entité User qui est associé à une entité Role et que lorsque vous chargez le User vous ne souhaitez pas charger le Role associé. Le Role associé ne se charge qu’à la demande, autrement dit que lorsque la méthode User#getRole() est appelée. En JPA le lazy loading s’écrit comme ceci :
public class User { ... private Role role = null; @OneToOne(fetch=FetchType.LAZY) @JoinColumn(name="USR_ROL_ID_N", referencedColumnName="ROL_ID_N") private Role role; public Role getRole() { return role; } }
Le client qui appelle la méthode User#getRole() déclenchera une requête SQL qui permettra de charger le Role du User dans le cas ou celui-ci n’est pas initialisé. La méthode User#getRole() est un simple POJO et n’a pas de code de requête SQL pour charger la liste des Roles. Pour que la requête SQL se déclenche lors de l’appel de la méthode User#getRole(), son appel doit être surveillé (principe de l’AOP). Chaque implémentation JPA gère le lazy-loading avec sa propre technique. Je vous conseille de lire l’article JPA Implementation patterns : Lazy loading pour plus d’information à ce sujet.
JPA/Hibernate- Run-time proxies
Dans le cas d’Hibernate le lazy loading est gère via un Proxy (CGLIB ou Javassist) . Jusqu’à la version 3.3 d’Hibernate, ce dernier utilisait par défaut les Proxy CGLIB. Depuis la version 3.3, il utilise par défaut les Proxy Javassist (il est quand même possible d’utiliser CGLIB si vous renseignez la propriété hibernate.bytecode.provider=cglib dans le fichier hibernate.properties mis dans le répertoire src).
Lorsque le client récupère une entité User via Hibernate, les champs qui sont déclarés en lazy-loading (ex : dans notre cas le champs role) sont associé à des Proxy. J’ai fait des petits tests ou j’ai modifié la base dynaresume pour qu’elle gère l’association User -> Role. Voici une copie d’écran d’une instance User récupérée via JPA/Hibernate :
Cette copie d’écran montre que l’instance User à le champs privé role renseigné avec Role_$$_javassist_1 qui est un proxy Javassist qui est à l’écoute de l’appel de la méthode User#getRole(). A l’appel de cette méthode le proxy teste si le Role est déja chargé et dans le cas contraire il execute une reqête SQL qui charge le Role. C’est pour cela que la méthode User#getRole() doit impérativement être appelée dans une session hibernate ouverte.
JPA/EclipseLink – Run-time bytecode instrumentation
Dans le cas d’Eclipselink le lazy loading est géré via la technique du load-time weaving qui consiste à changer le bytecode des classes persistentes, lorsque celle-ci est chargée en utilisant un agent Java (qui est renseigné au lancement de la JVM). Je vous conseille de lire l’article Java Agent – Instrumentez vos classes qui donne des explications sur ce qu’est un agent JAVA.
Il est aussi possible de désactiver le LoadTime Weaver de JPA/Eclipselink. J’explique tout cela dans la section EclipseLink/Load Time Weaver J’ai fait des petits tests ou j’ai modifié la base dynaresume pour qu’elle gère l’association User -> Role.
Voici une copie d’écran d’une instance User récupérée via JPA/Eclipselink AVEC le LoadTimeWeaver configuré (lancé via l’agent Spring):
Cette copie d’écran montre que de nouveau champs _persistence* ont été ajouté à la classe User. Le LoadTimeWeaver permet de modifier le bytecode de la classe User à la volée (a son chargement) pour lui ajouter entre autre des listeners sur la classe User pour surveiller les appels des méthodes de la classe. Le champs privé role est null à la différence d’Hibernate qui est associé à un Proxy.
Voici une copie d’écran d’une instance User récupérée via JPA/Eclipselink SANS le LoadTimeWeaver:
Cette copie d’écran montre que si le LoadTimeWeaver n’est pas activé, le lazy loading ne peut pas s’effectuer, autrement dit l’annotation
@OneToOne(fetch=FetchType.LAZY)
est ignoré.
EclipseLink/Load Time Weaver
Pour régler notre problème de Load Time Weaver avec JPA/Eclipselink, 2 solutions s’offrent à nous :
- désactiver le Load Time Weaver. Dans notre cas cette option est acceptable car nous n’avons pas de lazy loading à effectuer.
- configurer le Load Time Weaver dans la déclaration du fichier XML Spring et lancer nos classes Java de test en spécifiant à la JVM un agent JAVA.
org.dynaresume.test.jpa_lcfb_withoutLTW
Dans cette section nous allons désactiver le LoadTimeWeaver de JPA/Eclipselink qui consiste simplement à configurer la propriété Eclipselink eclipselink.weaving à false.
Copiez collez le projet org.dynaresume.test.jpa_lcfb_1 et renommez le en org.dynaresume.test.jpa_lcfb_withoutLTW.
Ajoutez la propriété
<property name="eclipselink.weaving" value="false" />
dans les déclaration des properties des persistence-unit de EclipseLink, ce qui donne pour le persistent-unit de dynaresume-eclipselink-derby :
<persistence-unit name="dynaresume-eclipselink-derby" transaction-type="RESOURCE_LOCAL"> <provider> org.eclipse.persistence.jpa.PersistenceProvider </provider> <class>org.dynaresume.domain.User</class> <properties> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="javax.persistence.jdbc.user" value="" /> <property name="javax.persistence.jdbc.password" value="" /> <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.DerbyPlatform" /> <property name="show-sql" value="true" /> <property name="eclipselink.weaving" value="false" /> </properties> </persistence-unit>
Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.
org.dynaresume.test.jpa_lcfb_withLTW
Dans cette section nous allons configurer le LoadTimeWeaver de JPA/Eclipselink. Pour cela je vous conseille de lire la documentation officielle de Spring à la section LocalContainerEntityManagerFactoryBean. Selon l’environnement dans lequel notre programme est lancé (Tomcat, Glassfissh, …), Spring fournit une implémentation de LoadTimeWeaver qui se déclare sous forme de bean et qui est injecté au bean entityManagerFactory. Dans le cas ou Spring ne fournit pas de LoadTimeWeaver au contexte d’éxecution du programme, org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver peut être utilisé :
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="loadTimeWeaver"> <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/> </property> </bean>
lors du lancement du programme, l’agent Spring Java doit être renseigné dans les paramètres de la JVM :
-javaagent:spring-agent.jar
Depuis la version 2.5 de Spring, il est possible de détecter automatiquement l’implémentatation du LoadTimeWeaver à utiliser en fonction du contexte d’éxécution (Tomcat, Glassfish) à l’aide de la déclaration :
<context:load-time-weaver/>
C’est ce que nous allons utiliser dans cette section. Copiez collez le projet org.dynaresume.test.jpa_lcfb_1 et renommez le en org.dynaresume.test.jpa_lcfb_withLTW.
Ajoutez dans les 2 fichier XML Spring de JPA/Eclipslink applicationContext-eclipselink-derby.xml, et applicationContext-eclipselink-h2.xml, la déclaration :
<context:load-time-weaver/>
Un nouveau namespace context doit être définit :
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ... xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ... http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> ... </beans>
Voici le contenu du fichier applicationContext-eclipselink-derby.xml :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume-eclipselink-derby" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <context:load-time-weaver/> </beans>
Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et la console affiche l’erreur suivante :
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loadTimeWeaver': Initialization of bean failed; nested exception is java.lang.IllegalStateException: ClassLoader [sun.misc.Launcher$AppClassLoader] does NOT provide an 'addTransformer(ClassFileTransformer)' method. Specify a custom LoadTimeWeaver or start your Java virtual machine with Spring's agent: -javaagent:spring-agent.jar
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:480)
Cette erreur indique que le programme doit être lancé en spécifiant à la JVM le jar de l’agent Spring. Téléchargezle JAR spring-agent.jar de la distribution Spring que vous pouvez ensuite trouver dans le répertoire spring-framework-2.5.6-with-dependencies/spring-framework-2.5.6/dist/weaving.
Créez un répertoire lib dans le projet org.dynaresume.test.jpa_lcfb_withLTW et ajoutez la librairie spring-agent.jar. Accédez au Launch de la classe FindAllUserDynaresumeDerbyEclipseLink à l’aide du menu Run Configurations…. Sélectionnez le launch FindAllUserDynaresumeDerbyEclipseLink et cliquez sur l’onglet Arguments et ajoutez dans le champs VM Arguments l’agent Java Spring à utiliser :
-javaagent:lib/spring-agent.jar
Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.
REMARQUE : vous pouvez trouvez tous les launch de JPA/Eclipselink (comme expliqué ici) avec LoadTimeWeaver (se terminant par « – SpringAgent ») dans le répertoire launch du projet org.dynaresume.test.jpa_lcfb_withLTW.
org.dynaresume.test.jpa_lcfb_2
Dans les sections précédantes nous avons vu comment régler le problème de LoadTimeWeaver avec JPA/Eclipselink lorsque LocalContainerEntityManagerFactoryBean est utilisé. J’ai fait le choix de désactiver le Load Time Weaver dans cette section et les suivantes car nous n’avons pas de lazy-loading dans notre domaine User. De plus je n’ai pas testé le LoadTimeWeaver dans un contexte OSGi. Si vous êtes intéressés par ce sujet je vous conseille de lire le billet Load-Time Weaving for Spring-DM.
Dans cette section nous allons utiliser les possibilités de LocalContainerEntityManagerFactoryBean qui permet de déclarer dans des bean Spring les informations « provider » et « properties » du fichier JPA persistence.xml.
Copiez collez le projet org.dynaresume.test.jpa_lcfb_withoutLTW et renommez le en org.dynaresume.test.jpa_lcfb_2. Modifiez le fichier persistence.xml pour ne déclarer que les élements « class », comme suit :
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="dynaresume" transaction-type="RESOURCE_LOCAL"> <class>org.dynaresume.domain.User</class> </persistence-unit> </persistence>
Comme vous pouvez le constater un seul persistence-unit a été déclaré identifié par son nom dynaresume.
JPA/EclipseLink
Pour utiliser l’implémentation JPA/EclipseLink nous avons déclaré l’élément « provider » du fichier persistence.xml :
<provider> org.eclipse.persistence.jpa.PersistenceProvider </provider>
qui peut aussi se déclarer via un bean Spring jpaVendorAdapter :
<!-- JPA/EclipseLink Vendor with Derby dialect --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> </bean>
qui doit être injecté au bean l’entityManagerfactory :
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> </bean>
JPA/EclipseLink – Derby
Pour configurer JPA/EclipseLink avec Derby nous avons utilisé les élements « property » du fichier persistence.xml :
<properties> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="javax.persistence.jdbc.user" value="" /> <property name="javax.persistence.jdbc.password" value="" /> <property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.DerbyPlatform" /> <property name="show-sql" value="true" /> <property name="eclipselink.weaving" value="false" /> </properties>
Voici l’explication de ces élements « property » :
- les 4 première « property » concerne la configuration de la datasource Derby
- la 5ème property concerne la configuration platform (dialect) Derby
- la 6ème property concerne la configuration show SQL
- la 7ème property concerne la désactivation du LoadTimeWeaver qui est une propriété spécifique à JPA/EclipseLink.
Configuration datasource – Derby
Les 4 propriétés de configuration de la datasource Derby sont configurées via des « property » dans le fichier persistence.xml :
<property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="javax.persistence.jdbc.user" value="" /> <property name="javax.persistence.jdbc.password" value="" />
qui peuvent se traduire via un bean Spring dataSource :
<!-- Derby DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="username" value="" /> <property name="password" value="" /> </bean>
qui doit être injecté au bean entityManagerFactory :
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> </bean>
Configuration Platform Derby
La platform (dialect) Derby est configuré dans le fichier persitence.xml via la « property » :
<property name="eclipselink.target-database" value="org.eclipse.persistence.platform.database.DerbyPlatform" />
qui peut se configurer dans le bean Spring jpaVendorAdapter via la propriété databasePlatform :
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="databasePlatform" value="org.eclipse.persistence.platform.database.DerbyPlatform" /> </bean>
Une configuration plus générique de la platform Derby peut s’effectuer via la propriété database qui est un enm Database (ceci évite de devoir mettre la classe de la platform spécifique à l’implémentation JPA) :
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="database" value="DERBY" /> </bean>
Configuration show SQL
La configuration show SQL qui permet de tracer les requêtes SQL est paramétrée dans le fichier persitence.xml via la « property » :
<property name="show-sql" value="true" />
Ceci peut se traduire via le bean Spring jpaVendorAdapter :
<!-- JPA/EclipseLink Vendor with Derby dialect --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="database" value="DERBY" /> <property name="showSql" value="true" /> </bean>
Configuration propriété eclipselink.weaving
La désactivation du LoadTimeWeave qui est une propriété spécifique à JPA/EclipseLink s’effectue dans le fichier persitence.xml via la « property » :
<property name="eclipselink.weaving" value="false" />
qui peut se traduire via un bean Spring jpaProperties (qui est un java.util.Properties) :
<bean id="jpaProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="eclipselink.weaving">false</prop> </props> </property> </bean>
qui doit être injecté au bean entityManagerFactory :
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaProperties" ref="jpaProperties" /> </bean>
Modifiez le fichier applicationContext-eclipselink-derby.xml comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- Derby DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="username" value="" /> <property name="password" value="" /> </bean> <!-- JPA/EclipseLink properties --> <bean id="jpaProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="eclipselink.weaving">false</prop> </props> </property> </bean> <!-- JPA/EclipseLink Vendor with Derby dialect --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="database" value="DERBY" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaProperties" ref="jpaProperties" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.
JPA/EclipseLink – H2
Nous pouvons effectuer la même chose avec JPA/EclipseLink et H2. Modifiez le fichier XML Spring applicationContext-eclipselink-h2.xml comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- H2 DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:C:/db/h2/dynaresume" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean> <!-- JPA/EclipseLink properties --> <bean id="jpaProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="eclipselink.weaving">false</prop> </props> </property> </bean> <!-- JPA/EclipseLink Vendor with H2 dialect --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="database" value="H2" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaProperties" ref="jpaProperties" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Relancez la classe FindAllUserDynaresumeH2EclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.
JPA/Hibernate – Derby
Nous pouvons effectuer la même chose avec JPA/Hibernate et Derby en utilisant org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter. Modifiez le fichier XML Spring applicationContext-hibernate-derby.xml comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- Derby DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="username" value="" /> <property name="password" value="" /> </bean> <!-- JPA/Hibernate properties --> <bean id="jpaProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> </bean> <!-- JPA/Hibernate Vendor with Derby dialect --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="DERBY" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaProperties" ref="jpaProperties" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Relancez la classe FindAllUserDynaresumeDerbyHibernate et vous pourrez vérifier que la liste des User s’affiche dans la console.
JPA/Hibernate H2
Nous pouvons effectuer la même chose avec JPA/Hibernate et H2. Modifiez le fichier XML Spring applicationContext-hibernate-h2.xml comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <!-- H2 DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:C:/db/h2/dynaresume" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean> <!-- JPA/Hibernate properties --> <bean id="jpaProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> </bean> <!-- JPA/Hibernate Vendor with H2 dialect --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" value="H2" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaProperties" ref="jpaProperties" /> </bean> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Relancez la classe FindAllUserDynaresumeH2Hibernate et vous pourrez vérifier que la liste des User s’affiche dans la console.
org.dynaresume.test.jpa_lcfb_3
A ce stade nous avons 4 fichiers XML Spring qui définissent divers bean (DAO, Datasource, JPA….) qui sont redondants (ex : le bean userService est déclaré dans les 4 fichiers XML Spring). Dans cette section nous allons découper nos déclarations des beans dans plusieurs fichiers XML Spring. Ce découpage nous sera util dans le prochain billet pour découper nos bundles OSGi JPA/DAO.
Voici comment nous allons répartir nos beans dans différents fichiers XML Spring applicationContext :
- applicationContext-services.xml : déclare le bean service userService.
- applicationContext-dao-jpa.xml : déclare les beans entityManagerFactory et userDAO (implémentation DAO en JPA). La déclaration du bean entityManagerFactory attend qu’on lui injecte les beans datasource, jpaVendorAdapter et jpaProperties.
- applicationContext-dao-jpa-*.xml pour chaque implémentation JPA :
- applicationContext-dao-jpa-eclipselink.xml : qui déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/EclipseLink. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).
- applicationContext-dao-jpa-hibernate.xml qui déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/Hibernate. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).
- applicationContext-datasource-*.xml pour chaque base de données :
- applicationContext-datasource-derby.xml qui déclare un bean datasource avec la configuration de la base de donnée Derby.
- applicationContext-datasource-h2.xml qui déclare un bean datasource avec la configuration de la base de donnée H2.
- applicationContext-dao-jpa-database-*.xml pour chaque base de donnée :
- applicationContext-dao-jpa-database-derby.xml qui déclare un bean database qui retourne la String « DERBY » qui est le dialect Derby à utiliser en JPA.
- applicationContext-dao-jpa-database-h2.xml qui déclare un bean database qui retourne la String « H2 » qui est le dialect H2 à utiliser en JPA.
Copiez collez le projet org.dynaresume.test.jpa_lcfb_2 et renommez le en org.dynaresume.test.jpa_lcfb_3.
Services – applicationContext-services.xml
Créez le fichier applicationContext-services.xml dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="userService" class="org.dynaresume.services.impl.UserServiceImpl"> <property name="userDAO" ref="userDAO" /> </bean> </beans>
Ce fichier XML Spring déclare le bean service userService qui attend une DAO userDAO.
DAO/JPA – applicationContext-dao-jpa.xml
Créez le fichier applicationContext-dao-jpa.xml dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="userDAO" class="org.dynaresume.dao.jpa.UserDAOJpa" /> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="persistenceUnitName" value="dynaresume" /> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="jpaVendorAdapter" /> <property name="jpaProperties" ref="jpaProperties" /> </bean> <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> <tx:annotation-driven transaction-manager="txManager" /> <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>
Ce fichier XML Spring déclare les beans entityManagerFactory et userDAO (implémentation DAO en JPA). La déclaration du bean entityManagerFactory attend qu’on lui injecte les beans datasource, jpaVendorAdapter et jpaProperties.
DAO-JPA/EclipseLink – applicationContext-dao-jpa-eclipselink.xml
Créez le fichier applicationContext-dao-jpa-eclipselink.xml dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- JPA/EclipseLink properties --> <bean id="jpaProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="eclipselink.weaving">false</prop> </props> </property> </bean> <!-- JPA/EclipseLink Vendor --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter"> <property name="database" ref="database" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> </beans>
Ce fichier XML Spring déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/EclipseLink. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).
DAO-JPA/EclipseLink – applicationContext-dao-jpa-hibernate.xml
Créez le fichier applicationContext-dao-jpa-hibernate.xml dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- JPA/Hibernate properties --> <bean id="jpaProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean"> </bean> <!-- JPA/Hibernate Vendor --> <bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="database" ref="database" /> <property name="generateDdl" value="false" /> <property name="showSql" value="true" /> </bean> </beans>
Ce fichier XML Spring déclare les beans jpaVendorAdapter et jpaProperties spécifiques à l’implémentation JPA/Hibernate. La déclaration du bean jpaVendorAdapter attend qu’on lui injecte le bean database qui concerne le dialect à utiliser (DERBY ou H2).
applicationContext-datasource-derby.xml
Créez le fichier applicationContext-datasource-derby.xml dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- Derby DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" /> <property name="url" value="jdbc:derby:C:/db/derby/dynaresume" /> <property name="username" value="" /> <property name="password" value="" /> </bean> </beans>
Ce fichier XML Spring déclare un bean datasource avec la configuration de la base de donnée Derby.
applicationContext-datasource-h2.xml
Créez le fichier applicationContext-datasource-h2.xml dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- H2 DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:C:/db/h2/dynaresume" /> <property name="username" value="sa" /> <property name="password" value="" /> </bean> </beans>
Ce fichier XML Spring déclare un bean datasource avec la configuration de la base de donnée H2.
applicationContext-dao-jpa-database-derby.xml
Créez le fichier applicationContext-dao-jpa-database-derby.xm dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" > <bean id="database" class="java.lang.String"> <constructor-arg> <value>DERBY</value> </constructor-arg> </bean> </beans>
Ce fichier XML Spring déclare un bean database qui retourne la String « DERBY » qui est le dialect Derby à utiliser en JPA.
applicationContext-dao-jpa-database-h2.xml
Créez le fichier applicationContext-dao-jpa-database-h2.xm dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd" > <bean id="database" class="java.lang.String"> <constructor-arg> <value>H2</value> </constructor-arg> </bean> </beans>
Ce fichier XML Spring déclare un bean database qui retourne la String « H2 » qui est le dialect H2 à utiliser en JPA.
Test JPA
A ce stade nous devons charger plusieurs fichiers XML Spring. Ce code n’est pas spécialement intéressant et vous pourrez le retrouvez dans le zip. Je vais montrer le code de la classe de test JPA avec JPA/EclipseLink et Deby. Pour cela modifiez la classe org.dynaresume.test.jpa.eclipselink.derby.FindAllUserDynaresumeDerbyEclipseLink comme suit :
package org.dynaresume.test.jpa.eclipselink.derby; import java.util.Collection; import org.dynaresume.domain.User; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class FindAllUserDynaresumeDerbyEclipseLink { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( new String[] { "org/dynaresume/applicationContext-services.xml", "org/dynaresume/applicationContext-dao-jpa.xml", "org/dynaresume/applicationContext-datasource-derby.xml", "org/dynaresume/applicationContext-dao-jpa-database-derby.xml", "org/dynaresume/applicationContext-dao-jpa-eclipselink.xml" }); UserService userService = (UserService) applicationContext .getBean("userService"); Collection<User> users = userService.findAllUsers(); for (User user : users) { System.out.println("User [id=" + user.getId() + " login=" + user.getLogin() + ", password=" + user.getPassword() + "]"); } } }
Relancez la classe FindAllUserDynaresumeDerbyEclipseLink et vous pourrez vérifier que la liste des User s’affiche dans la console.
org.dynaresume.test.jpa_lcfb_4
A ce stade, les valeurs de la configuration de la base de données se retrouvent en dur dans la déclaration du bean datasource. Il est beaucoup plus propre de mettre ces valeurs dans un fichier de prorpiérés.
Copiez collez le projet org.dynaresume.test.jpa_lcfb_3 et renommez le en org.dynaresume.test.jpa_lcfb_4.
Derby
derby.properties
Créez le fichier derby.properties dans le package org.dynaresume comme suit :
database.driverClassName=org.apache.derby.jdbc.EmbeddedDriver database.url=jdbc:derby:C:/db/derby/dynaresume database.username= database.password=
applicationContext-datasource.xml
Créez le fichier générique de datasource applicationContext-datasource.xml dans le package org.dynaresume :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${database.driverClassName}" /> <property name="url" value="${database.url}" /> <property name="username" value="${database.username}" /> <property name="password" value="${database.password}" /> </bean> </beans>
applicationContext-datasource-derby.xml
Jusqu’à maintenant le fichier applicationContext-datasource-derby.xml déclarait le bean datasource. Maintenant ce fichier XML Spring doit s’occuper uniquement de charger le fichier de propriétés derby.properties. Pour cela, modifiez le fichier applicationContext-datasource-derby.xml comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>classpath:org/dynaresume/derby.properties</value> </property> </bean> </beans>
H2
h2.properties
Créez le fichier h2.properties dans le package org.dynaresume comme suit :
database.driverClassName=org.h2.Driver database.url=jdbc:h2:C:/db/h2/dynaresume database.username=sa database.password=
applicationContext-datasource-h2.xml
Jusqu’à maintenant le fichier applicationContext-datasource-h2.xml déclarait le bean datasource. Maintenant ce fichier XML Spring doit s’occuper uniquement de charger le fichier de propriétés h2.properties. Pour cela, modifiez le fichier applicationContext-datasource-h2.xml comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>classpath:org/dynaresume/h2.properties</value> </property> </bean> </beans>
Test JPA
Ajoutez dans toutes les classes de test JPA, le chargement du fichier XML Spring « org/dynaresume/applicationContext-datasource.xml », Modifiez toutes les classes Java de test JPA. Voici la classe org.dynaresume.test.jpa.eclipselink.derby.FindAllUserDynaresumeDerbyEclipseLink modifié :
package org.dynaresume.test.jpa.eclipselink.derby; import java.util.Collection; import org.dynaresume.domain.User; import org.dynaresume.services.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class FindAllUserDynaresumeDerbyEclipseLink { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext( new String[] { "org/dynaresume/applicationContext-services.xml", "org/dynaresume/applicationContext-dao-jpa.xml", "org/dynaresume/applicationContext-datasource.xml", "org/dynaresume/applicationContext-datasource-derby.xml", "org/dynaresume/applicationContext-dao-jpa-database-derby.xml", "org/dynaresume/applicationContext-dao-jpa-eclipselink.xml" }); UserService userService = (UserService) applicationContext .getBean("userService"); Collection<User> users = userService.findAllUsers(); for (User user : users) { System.out.println("User [id=" + user.getId() + " login=" + user.getLogin() + ", password=" + user.getPassword() + "]"); } } }
Namespace p & applicationContext-datasource.xml
Le fichier applicationContext-datasource.xml qui déclare le bean datasource utilise l’élement property pour configurer la datasource.
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${database.driverClassName}" /> <property name="url" value="${database.url}" /> <property name="username" value="${database.username}" /> <property name="password" value="${database.password}" /> </bean> </beans>
Cette déclaration est assez verbeuse et il est possible d’utiliser le namespace p concaténé avec le nom de la propriété. Pour cela modifiez le fichier fichier applicationContext-datasource.xml comme suit :
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- DataSource --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${database.driverClassName}" p:url="${database.url}" p:username="${database.username}" p:password="${database.password}"> </bean> </beans>
Conclusion
Nous avons vu que l’utilisation de LocalContainerEntityManagerFactoryBean permet de déclarer les informations « provider » et « properties » du fichier JPA persistence.xml via des bean Spring. Nous avons découpé dans plusieurs fichiers XML Spring la déclaration des bean Spring par « module ». Ce découpage nous aidera dans le prochain billet à découper nos bundles qui s’occuperont de la couche DAO.
Vous pouvez lire le billet suivant [step19].