Archive for December 28th, 2010

Customizing GORM with a Configuration Subclass

Tuesday, December 28th, 2010

GORM 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:

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 License.