Customizing GORM with a Configuration Subclass

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:

10 Responses to “Customizing GORM with a Configuration Subclass”

  1. […] supported, and in this case a custom Configuration class is often the solution. By default… [full post] Burt An Army of Solipsists gormgrailshibernatejava 0 0 0 0 […]

  2. Kim A. Betti says:

    This is actually _very_ useful for many Hibernate related plugins – and a great source of plugin incompatibility issues as you can only have one Hibernate config class.

    I created a way for multiple plugins to participate in post-processing of the Hibernate configuration when I worked on a plugin[1] in the multi-tenant family.

    Perhaps it would be a good idea to let the Hibernate plugin exposed a hook for this?

    1. https://github.com/multi-tenant/grails-hibernate-hijacker

    • Burt says:

      Kim – I’m working on something more straightforward that should allow a lot more flexibility with the Hibernate configuration. This is for 1.4 but it should be straightforward to backport for current apps. I’ve discussed this briefly with Scott Ryan and I’ll forward the implementation to both of you once it’s ready.

  3. John Stoneham says:

    I don’t believe it’s true that you need to subclass in Java. We’ve used this technique in Groovy before. I do remember having to do something silly like overriding a method and specifically declaring it public and just calling the superclass, though.

    • Burt says:

      Right, overriding to increase the visibility of a method sounds familiar – I’ll check it out and update the post.

  4. […] Personnaliser GORM avec des sub-classes de Configuration […]

  5. […] turns out we can do this with a few lines of code. The basic idea is described in Customizing GORM with a Configuration Subclass using some Java code and a hardcoded foreign […]

  6. Mathias says:

    Hi Burt!

    Is it still working this way in version 2.3.3? I find it very strange that it has to be so “hard” to do something as simple as renaming a key.

    Thanks!

    Mathias

  7. Clark Wright says:

    Hi Burt,

    Any idea/suggestions on how to get this to work with the database-migrate/liquibase plugin?

    The foreign key rename fires correctly, but the dbm-* utilities still spit out:

    addForeignKeyConstraint(baseColumnNames: “current_result_id”, baseTableName: “assignment”, constraintName: “FK3D2B86CDB2BD8600”, ….

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