Hibernate integration
Mapping Domain Classes with Hibernate
If GORM (Grails Object Relational Mapping) is not flexible enough for your liking you can alternatively map your domain class using Hibernate. To do this create a "hibernate.cfg.xml" file in the "%PROJECT_HOME%\grails-app\conf\hibernate" directory of your project and the corresponding Hbm mapping xml file for your domain class. For more info on how to do this read the documentation on mapping on the Hibernate Website
This will allow you to map Grails domain classes onto a wider range of legacy systems and be more flexible in the creation of your databa se schema.
Using Existing Hibernate Data Models
Grails also allows you to write your domain model in Java or re-use an existing domain model that has been mapped using Hibernate. All you have to do is place the necessary "hibernate.cfg.xml" file and corresponding mappings files in the "%PROJECT_HOME%\grails-app\conf\hibernate" directory.
You will still be able to call all of the dynamic persistent and query methods allowed in GORM!
Mapping with Hibernate Annotations
Grails also supports creating domain classes mapped with Hibernate's Java 5.0 Annotations support. To do so you need to tell Grails that you are using an annotation configuration by setting the "configClass" in your data source project as follows:
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration class DevelopmentDataSource { def configClass = GrailsAnnotationConfiguration.class ... // remaining properties } as of 1.0 RC1 (AFAIK, could be earlier) note that you do not add def in front environments { development { dataSource { configClass = GrailsAnnotationConfiguration.class dbCreate = "update" // one of 'create', 'create-drop','update' //url = "jdbc:hsqldb:mem:devDB" url = "jdbc:postgresql://localhost/vprocedure" } } ....
That's it for the configuration! Oh and make sure you have Java 5.0 installed as this is required to use annotations. Now to create an annotated class we simply create a new Java class in grails-app/domain and use the annotations defined as part of the EJB 3.0 spec (for more info on this see the Hibernate Annotations Docs:
package com.books; @Entity public class Book { private Long id; private String title; private String description; private Date date; @Id @GeneratedValue public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
Once thats done we need to register the class with the Hibernate sessionFactory, to do so we add entries to the "%PROJECT_HOME%/grails-app/conf/hibernate/hibernate.cfg.xml" file as follows:
<!DOCTYPE hibernate-configuration SYSTEM "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <mapping package="com.books" /> <mapping class="com.books.Book" /> </session-factory> </hibernate-configuration>
And that's it! When Grails loads it will register the necessary dynamic methods with the class! To see what else you can do with a Hibernate domain class see the section on Scaffolding
Note when you generate views or controllers you need to specify the entire package name, i.e. com.books.Book, as there are currently (v 0.3) mistakes in the generated code. Specifically, the static methods need to be fully qualified (add the package name).
Using Grails Dynamic Methods in a Java-Hibernate Application
You can use Grails dynamic methods (for example, findBy*()) and properties for domain classes in an application written in Java that uses Hibernate for object-relational mapping (ORM). Simply embed into your application the Groovy scripts that harness Grails dynamic functionality, which results in short readable scripts that query for data (DML operations currently do not work).
Add the following JAR files to your build path:
- grails
- groovy-all
- spring
- commons-lang
- commons-collections
- servletapi
- ognl
You can find these JAR files within your Grails installation directory--more specifically, the <GRAILS_HOME>/lib and <GRAILS_HOME>/dist directories.
In your Java code:
import groovy.lang.Binding; import groovy.util.GroovyScriptEngine; import org.hibernate.SessionFactory; import org.codehaus.groovy.grails.commons.DefaultGrailsApplication; import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
To generate the dynamic methods do:
DefaultGrailsApplication defaultApplication; SessionFactory sessionFactory; defaultApplication = new DefaultGrailsApplication (new Class[] {}, null); sessionFactory = HibernateUtil.getSessionFactory (); GrailsHibernateUtil.configureDynamicMethods (sessionFactory, defaultApplication);
The HibernateUtil class manages a SessionFactory so that I have to create it only once. The source code for this class is taken from the Hibernate documentation.
import org.hibernate.*; import org.hibernate.cfg.*; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { // Create the SessionFactory from hibernate.cfg.xml sessionFactory = new Configuration ().configure ().buildSessionFactory (); } catch (Throwable ex) { // Make sure you log the exception, as it might be swallowed. System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError (ex); } } public static SessionFactory getSessionFactory () { return sessionFactory; } }
Now you are ready to execute Groovy scripts that use the dynamic methods:
String[] scriptLocations; GroovyScriptEngine engine; Binding binding; scriptLocations = new String[] { "groovy" }; engine = new GroovyScriptEngine (scriptLocations); binding = new Binding (); // Create a variable named "input" with a value "hello" in the script // binding.setVariable ("input", "hello"); try { Object obj = engine.run ("Foobar.groovy", binding); // ...
Foobar.groovy may look like this:
import foil.MillRoll return MillRoll.list()
which would give you a List with all persisted "foil.MillRoll" Objects.
Using custom UserType
You can define custom user hibernate types to map database fields in non-standard ways.
For example, here's a custom UserType that maps a varchar2(1) field which allows values of '0' and '1' to a boolean instead of a String.
For example, you can create this class as ./src/groovy/persistence/OneZeroUserType.groovy:
package persistence; import org.hibernate.*; import org.hibernate.usertype.*; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.*; import java.io.Serializable; public class OneZeroUserType implements UserType { def SQL_TYPES = [Hibernate.STRING.sqlType()]; public int[] sqlTypes() { return SQL_TYPES; } private Class targetClass; public void setParameterValues(Properties parameters) { String targetClassName = parameters.getProperty("targetClass"); try { targetClass = Class.forName(targetClassName); } catch (ClassNotFoundException e) { throw new HibernateException("Class " + targetClassName + " not found ", e); } } public Class returnedClass() { return targetClass; } public boolean isMutable() { return false; } public Object deepCopy(Object value) { return value; } public Serializable disassemble(Object value) { return (Serializable) value; } public Object assemble(Serializable cached, Object owner) { return cached; } public Object replace(Object original, Object target, Object owner) { return original; } public boolean equals(Object x, Object y) { if (x == y) return true; if (x == null || y == null) return false; return x.equals(y); } public int hashCode(Object x) { return x.hashCode(); } public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws SQLException { String value = resultSet.getString(names[0]); if ("1".equals(value)) return true; else return false; } public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException { if (value == null) { statement.setNull(index, Hibernate.STRING.sqlType()); } else { if((Boolean)value) { statement.setString(index, "1"); } else { statement.setString(index, "0"); } } } }
You can then use the new type in your .hbm.xml hibernate mapping [file:
]
<property name="FOrdLun" type="persistence.OneZeroUserType"> <column name="F_ORD_LUN" length="1" /> </property>
Other Resources
- Tutorial - Many-to-Many Mapping with Hibernate XML
- Tutorial - Hosting Grails to Your Legacy DB - Step-by-step guide written by Jason Rudolph on how to get Grails working with a legacy MySQL db using Hibernate XML
- Tutorial - Grails+EJB3 - Another excellent article by Jason Rudolph on how to use Grails with EJB entity beans

