Last updated by kgeis
3 months ago
JPA Plugin Requirements Spec
We need to properly support JPA in order to use GORM over other persistence technologies (including AppEngine).To do this we need to create a JPA plugin and a plugin for each provider. The main plugin isgorm-jpa . In order to use GORM JPA you would have have installed or configured a JPA provider. We should provide some out of the box providers so you can do:grails install-plugin hibernate-jpa grails install-plugin gorm-jpa
Configured Beans
The JPA provider plugin will need to take responsibility for configuring the EntityManagerFactory, ReflectiveLoadTimeWeaver, JpaTransactionManager beans namedentityManagerFactory , reflectiveLoadTimeWeaver and transactionManager respectively. The JPA provider plugins will need to depend on the DataSource plugin in order to obtain an appropriate dataSource bean.The JPA provider plugin should also setup the necessary JpaInterceptor to avoid lazy load problems:if (manager?.hasGrailsPlugin("controllers")) { openSessionInViewInterceptor(JpaInterceptor) { // etc. } if(getSpringConfig().containsBean("grailsUrlHandlerMapping")){ grailsUrlHandlerMapping.interceptors << openSessionInViewInterceptor } }
Generation of persistence.xml
We need to generate persistence.xml using MarkupBuilder to avoid the unnecessary boilerplate this provides and also integrate with Grails' configuration model.For example a typical persistence.xml configuration file with Hibernate looks like:<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> <persistence-unit name="manager1" transaction-type="JTA"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/DefaultDS</jta-data-source> <mapping-file>ormap.xml</mapping-file> <jar-file>MyApp.jar</jar-file> <class>org.acme.Employee</class> <class>org.acme.Person</class> <class>org.acme.Address</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/> <property name="hibernate.hbm2ddl.auto" value="create-drop"/> </properties> </persistence-unit> </persistence>
hibernate {
cache.use_second_level_cache=true
cache.use_query_cache=true
cache.provider_class='com.opensymphony.oscache.hibernate.OSCacheProvider'
}generateWebXml event:eventGenerateWebXmlStart = {
new File("${projectWorkDir}/resources/persistence.xml").withWriter { w ->
new MarkupBuilder(w).persistence(xmlns:"http://java.sun.com/xml/ns/persistence") {
// etc.
}
}
}_Events.groovy that will package the persistence.xml into the default location:eventCreateWarStart = { warLocation, stagingDir ->
ant.copy(file:"${projectWorkDir}/resources/persistence.xml", todir:"${stagingDir}/WEB-INF/classes/META-INF"
}Entity Scanning
The GORM-JPA plugin will need to setup a ComponentScanBeanDefinitionParser bean using the <context:component-scan/> tag to scan for all the classes marked with thejava.persistence.Entity annotation.With a list of persistent entities in hand these will all need to be added to the GrailsApplication object. In order to correctly support data binding and validation within GORM the JPA plugin will need to create an instance of the GrailsDomainClass and add it to each GrailsApplication object. The implementation, let's say JpaGrailsDomainClass will need to know how persistent associations relate, how to evaluate the identity etc.Dynamic Methods
Once this is done the GormJpaGrailsPlugin will need to implement thedoWithDynamicMethods block in order to add the necessary persistent methods. For example:def doWithDynamicMethods = { appCtx ->
def jpaTemplate = new JpaTemplate(appCtx.getBean("entityManagerFactory"))
for(domainClass in application.domainClasses) {
def theClass = domainClass.getClazz()
domainClass.metaClass.get { Serializable id ->
jpaTemplate.find(theClass, id)
}
… // etc.
}
}