Customizing GORM with a Configuration Subclass

Posted by: Burt Beckwith on 2010-12-28 14:19:00.0

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:

Share


be the first to rate this blog

About Burt Beckwith

Burt Beckwith

Burt Beckwith is a Java and Groovy developer with over ten years of experience in a variety of industries including biotech, travel, e-learning, social networking, and financial services. For the past three years he's been working with Grails and Groovy full-time. Along the way he's created over fifteen Grails plugins and made significant contributions to several others. He was the technical editor for Grails in Action.

More About Burt »

NFJS, the Magazine

2010-12-01 00:00:00.0 Issue Now Available
  • Functional Programming in Java
    by Ted Neward
  • On mini-languages and Clojure
    by Raju Gandhi
  • Testing in Scala
    by Daniel Hinojosa
  • An Introduction to Node.JS
    by James Carr
Learn More »