Customizing GORM with a Configuration Subclass
Tuesday, December 28th, 2010GORM mappings let you configure pretty much anything you need in your Grails applications, but occasionally there are more obscure tweaks that aren’t directly supported, and in this case a custom Configuration class is often the solution.
By default Grails uses an instance of GrailsAnnotationConfiguration and the standard approach is to subclass that to retain its functionality and override the secondPassCompile()
method.
As an example, let’s look at what is required to specify the foreign key name between two related domain classes. This is inspired by this mailing list question but is also a personal pet peeve since I always name foreign keys in traditional Hibernate apps (using annotations or hbm.xml files). FK_USER_COUNTRY is a lot more useful than FK183C3385A9B72.
One restriction is that you need to code the class in Java – a Groovy class won’t compile due to method visibility issues.
Create this class (with an appropriate name and package for your application) in src/java:
package com.yourcompany.yourapp; import java.util.Collection; import java.util.Iterator; import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration; import org.hibernate.MappingException; import org.hibernate.mapping.ForeignKey; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.RootClass; public class MyConfiguration extends GrailsAnnotationConfiguration { private static final long serialVersionUID = 1; private boolean _alreadyProcessed; @SuppressWarnings({"unchecked", "rawtypes"}) @Override protected void secondPassCompile() throws MappingException { super.secondPassCompile(); if (_alreadyProcessed) { return; } for (PersistentClass pc : (Collection<PersistentClass>)classes.values()) { if (pc instanceof RootClass) { RootClass root = (RootClass)pc; if ("com.yourcompany.yourapp.User".equals(root.getClassName())) { for (Iterator iter = root.getTable().getForeignKeyIterator(); iter.hasNext();) { ForeignKey fk = (ForeignKey)iter.next(); fk.setName("FK_USER_COUNTRY"); } } } } _alreadyProcessed = true; } }
This is a very simplistic example and everything is hard-coded. A real example would check that the foreign key exists, that it’s the correct one, etc., or might be more sophisticated and automatically rename all foreign keys using the FK_ prefix and using the table names of the two related tables.
This won’t be automatically used, but you just need to set the configClass
property in grails-app/conf/DataSource.groovy
:
dataSource { pooled = true driverClassName = '...' username = '...' password = '...' configClass = 'com.yourcompany.yourapp.MyConfiguration' }
For other examples of using this approach, see these posts in the Nabble archive:
- Renaming columns of a composite foreign key: http://grails.1312388.n4.nabble.com/Composite-foreign-key-td3046351.html#a3046436
- Specifying the ‘connection.provider_class’ property: http://grails.1312388.n4.nabble.com/Oracle-VPD-Virtual-Private-Database-td1387150.html#a1387152
- Overriding the EntityPersister class: http://grails.1312388.n4.nabble.com/GROM-mapping-and-EntityPersister-td2134133.html#a2134326
- Using field access: http://grails.1312388.n4.nabble.com/GORM-setting-access-quot-field-quot-td1592837.html#a1594428