Merge branch '3.x'

Conflicts:
	grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
	grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
diff --git a/boot-plugins/gorm-hibernate4-spring-boot/build.gradle b/boot-plugins/gorm-hibernate4-spring-boot/build.gradle
index 975b25f..43fb987 100644
--- a/boot-plugins/gorm-hibernate4-spring-boot/build.gradle
+++ b/boot-plugins/gorm-hibernate4-spring-boot/build.gradle
@@ -1,7 +1,7 @@
 apply from:'../gradle/maven-central-build.gradle'
 
 group = 'org.grails'
-version = "1.1.0.RELEASE"
+version = "4.0.0.BUILD-SNAPSHOT"
 sourceCompatibility = 1.6
 targetCompatibility = 1.6
 
diff --git a/boot-plugins/gorm-mongodb-spring-boot/build.gradle b/boot-plugins/gorm-mongodb-spring-boot/build.gradle
index 506b398..1104605 100644
--- a/boot-plugins/gorm-mongodb-spring-boot/build.gradle
+++ b/boot-plugins/gorm-mongodb-spring-boot/build.gradle
@@ -1,7 +1,7 @@
 apply from:'../gradle/maven-central-build.gradle'
 
 group = 'org.grails'
-version = "1.1.0.RELEASE"
+version = "4.0.0.BUILD-SNAPSHOT"
 sourceCompatibility = 1.6
 targetCompatibility = 1.6
 
diff --git a/build.gradle b/build.gradle
index c2ba14e..35d867f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,13 +1,13 @@
 project.ext {
-    springVersion = "3.2.9.RELEASE"
-    grailsVersion = "2.3.11"
+    springVersion = "4.1.2.RELEASE"
+    grailsVersion = "3.0.0.BUILD-SNAPSHOT"
     slf4jVersion = "1.7.5"
     junitVersion = "4.11"
-    groovyVersion = System.getProperty('groovyVersion') ?: '2.1.9'
+    groovyVersion = System.getProperty('groovyVersion') ?: '2.3.6'
     isTravisBuild = System.getenv().get("TRAVIS") == 'true'
 
-    projectVersion = "3.1.4"
-       // releaseType = "RELEASE"
+    projectVersion = "4.0.0"
+//        releaseType = "RELEASE"
     releaseType = "BUILD-SNAPSHOT"
     isCiBuild = project.hasProperty("isCiBuild")
     isBuildSnapshot = releaseType == "BUILD-SNAPSHOT"
@@ -67,13 +67,9 @@
     }
 }
 
-task wrapper(type: Wrapper) {
-    gradleVersion = '1.9'
-}
-
 subprojects {
     if(project.name.endsWith("spring-boot")) return
-    afterEvaluate { project ->
+   afterEvaluate { project ->
         if (isGroovyProject(project)) {
             def hasSnapshotVersion = project.version.endsWith("-SNAPSHOT")
             if(isBuildSnapshot != hasSnapshotVersion) {
@@ -86,6 +82,7 @@
         project.ext.artifactoryPublishPassword = System.getenv("ARTIFACTORY_PASSWORD")
     }
 
+
     version = "${projectVersion}.${releaseType}"
     group = "org.grails"
 
@@ -127,16 +124,26 @@
 
     dependencies {
         if (isStandardGroovyMavenProject) {
-            groovy group: 'org.codehaus.groovy', name: 'groovy-all', version: groovyVersion
+            groovy group: 'org.codehaus.groovy', name: 'groovy', version: groovyVersion
+
+            testCompile group: 'org.codehaus.groovy', name: 'groovy-test', version: groovyVersion
 
             testCompile "junit:junit:$junitVersion"
             testCompile (spockDependency) {
+                exclude group:'junit',module:'junit-dep'
+                exclude group:'org.codehaus.groovy',module:'groovy-all'
+                exclude group:'org.hamcrest',module:'hamcrest-core'
                 transitive = false
             }
         }
 
         if (project.name == "grails-datastore-gorm-tck") {
-            compile spockDependency
+            compile spockDependency, {
+                exclude group:'junit',module:'junit-dep'
+                exclude group:'org.codehaus.groovy',module:'groovy-all'
+                exclude group:'org.hamcrest',module:'hamcrest-core'
+                transitive = false
+            }
         }
     }
 
@@ -299,22 +306,22 @@
 
             repositories.mavenDeployer {
                 if(!isBuildSnapshot) {
-                    beforeDeployment { MavenDeployment deployment ->
-                        signing.signPom(deployment)
+                beforeDeployment { MavenDeployment deployment ->
+                    signing.signPom(deployment)
                     }
                 }
 
                 if(project.hasProperty("sonatypeUsername")) {
-                    repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
-                        authentication(userName: project.hasProperty("sonatypeUsername") ? project.sonatypeUsername : null,
-                                password: project.hasProperty("sonatypePassword") ?  project.sonatypePassword : null)
+                repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
+                    authentication(userName: project.hasProperty("sonatypeUsername") ? project.sonatypeUsername : null,
+                            password: project.hasProperty("sonatypePassword") ?  project.sonatypePassword : null)
                     }
                 }
                 if(project.hasProperty("artifactoryPublishUsername")) {
                     snapshotRepository(url: "https://repo.grails.org/grails/libs-snapshots-local") {
-                        authentication(userName: project.hasProperty("artifactoryPublishUsername") ? project.artifactoryPublishUsername : null,
-                                password: project.hasProperty("artifactoryPublishPassword") ?  project.artifactoryPublishPassword : null)
-                    }
+                    authentication(userName: project.hasProperty("artifactoryPublishUsername") ? project.artifactoryPublishUsername : null,
+                            password: project.hasProperty("artifactoryPublishPassword") ?  project.artifactoryPublishPassword : null)
+                }
                 }
 
                 pom.project {
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index d5c591c..0087cd3 100644
--- a/gradle/wrapper/gradle-wrapper.jar
+++ b/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 0a96f7c..eb9ac53 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Mon Apr 28 16:51:01 CEST 2014
+#Mon Dec 01 08:51:21 CST 2014
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-1.12-bin.zip
diff --git a/grails-datastore-appengine/src/test/groovy/grails/persistence/Entity.java b/grails-datastore-appengine/src/test/groovy/grails/persistence/Entity.java
deleted file mode 100644
index 725fbaf..0000000
--- a/grails-datastore-appengine/src/test/groovy/grails/persistence/Entity.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package grails.persistence;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * @author Graeme Rocher
- * @since 1.1
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Entity {
-}
diff --git a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Entity.java b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Entity.java
index ce70c16..0810511 100644
--- a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Entity.java
+++ b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/Entity.java
@@ -24,6 +24,7 @@
 
     private boolean stateless = false;
     private boolean autoTimestamp = true;
+    private Object defaultSort = null;
 
     /**
      * @return Whether automatic time stamps should be applied to 'lastUpdate' and 'dateCreated' properties
@@ -46,4 +47,15 @@
     public void setStateless(boolean stateless) {
         this.stateless = stateless;
     }
+
+    /**
+     * @return The default sort order definition, could be a string or a map
+     */
+    public Object getSort() {
+        return defaultSort;
+    }
+
+    public void setSort(Object defaultSort) {
+        this.defaultSort = defaultSort;
+    }
 }
diff --git a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/utils/ConfigUtils.java b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/utils/ConfigUtils.groovy
similarity index 67%
rename from grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/utils/ConfigUtils.java
rename to grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/utils/ConfigUtils.groovy
index 20d6bee..3604c16 100644
--- a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/utils/ConfigUtils.java
+++ b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/config/utils/ConfigUtils.groovy
@@ -1,4 +1,6 @@
-/* Copyright (C) 2011 SpringSource
+
+/*
+ * Copyright 2014 original authors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,22 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.grails.datastore.mapping.config.utils;
+package org.grails.datastore.mapping.config.utils
 
-import java.util.Map;
+import groovy.transform.CompileStatic
+import org.grails.datastore.mapping.model.types.conversion.DefaultConversionService
+import org.springframework.core.convert.ConversionService
 
-import org.grails.datastore.mapping.model.types.conversion.DefaultConversionService;
-import org.springframework.core.convert.ConversionService;
 
 /**
- * Used to ease reading of configuration.
+ * @author Graeme Rocher
+ * @since 3.0
  */
-public class ConfigUtils {
-
+@CompileStatic
+class ConfigUtils {
     private static ConversionService conversionService = new DefaultConversionService();
 
     public static <T> T read(Class<T> type, String key, Map<String, String> config, T defaultValue) {
-        String value = config.get(key);
-        return value == null ? defaultValue : conversionService.convert(value, type);
+        Object value = config.get(key);
+        return !value ? defaultValue : conversionService.convert(value, type);
     }
 }
diff --git a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/proxy/JavassistProxyFactory.java b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/proxy/JavassistProxyFactory.java
index 1e33e7e..8523b50 100644
--- a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/proxy/JavassistProxyFactory.java
+++ b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/proxy/JavassistProxyFactory.java
@@ -46,7 +46,7 @@
     private static final Set<String> EXCLUDES = new HashSet(Arrays.asList("$getStaticMetaClass"));
 
     public boolean isProxy(Object object) {
-        return (object instanceof EntityProxy) || (object instanceof ProxyObject);
+        return object instanceof EntityProxy;
     }
 
     public Serializable getIdentifier(Object obj) {
diff --git a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java
index 447e5d2..bca9ec4 100644
--- a/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java
+++ b/grails-datastore-core/src/main/groovy/org/grails/datastore/mapping/query/Query.java
@@ -61,7 +61,8 @@
     protected Session session;
     protected boolean uniqueResult;
     protected Map<String, FetchType> fetchStrategies = new HashMap<String,FetchType>();
-    protected boolean queryCache;
+    protected Boolean queryCache;
+    protected Boolean lockResult;
 
     protected Query(Session session, PersistentEntity entity) {
         this.entity = entity;
@@ -113,7 +114,18 @@
      * @return The query
      */
     public Query cache(boolean cache) {
-        queryCache = true;
+        queryCache = cache;
+        return this;
+    }
+
+    /**
+     * Specifies whether the query should obtain a pessimistic lock
+     *
+     * @param lock True if a lock should be obtained
+     * @return The query
+     */
+    public Query lock(boolean lock) {
+        lockResult = lock;
         return this;
     }
 
@@ -675,6 +687,7 @@
     public static class Order {
         private Direction direction = Direction.ASC;
         private String property;
+        private boolean ignoreCase = false;
 
         public Order(String property) {
             this.property = property;
@@ -685,22 +698,57 @@
             this.property = property;
         }
 
+        /**
+         * Whether to ignore the case for this order definition
+         *
+         * @return This order instance
+         */
+        public Order ignoreCase() {
+            this.ignoreCase = true;
+            return this;
+        }
+
+        public boolean isIgnoreCase() {
+            return ignoreCase;
+        }
+
+        /**
+         * @return The direction order by
+         */
         public Direction getDirection() {
             return direction;
         }
 
+        /**
+         * @return The property name to order by
+         */
         public String getProperty() {
             return property;
         }
 
+        /**
+         * Creates a new order for the given property in descending order
+         *
+         * @param property The property
+         * @return The order instance
+         */
         public static Order desc(String property) {
             return new Order(property, Direction.DESC);
         }
 
+        /**
+         * Creates a new order for the given property in ascending order
+         *
+         * @param property The property
+         * @return The order instance
+         */
         public static Order asc(String property) {
             return new Order(property, Direction.ASC);
         }
 
+        /**
+         * Represents the direction of the ordering
+         */
         public static enum Direction {
             ASC, DESC
         }
diff --git a/grails-datastore-core/src/test/groovy/grails/persistence/Entity.java b/grails-datastore-core/src/test/groovy/grails/persistence/Entity.java
deleted file mode 100644
index 725fbaf..0000000
--- a/grails-datastore-core/src/test/groovy/grails/persistence/Entity.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package grails.persistence;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * @author Graeme Rocher
- * @since 1.1
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Entity {
-}
diff --git a/grails-datastore-dynamodb/build.gradle b/grails-datastore-dynamodb/build.gradle
index 7d220a8..d5d5b9e 100644
--- a/grails-datastore-dynamodb/build.gradle
+++ b/grails-datastore-dynamodb/build.gradle
@@ -1,4 +1,4 @@
-version = "0.1.2.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 dependencies {
     compile project(":grails-datastore-core")
diff --git a/grails-datastore-gemfire/build.gradle b/grails-datastore-gemfire/build.gradle
index 7549d8e..8495583 100644
--- a/grails-datastore-gemfire/build.gradle
+++ b/grails-datastore-gemfire/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 repositories {
     maven { url "http://dist.gemstone.com/maven/release" }
diff --git a/grails-datastore-gorm-cassandra/build.gradle b/grails-datastore-gorm-cassandra/build.gradle
index 1169fba..0db05d6 100644
--- a/grails-datastore-gorm-cassandra/build.gradle
+++ b/grails-datastore-gorm-cassandra/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 configurations {
 	grails
@@ -25,6 +25,7 @@
         exclude group:'oro',module:'oro'
         exclude group:'asm',module:'asm'
         exclude group:'cglib',module:'cglib'
+        exclude group:'cglib', module:'cglib-nodep'
         exclude group:'xalan',module:'serializer'
         exclude group:'org.springframework',module:'spring-core'
         exclude group:'org.springframework',module:'spring-tx'
@@ -59,7 +60,7 @@
 
 	testCompile project(':grails-datastore-gorm-test'),
 		project(':grails-datastore-gorm-tck'),
-		('cglib:cglib:2.2.2')
+		('cglib:cglib-nodep:2.2.2')
 
 
 	
diff --git a/grails-datastore-gorm-cassandra/src/main/groovy/org/codehaus/groovy/grails/compiler/GormToCassandraTransform.java b/grails-datastore-gorm-cassandra/src/main/groovy/org/codehaus/groovy/grails/compiler/GormToCassandraTransform.java
index 57126ae..f38448a 100644
--- a/grails-datastore-gorm-cassandra/src/main/groovy/org/codehaus/groovy/grails/compiler/GormToCassandraTransform.java
+++ b/grails-datastore-gorm-cassandra/src/main/groovy/org/codehaus/groovy/grails/compiler/GormToCassandraTransform.java
@@ -48,7 +48,7 @@
 import org.codehaus.groovy.grails.commons.GrailsClassUtils;
 import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
 import org.codehaus.groovy.grails.compiler.injection.AstTransformer;
-import org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils;
+import org.grails.compiler.injection.GrailsASTUtils;
 import org.codehaus.groovy.grails.compiler.injection.GrailsArtefactClassInjector;
 import org.codehaus.groovy.grails.compiler.injection.GrailsDomainClassInjector;
 import org.codehaus.groovy.grails.io.support.GrailsResourceUtils;
diff --git a/grails-datastore-gorm-cassandra/src/main/groovy/org/grails/datastore/gorm/cassandra/bean/factory/CassandraMappingContextFactoryBean.groovy b/grails-datastore-gorm-cassandra/src/main/groovy/org/grails/datastore/gorm/cassandra/bean/factory/CassandraMappingContextFactoryBean.groovy
index b62ebd3..941c8b9 100644
--- a/grails-datastore-gorm-cassandra/src/main/groovy/org/grails/datastore/gorm/cassandra/bean/factory/CassandraMappingContextFactoryBean.groovy
+++ b/grails-datastore-gorm-cassandra/src/main/groovy/org/grails/datastore/gorm/cassandra/bean/factory/CassandraMappingContextFactoryBean.groovy
@@ -14,6 +14,7 @@
  */
 package org.grails.datastore.gorm.cassandra.bean.factory
 
+import grails.core.GrailsDomainClass
 import groovy.transform.Canonical
 
 import org.grails.datastore.gorm.bean.factory.AbstractMappingContextFactoryBean
diff --git a/grails-datastore-gorm-cassandra/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy b/grails-datastore-gorm-cassandra/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
index 1ea34f2..85a2aad 100644
--- a/grails-datastore-gorm-cassandra/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
+++ b/grails-datastore-gorm-cassandra/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
@@ -4,7 +4,7 @@
 import javax.persistence.FlushModeType
 
 import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
+import grails.validation.ConstrainedProperty
 import org.grails.datastore.gorm.validation.constraints.UniqueConstraint
 import org.grails.datastore.mapping.model.MappingContext
 import org.grails.datastore.mapping.model.PersistentEntity
diff --git a/grails-datastore-gorm-cassandra/src/test/groovy/grails/persistence/Entity.java b/grails-datastore-gorm-cassandra/src/test/groovy/grails/persistence/Entity.java
deleted file mode 100644
index 596dd22..0000000
--- a/grails-datastore-gorm-cassandra/src/test/groovy/grails/persistence/Entity.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package grails.persistence;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-import org.codehaus.groovy.transform.GroovyASTTransformationClass;
-
-/**
- * @author Graeme Rocher
- * @since 1.1
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-@GroovyASTTransformationClass("org.codehaus.groovy.grails.compiler.injection.EntityASTTransformation")
-public @interface Entity {
-}
diff --git a/grails-datastore-gorm-cassandra/src/test/groovy/org/grails/datastore/gorm/cassandra/plugin/support/CassandraSpringConfigurerSpec.groovy b/grails-datastore-gorm-cassandra/src/test/groovy/org/grails/datastore/gorm/cassandra/plugin/support/CassandraSpringConfigurerSpec.groovy
index 86adb93..706a4b7 100644
--- a/grails-datastore-gorm-cassandra/src/test/groovy/org/grails/datastore/gorm/cassandra/plugin/support/CassandraSpringConfigurerSpec.groovy
+++ b/grails-datastore-gorm-cassandra/src/test/groovy/org/grails/datastore/gorm/cassandra/plugin/support/CassandraSpringConfigurerSpec.groovy
@@ -1,12 +1,12 @@
 package org.grails.datastore.gorm.cassandra.plugin.support
 
+import grails.core.DefaultGrailsApplication
+import grails.core.GrailsApplication
 import grails.gorm.tests.Person
+import grails.plugins.DefaultGrailsPluginManager
 import grails.spring.BeanBuilder
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.plugins.DefaultGrailsPluginManager
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.grails.datastore.gorm.Setup
 import org.grails.datastore.mapping.cassandra.CassandraDatastore
 import org.grails.datastore.mapping.cassandra.config.CassandraMappingContext
@@ -16,6 +16,8 @@
 
 import com.datastax.driver.core.KeyspaceMetadata
 
+
+
 /**
  */
 class CassandraSpringConfigurerSpec extends Specification{
diff --git a/grails-datastore-gorm-dynamodb/build.gradle b/grails-datastore-gorm-dynamodb/build.gradle
index fbf2455..05d1ef0 100644
--- a/grails-datastore-gorm-dynamodb/build.gradle
+++ b/grails-datastore-gorm-dynamodb/build.gradle
@@ -1,4 +1,4 @@
-version = "0.1.2.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 configurations {
     grails
diff --git a/grails-datastore-gorm-gemfire/build.gradle b/grails-datastore-gorm-gemfire/build.gradle
index 4734a8f..b39fd97 100644
--- a/grails-datastore-gorm-gemfire/build.gradle
+++ b/grails-datastore-gorm-gemfire/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 repositories {
     maven { url "http://dist.gemstone.com/maven/release" }
diff --git a/grails-datastore-gorm-hibernate-core/build.gradle b/grails-datastore-gorm-hibernate-core/build.gradle
index 33f3233..df69fc02 100644
--- a/grails-datastore-gorm-hibernate-core/build.gradle
+++ b/grails-datastore-gorm-hibernate-core/build.gradle
@@ -17,6 +17,7 @@
         exclude group:'oro',module:'oro'
         exclude group:'asm',module:'asm'
         exclude group:'cglib',module:'cglib'
+        exclude group:'cglib', module:'cglib-nodep'
         exclude group:'xalan',module:'serializer'
         exclude group:'org.springframework',module:'spring-core'
         exclude group:'org.springframework',module:'spring-tx'
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractEventTriggeringInterceptor.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractEventTriggeringInterceptor.java
index 788b1db..8e47180 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractEventTriggeringInterceptor.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractEventTriggeringInterceptor.java
@@ -20,15 +20,15 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.AbstractGrailsDomainBinder;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.Mapping;
 import org.codehaus.groovy.grails.orm.hibernate.support.SoftKey;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.grails.datastore.mapping.core.Datastore;
 import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent;
 import org.grails.datastore.mapping.engine.event.AbstractPersistenceEventListener;
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateDomainClass.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateDomainClass.java
index e4a47cd..19923a0 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateDomainClass.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateDomainClass.java
@@ -22,15 +22,15 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.codehaus.groovy.grails.commons.AbstractGrailsClass;
-import org.codehaus.groovy.grails.commons.ExternalGrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.exceptions.InvalidPropertyException;
-import org.codehaus.groovy.grails.validation.ConstraintsEvaluator;
-import org.codehaus.groovy.grails.validation.DefaultConstraintEvaluator;
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator;
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.util.GrailsClassUtils;
+import grails.validation.ConstraintsEvaluator;
+import org.grails.core.AbstractGrailsClass;
+import org.grails.core.exceptions.InvalidPropertyException;
+import org.grails.validation.DefaultConstraintEvaluator;
+import org.grails.validation.GrailsDomainClassValidator;
 import org.hibernate.SessionFactory;
 import org.hibernate.metadata.ClassMetadata;
 import org.hibernate.type.AnyType;
@@ -42,7 +42,7 @@
 import org.springframework.validation.Validator;
 
 @SuppressWarnings("rawtypes")
-public abstract class AbstractGrailsHibernateDomainClass extends AbstractGrailsClass implements ExternalGrailsDomainClass {
+public abstract class AbstractGrailsHibernateDomainClass extends AbstractGrailsClass implements GrailsDomainClass {
 
     public static final String HIBERNATE = "hibernate";
 
@@ -103,7 +103,7 @@
             if (!propertyName.equals(ident) && !(versionPropertyName != null &&
                     propertyName.equals(versionPropertyName))) {
 
-                PropertyDescriptor pd = GrailsClassUtils.getProperty(clazz,propertyName);
+                PropertyDescriptor pd = GrailsClassUtils.getProperty(clazz, propertyName);
                 if (pd == null) continue;
 
                 GrailsHibernateDomainClassProperty prop = new GrailsHibernateDomainClassProperty(this, propertyName);
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateDatastore.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateDatastore.java
index d775360..b028009 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateDatastore.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateDatastore.java
@@ -14,6 +14,7 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.config.Config;
 import groovy.util.ConfigObject;
 
 import org.grails.datastore.mapping.core.AbstractDatastore;
@@ -31,10 +32,10 @@
 public abstract class AbstractHibernateDatastore extends AbstractDatastore implements ApplicationContextAware {
 
     protected SessionFactory sessionFactory;
-    protected ConfigObject config;
+    protected Config config;
     protected AbstractEventTriggeringInterceptor eventTriggeringInterceptor;
 
-    protected AbstractHibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config, ApplicationContext applicationContext) {
+    protected AbstractHibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config, ApplicationContext applicationContext) {
         super(mappingContext);
         this.sessionFactory = sessionFactory;
         this.config = config;
@@ -44,7 +45,7 @@
         }
     }
 
-    public AbstractHibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config) {
+    public AbstractHibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config) {
         this(mappingContext, sessionFactory, config, null);
     }
 
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormEnhancer.groovy b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormEnhancer.groovy
index 7ef8c9b..e9071a5b 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormEnhancer.groovy
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormEnhancer.groovy
@@ -14,11 +14,15 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
+import grails.util.GrailsClassUtils
 import grails.util.GrailsNameUtils
 import groovy.transform.CompileStatic
 import groovy.transform.TypeCheckingMode
-import org.codehaus.groovy.grails.commons.*
 import org.codehaus.groovy.grails.orm.hibernate.cfg.HibernateNamedQueriesBuilder
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.core.support.GrailsDomainConfigurationUtil
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.mapping.core.Datastore
 import org.grails.datastore.mapping.model.PersistentEntity
@@ -46,6 +50,14 @@
     }
 
     @Override
+    void enhance(PersistentEntity e, boolean onlyExtendedMethods) {
+        super.enhance(e, onlyExtendedMethods)
+
+        GrailsDomainClass domainClass = (GrailsDomainClass)grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, e.name)
+        datastore.mappingContext.addEntityValidator(e, domainClass.validator)
+    }
+
+    @Override
     protected void registerConstraints(Datastore datastore) {
         // no-op
     }
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormInstanceApi.groovy b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormInstanceApi.groovy
index 2c9b4c3..76e2b3d 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormInstanceApi.groovy
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormInstanceApi.groovy
@@ -15,31 +15,471 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClassProperty
+import grails.core.support.proxy.ProxyHandler
+import grails.util.GrailsClassUtils
+import grails.validation.CascadingValidator
+import grails.validation.DeferredBindingActions
+import grails.validation.ValidationException
+import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
-
+import org.codehaus.groovy.grails.orm.hibernate.proxy.SimpleHibernateProxyHandler
+import org.codehaus.groovy.grails.orm.hibernate.support.HibernateRuntimeUtils
+import org.codehaus.groovy.grails.orm.hibernate.validation.AbstractPersistentConstraint
+import org.grails.core.lifecycle.ShutdownOperations
 import org.grails.datastore.gorm.GormInstanceApi
-import org.hibernate.SessionFactory
+import org.grails.datastore.mapping.engine.event.ValidationEvent
+import org.grails.datastore.mapping.model.PersistentEntity
+import org.grails.datastore.mapping.model.PersistentProperty
+import org.grails.datastore.mapping.model.types.Association
+import org.grails.datastore.mapping.model.types.ToOne
+import org.hibernate.*
+import org.springframework.beans.BeanWrapperImpl
+import org.springframework.beans.InvalidPropertyException
+import org.springframework.dao.DataAccessException
+import org.springframework.validation.Errors
+import org.springframework.validation.Validator
 
+
+/**
+ * Abstract extension of the {@link GormInstanceApi} class that provides common logic shared by Hibernate 3 and Hibernate 4
+ *
+ * @author Graeme Rocher
+ * @param < D >
+ */
 @CompileStatic
-class AbstractHibernateGormInstanceApi<D> extends GormInstanceApi<D> {
+abstract class AbstractHibernateGormInstanceApi<D> extends GormInstanceApi<D> {
+    private static final String ARGUMENT_VALIDATE = "validate";
+    private static final String ARGUMENT_DEEP_VALIDATE = "deepValidate";
+    private static final String ARGUMENT_FLUSH = "flush";
+    private static final String ARGUMENT_INSERT = "insert";
+    private static final String ARGUMENT_MERGE = "merge";
+    private static final String ARGUMENT_FAIL_ON_ERROR = "failOnError";
+
     protected static final Object[] EMPTY_ARRAY = []
+    /**
+     * When a domain instance is saved without validation, we put it
+     * into this thread local variable. Any code that needs to know
+     * whether the domain instance should be validated can just check
+     * the value. Note that this only works because the session is
+     * flushed when a domain instance is saved without validation.
+     */
+    static ThreadLocal<Set<Integer>> disableAutoValidationForThreadLocal = new ThreadLocal<Set<Integer>>()
+    static final ThreadLocal<Boolean> insertActiveThreadLocal = new ThreadLocal<Boolean>()
+
+    static {
+        ShutdownOperations.addOperation(new Runnable() {
+            public void run() {
+                AbstractHibernateGormInstanceApi.disableAutoValidationForThreadLocal.remove()
+                AbstractHibernateGormInstanceApi.insertActiveThreadLocal.remove()
+            }
+        });
+    }
+
+    private static Set<Integer> getDisableAutoValidationFor() {
+        Set<Integer> identifiers = AbstractHibernateGormInstanceApi.disableAutoValidationForThreadLocal.get()
+        if (identifiers == null)
+            AbstractHibernateGormInstanceApi.disableAutoValidationForThreadLocal.set(identifiers = new HashSet<Integer>())
+        return identifiers;
+    }
+
+    public static boolean isAutoValidationDisabled(Object obj) {
+        Set<Integer> identifiers = getDisableAutoValidationFor()
+        return obj != null && identifiers.contains(System.identityHashCode(obj))
+    }
+
+    public static void clearDisabledValidations(Object obj) {
+        getDisableAutoValidationFor().remove(System.identityHashCode(obj))
+    }
+
+    public static void clearDisabledValidations() {
+        getDisableAutoValidationFor().clear();
+    }
 
     protected SessionFactory sessionFactory
     protected ClassLoader classLoader
-    protected boolean cacheQueriesByDefault = false
-
+    protected IHibernateTemplate hibernateTemplate
+    protected ProxyHandler proxyHandler = new SimpleHibernateProxyHandler()
     Map config = Collections.emptyMap()
 
-    protected AbstractHibernateGormInstanceApi(Class<D> persistentClass, AbstractHibernateDatastore datastore, ClassLoader classLoader) {
+    protected AbstractHibernateGormInstanceApi(Class<D> persistentClass, AbstractHibernateDatastore datastore, ClassLoader classLoader, IHibernateTemplate hibernateTemplate) {
         super(persistentClass, datastore)
         this.classLoader = classLoader
         sessionFactory = datastore.getSessionFactory()
+        this.hibernateTemplate = hibernateTemplate
     }
 
-    protected boolean shouldFlush(Map map = [:]) {
-        if (map?.containsKey('flush')) {
-            return Boolean.TRUE == map.flush
+
+
+    @Override
+    D save(D target, Map arguments) {
+
+        PersistentEntity domainClass = persistentEntity
+        DeferredBindingActions.runActions()
+        boolean shouldFlush = shouldFlush(arguments)
+        boolean shouldValidate = shouldValidate(arguments, persistentEntity)
+
+        HibernateRuntimeUtils.autoAssociateBidirectionalOneToOnes(domainClass, target)
+
+        if (shouldValidate) {
+            Validator validator = datastore.mappingContext.getEntityValidator(domainClass)
+
+            Errors errors = HibernateRuntimeUtils.setupErrorsProperty(target)
+
+            if (validator) {
+                datastore.applicationContext?.publishEvent new ValidationEvent(datastore, target)
+
+                boolean deepValidate = true
+                if (arguments?.containsKey(ARGUMENT_DEEP_VALIDATE)) {
+                    deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, arguments);
+                }
+
+                AbstractPersistentConstraint.sessionFactory.set(sessionFactory)
+                try {
+                    if (deepValidate && (validator instanceof CascadingValidator)) {
+                        ((CascadingValidator)validator).validate target, errors, deepValidate
+                    }
+                    else {
+                        validator.validate target, errors
+                    }
+                }
+                finally {
+                    AbstractPersistentConstraint.sessionFactory.remove()
+                }
+
+                if (errors.hasErrors()) {
+                    handleValidationError(domainClass,target,errors);
+                    if (shouldFail(arguments)) {
+                        throw new ValidationException("Validation Error(s) occurred during save()", errors)
+                    }
+                    return null
+                }
+
+                setObjectToReadWrite(target);
+            }
+        }
+
+        // this piece of code will retrieve a persistent instant
+        // of a domain class property is only the id is set thus
+        // relieving this burden off the developer
+        autoRetrieveAssocations domainClass, target
+
+        if (!shouldValidate) {
+            Set<Integer> identifiers = getDisableAutoValidationFor()
+            identifiers.add System.identityHashCode(target)
+        }
+
+        if (shouldInsert(arguments)) {
+            return performInsert(target, shouldFlush)
+        }
+        else if(shouldMerge(arguments)) {
+            return performMerge(target, shouldFlush)
+        }
+        else {
+            return performSave(target, shouldFlush)
+        }
+    }
+
+    @Override
+    D merge(D instance, Map params) {
+        Map args = new HashMap(params)
+        args[ARGUMENT_MERGE] = true
+        return save(instance, params)
+    }
+
+    @Override
+    D insert(D instance, Map params) {
+        Map args = new HashMap(params)
+        args[ARGUMENT_INSERT] = true
+        return save(instance, args)
+    }
+
+    @Override
+    void discard(D instance) {
+        hibernateTemplate.evict instance
+    }
+
+    @Override
+    void delete(D instance, Map params = Collections.emptyMap()) {
+        boolean flush = shouldFlush(params)
+        try {
+            hibernateTemplate.execute { Session session ->
+                session.delete instance
+                if(flush) {
+                    session.flush()
+                }
+            }
+        }
+        catch (DataAccessException e) {
+            try {
+                hibernateTemplate.execute { Session session ->
+                    session.flushMode = FlushMode.MANUAL
+                }
+            }
+            finally {
+                throw e
+            }
+        }
+    }
+
+    @Override
+    boolean isAttached(D instance) {
+        hibernateTemplate.contains instance
+    }
+
+    @Override
+    boolean instanceOf(D instance, Class cls) {
+        return proxyHandler.unwrapIfProxy(instance) in cls
+    }
+
+    @Override
+    D lock(D instance) {
+        hibernateTemplate.lock(instance, LockMode.PESSIMISTIC_WRITE)
+    }
+
+    @Override
+    D attach(D instance) {
+        hibernateTemplate.lock(instance, LockMode.NONE)
+        return instance
+    }
+
+    @Override
+    D refresh(D instance) {
+        hibernateTemplate.refresh(instance)
+        return instance
+    }
+
+    protected D performSave(final D target, final boolean flush) {
+        hibernateTemplate.execute { Session session ->
+            session.saveOrUpdate target
+            if (flush) {
+                flushSession session
+            }
+            return target
+        }
+    }
+
+    protected D performMerge(final D target, final boolean flush) {
+        hibernateTemplate.execute { Session session ->
+            Object merged = session.merge(target)
+            session.lock(merged, LockMode.NONE);
+            if (flush) {
+                flushSession session
+            }
+            return merged
+        }
+    }
+
+    protected D performInsert(final D target, final boolean shouldFlush) {
+        hibernateTemplate.execute { Session session ->
+            try {
+                markInsertActive()
+                session.save target
+                if (shouldFlush) {
+                    flushSession session
+                }
+                return target
+            } finally {
+                resetInsertActive()
+            }
+
+        }
+    }
+
+    protected void flushSession(Session session) throws HibernateException {
+        try {
+            session.flush()
+        } catch (HibernateException e) {
+            // session should not be flushed again after a data acccess exception!
+            session.setFlushMode FlushMode.MANUAL
+            throw e
+        }
+    }
+    /**
+     * Performs automatic association retrieval
+     * @param entity The domain class to retrieve associations for
+     * @param target The target object
+     */
+    @SuppressWarnings("unchecked")
+    private void autoRetrieveAssocations(PersistentEntity entity, Object target) {
+        def bean = new BeanWrapperImpl(target)
+        IHibernateTemplate t = this.hibernateTemplate
+        for (PersistentProperty prop in entity.associations) {
+            if(prop instanceof ToOne) {
+                ToOne toOne = (ToOne)prop
+                def propValue = bean.getPropertyValue(prop.name)
+                if (propValue == null || t.contains(propValue)) {
+                    continue
+                }
+
+                PersistentEntity otherSide = toOne.associatedEntity
+                if (otherSide == null) {
+                    continue
+                }
+
+                def propBean = new BeanWrapperImpl(propValue)
+                try {
+                    def id = (Serializable)propBean.getPropertyValue(otherSide.identity.name);
+                    if (id) {
+                        final Object propVal = t.get(prop.type, id)
+                        if (propVal) {
+                            bean.setPropertyValue prop.name, propVal
+                        }
+                    }
+                }
+                catch (InvalidPropertyException ipe) {
+                    // property is not accessable
+                }
+            }
+
+        }
+    }
+
+    /**
+     * Checks whether validation should be performed
+     * @return true if the domain class should be validated
+     * @param arguments  The arguments to the validate method
+     * @param domainClass The domain class
+     */
+    private boolean shouldValidate(Map arguments, PersistentEntity entity) {
+        if (!entity) {
+            return false
+        }
+
+        if (arguments.containsKey(ARGUMENT_VALIDATE)) {
+            return GrailsClassUtils.getBooleanFromMap(ARGUMENT_VALIDATE, arguments)
+        }
+        return true
+    }
+
+    private boolean shouldInsert(Map arguments) {
+        GrailsClassUtils.getBooleanFromMap(ARGUMENT_INSERT, arguments)
+    }
+
+    private boolean shouldMerge(Map arguments) {
+        GrailsClassUtils.getBooleanFromMap(ARGUMENT_MERGE, arguments)
+    }
+
+
+    protected boolean shouldFlush(Map map) {
+        if (map?.containsKey(ARGUMENT_FLUSH)) {
+            return GrailsClassUtils.getBooleanFromMap(ARGUMENT_FLUSH, map)
         }
         return config?.autoFlush instanceof Boolean ? config.autoFlush : false
     }
+
+    protected boolean shouldFail(Map map) {
+        if (map?.containsKey(ARGUMENT_FAIL_ON_ERROR)) {
+            return GrailsClassUtils.getBooleanFromMap(ARGUMENT_FAIL_ON_ERROR, map)
+        }
+        return config?.get(ARGUMENT_FAIL_ON_ERROR) instanceof Boolean ? GrailsClassUtils.getBooleanFromMap(ARGUMENT_FAIL_ON_ERROR, config) : false
+    }
+
+    /**
+     * Sets the flush mode to manual. which ensures that the database changes are not persisted to the database
+     * if a validation error occurs. If save() is called again and validation passes the code will check if there
+     * is a manual flush mode and flush manually if necessary
+     *
+     * @param domainClass The domain class
+     * @param target The target object that failed validation
+     * @param errors The Errors instance  @return This method will return null signaling a validation failure
+     */
+    protected Object handleValidationError(PersistentEntity entity, final Object target, Errors errors) {
+        // if a validation error occurs set the object to read-only to prevent a flush
+        setObjectToReadOnly target
+        if (entity) {
+            for (Association association in entity.associations) {
+                if (association instanceof ToOne) {
+                    if(proxyHandler.isInitialized(target, association.name)) {
+                        def bean = new BeanWrapperImpl(target)
+                        def propertyValue = bean.getPropertyValue(association.name)
+                        if (propertyValue != null) {
+                            setObjectToReadOnly propertyValue
+                        }
+                    }
+                }
+            }
+        }
+        setErrorsOnInstance target, errors
+        return null
+    }
+
+    /**
+     * Sets the target object to read-only using the given SessionFactory instance. This
+     * avoids Hibernate performing any dirty checking on the object
+     *
+     *
+     * @param target The target object
+     * @param sessionFactory The SessionFactory instance
+     */
+    public void setObjectToReadOnly(Object target) {
+        hibernateTemplate.execute { Session session ->
+            if (session.contains(target) && proxyHandler.isInitialized(target)) {
+                target = proxyHandler.unwrapIfProxy(target)
+                session.setReadOnly target, true
+                session.flushMode = FlushMode.MANUAL
+            }
+        }
+    }
+    /**
+     * Sets the target object to read-write, allowing Hibernate to dirty check it and auto-flush changes.
+     *
+     * @see #setObjectToReadOnly(Object)
+     *
+     * @param target The target object
+     * @param sessionFactory The SessionFactory instance
+     */
+    public abstract void setObjectToReadWrite(Object target)
+
+    /**
+     * Associates the Errors object on the instance
+     *
+     * @param target The target instance
+     * @param errors The Errors object
+     */
+    @CompileDynamic
+    protected void setErrorsOnInstance(Object target, Errors errors) {
+        target."$GrailsDomainClassProperty.ERRORS" = errors
+    }
+
+    /**
+     * Prevents hitting the database for an extra check if the row exists in the database.
+     *
+     * ThreadLocal is used to pass the "insert:true" information to Hibernate.
+     *
+     * @see org.hibernate.event.def.AbstractSaveEventListener#getAssumedUnsaved()
+     */
+    public static Boolean getAssumedUnsaved() {
+        return insertActiveThreadLocal.get();
+    }
+
+    /**
+     * Called by org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod's performInsert
+     * to set a ThreadLocal variable that determines the value for getAssumedUnsaved().
+     */
+    public static void markInsertActive() {
+        insertActiveThreadLocal.set(Boolean.TRUE);
+    }
+
+    /**
+     * Clears the ThreadLocal variable set by markInsertActive().
+     */
+    public static void resetInsertActive() {
+        insertActiveThreadLocal.remove();
+    }
+
+    /**
+     * Increments the entities version number in order to force an update
+     * @param target The target entity
+     */
+    @CompileDynamic
+    protected void incrementVersion(Object target) {
+        if (target.hasProperty(GrailsDomainClassProperty.VERSION)) {
+            Object version = target."${GrailsDomainClassProperty.VERSION}"
+            if (version instanceof Long) {
+                target."${GrailsDomainClassProperty.VERSION}" = ++((Long)version)
+            }
+        }
+    }
+
 }
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormStaticApi.groovy b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormStaticApi.groovy
new file mode 100644
index 0000000..806e83e
--- /dev/null
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormStaticApi.groovy
@@ -0,0 +1,491 @@
+package org.codehaus.groovy.grails.orm.hibernate
+
+import grails.core.support.proxy.ProxyHandler
+import grails.util.GrailsClassUtils
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.grails.orm.hibernate.cfg.AbstractGrailsDomainBinder
+import org.codehaus.groovy.grails.orm.hibernate.cfg.CompositeIdentity
+import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException
+import org.codehaus.groovy.grails.orm.hibernate.proxy.SimpleHibernateProxyHandler
+import org.codehaus.groovy.grails.orm.hibernate.query.GrailsHibernateQueryUtils
+import org.codehaus.groovy.grails.orm.hibernate.support.HibernateRuntimeUtils
+import org.grails.datastore.gorm.GormStaticApi
+import org.grails.datastore.gorm.finders.DynamicFinder
+import org.grails.datastore.gorm.finders.FinderMethod
+import org.grails.datastore.mapping.core.Datastore
+import org.hibernate.Criteria
+import org.hibernate.FlushMode
+import org.hibernate.Query
+import org.hibernate.Session
+import org.hibernate.criterion.Example
+import org.hibernate.criterion.Projections
+import org.hibernate.criterion.Restrictions
+import org.hibernate.transform.DistinctRootEntityResultTransformer
+import org.springframework.core.convert.ConversionService
+import org.springframework.transaction.PlatformTransactionManager
+
+import java.util.regex.Pattern
+
+/**
+ * Abstract implementation of the Hibernate static API for GORM, providing String-based method implementations
+ *
+ * @author Graeme Rocher
+ * @since 4.0
+ */
+@CompileStatic
+abstract class AbstractHibernateGormStaticApi<D> extends GormStaticApi<D> {
+
+    protected ProxyHandler proxyHandler = new SimpleHibernateProxyHandler()
+    protected Pattern queryPattern
+    protected IHibernateTemplate hibernateTemplate
+    protected ConversionService conversionService
+
+    AbstractHibernateGormStaticApi(Class<D> persistentClass, Datastore datastore, List<FinderMethod> finders, IHibernateTemplate hibernateTemplate) {
+        this(persistentClass, datastore, finders, null, hibernateTemplate)
+    }
+
+    AbstractHibernateGormStaticApi(Class<D> persistentClass, Datastore datastore, List<FinderMethod> finders, PlatformTransactionManager transactionManager, IHibernateTemplate hibernateTemplate) {
+        super(persistentClass, datastore, finders, transactionManager)
+        this.hibernateTemplate = hibernateTemplate
+        this.queryPattern = ~/(?i)from(?-i)\s+[${persistentEntity.name}|${persistentEntity.javaClass.simpleName}].*/
+        this.conversionService = datastore.mappingContext.conversionService
+    }
+
+    @Override
+    D get(Serializable id) {
+        if (id || (id instanceof Number)) {
+            id = convertIdentifier(id)
+            D result = (D)hibernateTemplate.get((Class)persistentClass, id)
+            return (D)proxyHandler.unwrapIfProxy(result)
+        }
+    }
+
+    @Override
+    D read(Serializable id) {
+        if (id == null) {
+            return null
+        }
+
+        hibernateTemplate.execute(  { Session session ->
+
+            def criteria = session.createCriteria(persistentEntity.javaClass)
+            criteria.add Restrictions.idEq(convertIdentifier(id))
+            criteria.readOnly = true
+            def result = (D) criteria.uniqueResult()
+            if(result)
+                session.setReadOnly(result, true)
+            return proxyHandler.unwrapIfProxy( result )
+        } )
+    }
+
+    @Override
+    D load(Serializable id) {
+        id = convertIdentifier(id)
+        if (id != null) {
+            return (D) hibernateTemplate.load((Class)persistentClass, id)
+        }
+    }
+
+    @Override
+    List<D> getAll() {
+        (List<D>)hibernateTemplate.execute({ Session session ->
+            Criteria criteria = session.createCriteria(persistentClass)
+            hibernateTemplate.applySettings(criteria)
+            criteria.list()
+        })
+    }
+
+    @Override
+    Integer count() {
+        (Integer)hibernateTemplate.execute({ Session session ->
+            def criteria = session.createCriteria(persistentClass)
+            hibernateTemplate.applySettings(criteria)
+            criteria.setProjection(Projections.rowCount())
+            def num = criteria.uniqueResult()
+            num == null ? 0 : num
+        })
+    }
+
+    @Override
+    boolean exists(Serializable id) {
+        id = convertIdentifier(id)
+        hibernateTemplate.execute  { Session session ->
+            Criteria criteria = session.createCriteria(persistentEntity.javaClass)
+            hibernateTemplate.applySettings(criteria)
+            criteria.add(Restrictions.idEq(id))
+                    .setProjection(Projections.rowCount())
+                    .uniqueResult()
+        }
+    }
+
+    D first(Map m) {
+        def entityMapping = AbstractGrailsDomainBinder.getMapping(persistentEntity.javaClass)
+        if (entityMapping?.identity instanceof CompositeIdentity) {
+            throw new UnsupportedOperationException('The first() method is not supported for domain classes that have composite keys.')
+        }
+        super.first(m)
+    }
+
+    D last(Map m) {
+        def entityMapping = AbstractGrailsDomainBinder.getMapping(persistentEntity.javaClass)
+        if (entityMapping?.identity instanceof CompositeIdentity) {
+            throw new UnsupportedOperationException('The last() method is not supported for domain classes that have composite keys.')
+        }
+        super.last(m)
+    }
+
+    /**
+     * Implements the 'find(String' method to use HQL queries with named arguments
+     *
+     * @param query The query
+     * @param queryNamedArgs The named arguments
+     * @param args Any additional query arguments
+     * @return A result or null if no result found
+     */
+    @Override
+    D find(String query, Map queryNamedArgs, Map args) {
+        if (!queryPattern.matcher(query).matches()) {
+            throw new GrailsQueryException("Invalid query [$query] for domain class [$persistentEntity.name]");
+        }
+
+        def template = hibernateTemplate
+        queryNamedArgs = new HashMap(queryNamedArgs)
+        args = new HashMap(args)
+        return (D) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+
+            populateQueryArguments(q, queryNamedArgs)
+            populateQueryArguments(q, args)
+            populateQueryWithNamedArguments(q, queryNamedArgs)
+            return executeHibernateQuery(q, args)
+        }
+    }
+
+    @Override
+    D find(String query, Collection params, Map args) {
+        if (!queryPattern.matcher(query).matches()) {
+            throw new GrailsQueryException("Invalid query [$query] for domain class [$persistentEntity.name]");
+        }
+
+        args = new HashMap(args)
+        def template = hibernateTemplate
+        return (D) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+
+            params.eachWithIndex { val, int i ->
+                if (val instanceof CharSequence) {
+                    q.setParameter i, val.toString()
+                }
+                else {
+                    q.setParameter i, val
+                }
+            }
+            populateQueryArguments(q, args)
+            return executeHibernateQuery(q, args)
+        }
+    }
+
+    @Override
+    List<D> findAll(String query, Map params, Map args) {
+        if (!queryPattern.matcher(query).matches()) {
+            throw new GrailsQueryException("Invalid query [$query] for domain class [$persistentEntity.name]");
+        }
+
+        args = new HashMap(args)
+        params = new HashMap(params)
+        def template = hibernateTemplate
+        return (List<D>) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+
+            populateQueryArguments(q, params)
+            populateQueryArguments(q, args)
+            populateQueryWithNamedArguments(q, params)
+
+            return q.list()
+        }
+    }
+
+    @Override
+    List<D> findAll(String query, Collection params, Map args) {
+        if (!queryPattern.matcher(query).matches()) {
+            throw new GrailsQueryException("Invalid query [$query] for domain class [$persistentEntity.name]");
+        }
+
+        args = new HashMap(args)
+
+        def template = hibernateTemplate
+        return (List<D>) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+
+            params.eachWithIndex { val, int i ->
+                if (val instanceof CharSequence) {
+                    q.setParameter i, val.toString()
+                }
+                else {
+                    q.setParameter i, val
+                }
+            }
+            populateQueryArguments(q, args)
+            return q.list()
+        }
+    }
+
+    @Override
+    D find(D exampleObject, Map args) {
+        def template = hibernateTemplate
+        return (D) template.execute { Session session ->
+            Example example = Example.create(exampleObject).ignoreCase()
+
+            Criteria crit = session.createCriteria(persistentEntity.javaClass);
+            hibernateTemplate.applySettings(crit)
+            crit.add example
+            GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, crit, args, datastore.mappingContext.conversionService, true)
+            crit.maxResults = 1
+            List results = crit.list()
+            if (results) {
+                return proxyHandler.unwrapIfProxy( results.get(0) )
+            }
+        }
+    }
+
+    @Override
+    List<D> findAll(D exampleObject, Map args) {
+        def template = hibernateTemplate
+        return (List<D>) template.execute { Session session ->
+            Example example = Example.create(exampleObject).ignoreCase()
+
+            Criteria crit = session.createCriteria(persistentEntity.javaClass);
+            hibernateTemplate.applySettings(crit)
+            crit.add example
+            GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, crit, args, datastore.mappingContext.conversionService, true)
+            crit.list()
+        }
+    }
+
+    @Override
+    List<D> findAllWhere(Map queryMap, Map args) {
+        if (!queryMap) return null
+        (List<D>)hibernateTemplate.execute { Session session ->
+            Map<String, Object> processedQueryMap = [:]
+            queryMap.each{ key, value -> processedQueryMap[key.toString()] = value }
+            Map queryArgs = filterQueryArgumentMap(processedQueryMap)
+            List<String> nullNames = removeNullNames(queryArgs)
+            Criteria criteria = session.createCriteria(persistentClass)
+            hibernateTemplate.applySettings(criteria)
+            criteria.add(Restrictions.allEq(queryArgs))
+            for (name in nullNames) {
+                criteria.add Restrictions.isNull(name)
+            }
+            criteria.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE)
+            criteria.list()
+        }
+    }
+
+    @Override
+    List<D> executeQuery(String query, Map params, Map args) {
+        def template = hibernateTemplate
+        args = new HashMap(args)
+        params = new HashMap(params)
+
+        return (List<D>) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+
+            populateQueryArguments(q, params)
+            populateQueryArguments(q, args)
+            populateQueryWithNamedArguments(q, params)
+
+            return q.list()
+        }
+    }
+
+    @Override
+    List<D> executeQuery(String query, Collection params, Map args) {
+        def template = hibernateTemplate
+        args = new HashMap(args)
+
+        return (List<D>) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+
+            params.eachWithIndex { val, int i ->
+                if (val instanceof CharSequence) {
+                    q.setParameter i, val.toString()
+                }
+                else {
+                    q.setParameter i, val
+                }
+            }
+            populateQueryArguments(q, args)
+            return q.list()
+        }
+    }
+
+    @Override
+    D findWhere(Map queryMap, Map args) {
+        if (!queryMap) return null
+        (D)hibernateTemplate.execute { Session session ->
+            Map<String, Object> processedQueryMap = [:]
+            queryMap.each{ key, value -> processedQueryMap[key.toString()] = value }
+            Map queryArgs = filterQueryArgumentMap(processedQueryMap)
+            List<String> nullNames = removeNullNames(queryArgs)
+            Criteria criteria = session.createCriteria(persistentClass)
+            hibernateTemplate.applySettings(criteria)
+            criteria.add(Restrictions.allEq(queryArgs))
+            for (name in nullNames) {
+                criteria.add Restrictions.isNull(name)
+            }
+            criteria.setMaxResults(1)
+            proxyHandler.unwrapIfProxy(criteria.uniqueResult())
+        }
+    }
+
+
+
+    List<D> getAll(List ids) {
+        getAllInternal(ids)
+    }
+
+    List<D> getAll(Long... ids) {
+        getAllInternal(ids as List)
+    }
+
+    @Override
+    List<D> getAll(Serializable... ids) {
+        getAllInternal(ids as List)
+    }
+
+    private List getAllInternal(List ids) {
+        if (!ids) return []
+
+        (List)hibernateTemplate.execute { Session session ->
+            def identityType = persistentEntity.identity.type
+            ids = ids.collect { HibernateRuntimeUtils.convertValueToType((Serializable)it, identityType, conversionService) }
+            def criteria = session.createCriteria(persistentClass)
+            hibernateTemplate.applySettings(criteria)
+            def identityName = persistentEntity.identity.name
+            criteria.add(Restrictions.'in'(identityName, ids))
+            def results = criteria.list()
+            def idsMap = [:]
+            for (object in results) {
+                idsMap[object[identityName]] = object
+            }
+            results.clear()
+            for (id in ids) {
+                results << idsMap[id]
+            }
+            results
+        }
+    }
+
+    protected Map filterQueryArgumentMap(Map query) {
+        def queryArgs = [:]
+        for (entry in query.entrySet()) {
+            if (entry.value instanceof CharSequence) {
+                queryArgs[entry.key] = entry.value.toString()
+            }
+            else {
+                queryArgs[entry.key] = entry.value
+            }
+        }
+        return queryArgs
+    }
+
+
+    protected List<String> removeNullNames(Map query) {
+        List<String> nullNames = []
+        Set<String> allNames = new HashSet(query.keySet())
+        for (String name in allNames) {
+            if (query[name] == null) {
+                query.remove name
+                nullNames << name
+            }
+        }
+        nullNames
+    }
+
+    protected D executeHibernateQuery(Query q, Map args) {
+        q.maxResults = 1
+        List results = q.list()
+        if (results) {
+            return (D)proxyHandler.unwrapIfProxy(results.get(0))
+        }
+    }
+
+    protected Serializable convertIdentifier(Serializable id) {
+        (Serializable)HibernateRuntimeUtils.convertValueToType(id, persistentEntity.identity.type, conversionService)
+    }
+
+    protected void populateQueryWithNamedArguments(Query q, Map queryNamedArgs) {
+
+        if (queryNamedArgs) {
+            for (Map.Entry entry in queryNamedArgs.entrySet()) {
+                def key = entry.key
+                if (!(key instanceof CharSequence)) {
+                    throw new GrailsQueryException("Named parameter's name must be String: $queryNamedArgs")
+                }
+                String stringKey = key.toString()
+                def value = entry.value
+
+                if(value == null) {
+                    q.setParameter stringKey, null
+                } else if (value instanceof CharSequence) {
+                    q.setParameter stringKey, value.toString()
+                } else if (List.class.isAssignableFrom(value.getClass())) {
+                    q.setParameterList stringKey, (List) value
+                } else if (value.getClass().isArray()) {
+                    q.setParameterList stringKey, (Object[]) value
+                } else {
+                    q.setParameter stringKey, value
+                }
+            }
+        }
+    }
+
+    protected Integer intValue(Map args, String key) {
+        def value = args.get(key)
+        if(value) {
+            return conversionService.convert(value, Integer.class)
+        }
+        return null
+    }
+
+    protected void populateQueryArguments(Query q, Map args) {
+        Integer max = intValue(args, DynamicFinder.ARGUMENT_MAX)
+        args.remove(DynamicFinder.ARGUMENT_MAX)
+        Integer offset = intValue(args, DynamicFinder.ARGUMENT_OFFSET)
+        args.remove(DynamicFinder.ARGUMENT_OFFSET)
+
+        //
+        if (max != null) {
+            q.maxResults = max
+        }
+        if (offset != null) {
+            q.firstResult = offset
+        }
+
+        if (args.containsKey(DynamicFinder.ARGUMENT_CACHE)) {
+            q.cacheable = GrailsClassUtils.getBooleanFromMap(DynamicFinder.ARGUMENT_CACHE, args)
+        }
+        if (args.containsKey(DynamicFinder.ARGUMENT_FETCH_SIZE)) {
+            Integer fetchSizeParam = conversionService.convert(args.remove(DynamicFinder.ARGUMENT_FETCH_SIZE), Integer.class);
+            q.setFetchSize(fetchSizeParam.intValue());
+        }
+        if (args.containsKey(DynamicFinder.ARGUMENT_TIMEOUT)) {
+            Integer timeoutParam = conversionService.convert(args.remove(DynamicFinder.ARGUMENT_TIMEOUT), Integer.class);
+            q.setTimeout(timeoutParam.intValue());
+        }
+        if (args.containsKey(DynamicFinder.ARGUMENT_READ_ONLY)) {
+            q.setReadOnly((Boolean)args.remove(DynamicFinder.ARGUMENT_READ_ONLY));
+        }
+        if (args.containsKey(DynamicFinder.ARGUMENT_FLUSH_MODE)) {
+            q.setFlushMode((FlushMode)args.remove(DynamicFinder.ARGUMENT_FLUSH_MODE));
+        }
+
+        args.remove(DynamicFinder.ARGUMENT_CACHE)
+    }
+}
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormValidationApi.groovy b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormValidationApi.groovy
index 06e8720..cbc9fae 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormValidationApi.groovy
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractHibernateGormValidationApi.groovy
@@ -15,55 +15,137 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClassProperty
+import grails.util.GrailsClassUtils
+import grails.validation.CascadingValidator
+import grails.validation.ValidationErrors
 import groovy.transform.CompileStatic
-
+import org.codehaus.groovy.grails.orm.hibernate.support.HibernateRuntimeUtils
+import org.codehaus.groovy.grails.orm.hibernate.validation.AbstractPersistentConstraint
 import org.grails.datastore.gorm.GormValidationApi
-import groovy.transform.CompileStatic
-
-import org.codehaus.groovy.grails.commons.metaclass.DynamicMethodInvocation
-import org.grails.datastore.gorm.GormValidationApi
+import org.grails.datastore.mapping.engine.event.ValidationEvent
+import org.springframework.validation.Errors
+import org.springframework.validation.FieldError
+import org.springframework.validation.ObjectError
 
 @CompileStatic
 abstract class AbstractHibernateGormValidationApi<D> extends GormValidationApi<D> {
 
+    public static final String ARGUMENT_DEEP_VALIDATE = "deepValidate";
+    private static final String ARGUMENT_EVICT = "evict";
+
+
     protected ClassLoader classLoader
+    protected AbstractHibernateDatastore datastore
+    protected IHibernateTemplate hibernateTemplate
 
     protected AbstractHibernateGormValidationApi(Class<D> persistentClass, AbstractHibernateDatastore datastore, ClassLoader classLoader) {
         super(persistentClass, datastore)
         this.classLoader = classLoader
+        this.datastore = datastore
     }
 
-    protected abstract DynamicMethodInvocation getValidateMethod()
 
     @Override
-    boolean validate(D instance) {
-        if (getValidateMethod()) {
-            return getValidateMethod().invoke(instance, "validate", [] as Object[])
-        }
-        return super.validate(instance)
+    boolean validate(D instance, Map arguments = Collections.emptyMap()) {
+        validate(instance, null, arguments)
     }
 
-    @Override
-    boolean validate(D instance, boolean evict) {
-        if (getValidateMethod()) {
-            return getValidateMethod().invoke(instance, "validate", [evict] as Object[])
+    boolean validate(D instance, List validatedFieldsList, Map arguments = Collections.emptyMap()) {
+        Errors errors = setupErrorsProperty(instance);
+        if(validator == null) return true
+
+        Boolean valid = Boolean.TRUE
+        // should evict?
+        boolean evict = false
+        boolean deepValidate = true
+        Set validatedFields = null
+        if(validatedFieldsList != null) {
+            validatedFields = new HashSet(validatedFieldsList)
         }
-        return super.validate(instance, evict)
+
+        if (arguments.containsKey(ARGUMENT_DEEP_VALIDATE)) {
+            deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, arguments)
+        }
+
+        evict = GrailsClassUtils.getBooleanFromMap(ARGUMENT_EVICT, arguments);
+
+        fireEvent instance, validatedFieldsList
+
+        AbstractPersistentConstraint.sessionFactory.set datastore.sessionFactory
+        try {
+            if (deepValidate && (validator instanceof CascadingValidator)) {
+                ((CascadingValidator)validator).validate instance, errors, deepValidate
+            }
+            else {
+                validator.validate instance, errors
+            }
+        }
+        finally {
+            AbstractPersistentConstraint.sessionFactory.remove()
+        }
+
+        int oldErrorCount = errors.errorCount
+        errors = filterErrors(errors, validatedFields, instance)
+
+        if (errors.hasErrors()) {
+            valid = Boolean.FALSE
+            if (evict) {
+                // if an boolean argument 'true' is passed to the method
+                // and validation fails then the object will be evicted
+                // from the session, ensuring it is not saved later when
+                // flush is called
+                if (hibernateTemplate.contains(instance)) {
+                    hibernateTemplate.evict(instance)
+                }
+            }
+        }
+
+        // If the errors have been filtered, update the 'errors' object attached to the target.
+        if (errors.errorCount != oldErrorCount) {
+            MetaClass metaClass = GroovySystem.metaClassRegistry.getMetaClass(instance.getClass())
+            metaClass.setProperty( instance, GrailsDomainClassProperty.ERRORS, errors)
+        }
+
+        return valid
     }
 
-    @Override
-    boolean validate(D instance, Map arguments) {
-        if (getValidateMethod()) {
-            return getValidateMethod().invoke(instance, "validate", [arguments] as Object[])
-        }
-        return super.validate(instance, arguments)
+    private void fireEvent(Object target, List<?> validatedFieldsList) {
+        ValidationEvent event = new ValidationEvent(datastore, target);
+        event.setValidatedFields(validatedFieldsList);
+        datastore.getApplicationContext().publishEvent(event);
     }
 
-    @Override
-    boolean validate(D instance, List fields) {
-        if (getValidateMethod()) {
-            return getValidateMethod().invoke(instance, "validate", [fields] as Object[])
+    @SuppressWarnings("rawtypes")
+    private Errors filterErrors(Errors errors, Set validatedFields, Object target) {
+        if (validatedFields == null) return errors;
+
+        ValidationErrors result = new ValidationErrors(target);
+
+        final List allErrors = errors.getAllErrors();
+        for (Object allError : allErrors) {
+            ObjectError error = (ObjectError) allError;
+
+            if (error instanceof FieldError) {
+                FieldError fieldError = (FieldError) error;
+                if (!validatedFields.contains(fieldError.getField())) continue;
+            }
+
+            result.addError(error);
         }
-        return super.validate(instance, fields)
+
+        return result;
+    }
+
+    /**
+     * Initializes the Errors property on target.  The target will be assigned a new
+     * Errors property.  If the target contains any binding errors, those binding
+     * errors will be copied in to the new Errors property.
+     *
+     * @param target object to initialize
+     * @return the new Errors object
+     */
+    protected Errors setupErrorsProperty(Object target) {
+        HibernateRuntimeUtils.setupErrorsProperty target
     }
 }
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClassProperty.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClassProperty.java
index dc3b348..1eb1aee 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClassProperty.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClassProperty.java
@@ -14,13 +14,13 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import grails.util.GrailsNameUtils;
 
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.Field;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
 import org.springframework.beans.BeanUtils;
 import org.springframework.util.ReflectionUtils;
 
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/IHibernateTemplate.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/IHibernateTemplate.java
index 395519f..9096366 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/IHibernateTemplate.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/IHibernateTemplate.java
@@ -18,11 +18,17 @@
 import java.io.Serializable;
 import java.util.Collection;
 
+import groovy.lang.Closure;
+import org.hibernate.Criteria;
 import org.hibernate.LockMode;
+import org.hibernate.Query;
 import org.hibernate.SessionFactory;
 
 /**
+ * Template interface that can be used with both Hibernate 3 and Hibernate 4
+ *
  * @author Burt Beckwith
+ * @author Graeme Rocher
  */
 public interface IHibernateTemplate {
 
@@ -46,6 +52,10 @@
 
     void deleteAll(Collection<?> list);
 
+    void applySettings(Query query);
+
+    void applySettings(Criteria criteria);
+
     <T> T get(Class<T> type, Serializable key);
 
     <T> T get(Class<T> type, Serializable key, LockMode mode);
@@ -55,4 +65,6 @@
     void delete(Object o);
 
     SessionFactory getSessionFactory();
+
+    <T> T execute(Closure<T> callable);
 }
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/AbstractGrailsDomainBinder.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/AbstractGrailsDomainBinder.java
index a0910c6..3f6d484 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/AbstractGrailsDomainBinder.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/AbstractGrailsDomainBinder.java
@@ -14,16 +14,21 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
+import grails.config.Config;
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.plugins.GrailsPlugin;
+import grails.plugins.GrailsPluginManager;
+import grails.util.GrailsClassUtils;
 import grails.util.GrailsNameUtils;
+import grails.validation.ConstrainedProperty;
 import groovy.lang.Closure;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.*;
-import org.codehaus.groovy.grails.exceptions.GrailsDomainException;
-import org.codehaus.groovy.grails.plugins.GrailsPlugin;
-import org.codehaus.groovy.grails.plugins.GrailsPluginManager;
-import org.codehaus.groovy.grails.validation.ConstrainedProperty;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.grails.core.DefaultGrailsDomainClassProperty;
+import org.grails.core.exceptions.GrailsDomainException;
 import org.hibernate.FetchMode;
 import org.hibernate.MappingException;
 import org.hibernate.cfg.*;
@@ -1172,7 +1177,7 @@
         }
         if (tableName == null) {
             String shortName = domainClass.getShortName();
-            final GrailsApplication grailsApplication = domainClass.getGrailsApplication();
+            final GrailsApplication grailsApplication = domainClass.getApplication();
             if (grailsApplication != null) {
                 final ApplicationContext mainContext = grailsApplication.getMainContext();
                 if (mainContext != null && mainContext.containsBean("pluginManager")) {
@@ -1183,11 +1188,11 @@
                         boolean shouldApplyPluginPrefix = false;
                         if (!shortName.toLowerCase().startsWith(pluginName.toLowerCase())) {
                             final String pluginSpecificConfigProperty = "grails.gorm." + GrailsNameUtils.getPropertyName(pluginName) + ".table.prefix.enabled";
-                            final Map<String, Object> flatConfig = grailsApplication.getFlatConfig();
-                            if (flatConfig.containsKey(pluginSpecificConfigProperty)) {
-                                shouldApplyPluginPrefix = Boolean.TRUE.equals(flatConfig.get(pluginSpecificConfigProperty));
+                            final Config config = grailsApplication.getConfig();
+                            if (config.containsKey(pluginSpecificConfigProperty)) {
+                                shouldApplyPluginPrefix = config.getProperty(pluginSpecificConfigProperty, Boolean.class, false);
                             } else {
-                                shouldApplyPluginPrefix = Boolean.TRUE.equals(flatConfig.get("grails.gorm.table.prefix.enabled"));
+                                shouldApplyPluginPrefix = config.getProperty("grails.gorm.table.prefix.enabled", Boolean.class, false);
                             }
                         }
                         if (shouldApplyPluginPrefix) {
@@ -1244,7 +1249,7 @@
             Object o = GrailsClassUtils.getStaticPropertyValue(domainClass.getClazz(), GrailsDomainClassProperty.MAPPING);
             if (o != null || defaultMapping != null) {
                 HibernateMappingBuilder builder = new HibernateMappingBuilder(domainClass.getFullName());
-                GrailsApplication application = domainClass.getGrailsApplication();
+                GrailsApplication application = domainClass.getApplication();
                 ApplicationContext ctx = null;
                 if (application != null) {
                     ctx = application.getMainContext();
@@ -1328,7 +1333,7 @@
      * @param theClass The domain class in question
      * @return A Mapping object or null
      */
-    public Mapping getMapping(Class<?> theClass) {
+    public static Mapping getMapping(Class<?> theClass) {
         return theClass == null ? null : MAPPING_CACHE.get(theClass);
     }
 
@@ -1338,7 +1343,7 @@
      * @param domainClass The domain class in question
      * @return A Mapping object or null
      */
-    public Mapping getMapping(GrailsDomainClass domainClass) {
+    public static Mapping getMapping(GrailsDomainClass domainClass) {
         return domainClass == null ? null : MAPPING_CACHE.get(domainClass.getClazz());
     }
 
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainConfiguration.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainConfiguration.java
index c8d8ecd..f52a226 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainConfiguration.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainConfiguration.java
@@ -14,8 +14,9 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
+
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClass;
 
 /**
  * @author Graeme Rocher
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateNamedQueriesBuilder.groovy b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateNamedQueriesBuilder.groovy
index a6ae77d..f6966f9 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateNamedQueriesBuilder.groovy
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateNamedQueriesBuilder.groovy
@@ -15,13 +15,13 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg
 
+import grails.core.GrailsDomainClass
 import grails.util.GrailsNameUtils
 import groovy.lang.Closure;
 
 import java.lang.reflect.Modifier
 import java.util.List;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.grails.datastore.gorm.finders.FinderMethod
 import org.grails.datastore.gorm.query.NamedQueriesBuilder
 import org.grails.datastore.mapping.model.PersistentEntity;
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtilities.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtilities.java
index 2f0933e..c20d45f 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtilities.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtilities.java
@@ -2,8 +2,8 @@
 
 import java.util.List;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import org.codehaus.groovy.grails.orm.hibernate.AbstractGrailsHibernateDomainClass;
 
 public class HibernateUtilities {
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsHibernateException.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsHibernateException.java
index 545d273..62cfdd2 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsHibernateException.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsHibernateException.java
@@ -15,7 +15,8 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.exceptions;
 
-import org.codehaus.groovy.grails.exceptions.GrailsException;
+
+import org.grails.core.exceptions.GrailsException;
 
 /**
  * Base exception class for errors related to Hibernate configuration in Grails.
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsQueryException.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsQueryException.java
index e66724f..d8ba3f7 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsQueryException.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/exceptions/GrailsQueryException.java
@@ -15,7 +15,8 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.exceptions;
 
-import org.codehaus.groovy.grails.exceptions.GrailsException;
+
+import org.grails.core.exceptions.GrailsException;
 
 /**
  * Base exception class for errors related to Domain class queries in Grails.
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/SimpleHibernateProxyHandler.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/SimpleHibernateProxyHandler.java
new file mode 100644
index 0000000..bd6f2dc
--- /dev/null
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/SimpleHibernateProxyHandler.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2004-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.grails.orm.hibernate.proxy;
+
+
+import grails.core.support.proxy.EntityProxyHandler;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovySystem;
+import org.grails.datastore.mapping.reflect.ClassPropertyFetcher;
+import org.hibernate.Hibernate;
+import org.hibernate.proxy.HibernateProxy;
+import org.hibernate.proxy.HibernateProxyHelper;
+import org.hibernate.proxy.LazyInitializer;
+
+/**
+ * Implementation of the ProxyHandler interface for Hibernate.
+ *
+ * @author Graeme Rocher
+ * @since 1.2.2
+ */
+public class SimpleHibernateProxyHandler implements EntityProxyHandler {
+
+    public boolean isInitialized(Object o) {
+        if (o instanceof HibernateProxy) {
+            return !((HibernateProxy)o).getHibernateLazyInitializer().isUninitialized();
+        }
+        return true;
+    }
+
+    public boolean isInitialized(Object obj, String associationName) {
+        try {
+            Object proxy = ClassPropertyFetcher.forClass(obj.getClass()).getPropertyValue(obj, associationName);
+            return Hibernate.isInitialized(proxy);
+        }
+        catch (RuntimeException e) {
+            return false;
+        }
+    }
+
+    public Object unwrapIfProxy(Object instance) {
+        if (instance instanceof HibernateProxy) {
+            final HibernateProxy proxy = (HibernateProxy)instance;
+            return unwrapProxy(proxy);
+        }
+        return instance;
+    }
+
+    public Object unwrapProxy(final HibernateProxy proxy) {
+        final LazyInitializer lazyInitializer = proxy.getHibernateLazyInitializer();
+        if (lazyInitializer.isUninitialized()) {
+            lazyInitializer.initialize();
+        }
+        final Object obj = lazyInitializer.getImplementation();
+        if (obj != null) {
+            ensureCorrectGroovyMetaClass(obj, obj.getClass());
+        }
+        return obj;
+    }
+
+    /**
+     * Ensures the meta class is correct for a given class
+     *
+     * @param target The GroovyObject
+     * @param persistentClass The persistent class
+     */
+    private static void ensureCorrectGroovyMetaClass(Object target, Class<?> persistentClass) {
+        if (target instanceof GroovyObject) {
+            GroovyObject go = ((GroovyObject)target);
+            if (!go.getMetaClass().getTheClass().equals(persistentClass)) {
+                go.setMetaClass(GroovySystem.getMetaClassRegistry().getMetaClass(persistentClass));
+            }
+        }
+    }
+
+
+    public HibernateProxy getAssociationProxy(Object obj, String associationName) {
+        try {
+            Object proxy = ClassPropertyFetcher.forClass(obj.getClass()).getPropertyValue(obj, associationName);
+            if (proxy instanceof HibernateProxy) {
+                return (HibernateProxy) proxy;
+            }
+            return null;
+        }
+        catch (RuntimeException e) {
+            return null;
+        }
+    }
+
+    public boolean isProxy(Object o) {
+        return (o instanceof HibernateProxy);
+    }
+
+    public void initialize(Object o) {
+        if (o instanceof HibernateProxy) {
+            final LazyInitializer hibernateLazyInitializer = ((HibernateProxy)o).getHibernateLazyInitializer();
+            if (hibernateLazyInitializer.isUninitialized()) {
+                hibernateLazyInitializer.initialize();
+            }
+        }
+    }
+
+    public Object getProxyIdentifier(Object o) {
+        if (o instanceof HibernateProxy) {
+            return ((HibernateProxy)o).getHibernateLazyInitializer().getIdentifier();
+        }
+        return null;
+    }
+
+    public Class<?> getProxiedClass(Object o) {
+        return HibernateProxyHelper.getClassWithoutInitializingProxy(o);
+    }
+}
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateCriteriaBuilder.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateCriteriaBuilder.java
index 906e42f..ba69ae8 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateCriteriaBuilder.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateCriteriaBuilder.java
@@ -1,10 +1,9 @@
 package org.codehaus.groovy.grails.orm.hibernate.query;
 
+import grails.core.GrailsApplication;
 import grails.util.CollectionUtils;
+import grails.util.GrailsClassUtils;
 import groovy.lang.*;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
 import org.grails.datastore.mapping.query.api.*;
 import org.hibernate.*;
 import org.hibernate.Criteria;
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateQuery.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateQuery.java
index 2d5cf89..c930706 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateQuery.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/AbstractHibernateQuery.java
@@ -21,22 +21,27 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.persistence.FetchType;
 
+import grails.core.support.proxy.ProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateSession;
 import org.codehaus.groovy.grails.orm.hibernate.IHibernateTemplate;
+import org.codehaus.groovy.grails.orm.hibernate.cfg.AbstractGrailsDomainBinder;
+import org.codehaus.groovy.grails.orm.hibernate.cfg.Mapping;
+import org.codehaus.groovy.grails.orm.hibernate.proxy.SimpleHibernateProxyHandler;
+import org.grails.datastore.gorm.finders.DynamicFinder;
 import org.grails.datastore.gorm.query.criteria.DetachedAssociationCriteria;
 import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.model.PersistentProperty;
 import org.grails.datastore.mapping.model.types.Association;
+import org.grails.datastore.mapping.model.types.Embedded;
 import org.grails.datastore.mapping.query.AssociationQuery;
 import org.grails.datastore.mapping.query.Query;
 import org.grails.datastore.mapping.query.api.QueryableCriteria;
 import org.grails.datastore.mapping.query.criteria.FunctionCallingCriterion;
-import org.hibernate.Criteria;
-import org.hibernate.FetchMode;
-import org.hibernate.SessionFactory;
+import org.hibernate.*;
 import org.hibernate.criterion.*;
 import org.hibernate.dialect.Dialect;
 import org.hibernate.dialect.function.SQLFunction;
@@ -63,6 +68,7 @@
     protected static final String ALIAS = "_alias";
     protected static ConversionService conversionService = new DefaultConversionService();
     protected static Field opField = ReflectionUtils.findField(SimpleExpression.class, "op");
+    private static final Map<String, Boolean> JOIN_STATUS_CACHE = new ConcurrentHashMap<String, Boolean>();
     static {
         ReflectionUtils.makeAccessible(opField);
     }
@@ -77,10 +83,15 @@
     protected LinkedList<PersistentEntity> entityStack = new LinkedList<PersistentEntity>();
     protected LinkedList<Association> associationStack = new LinkedList<Association>();
     protected LinkedList aliasInstanceStack = new LinkedList();
+    private boolean hasJoins = false;
+    protected ProxyHandler proxyHandler = new SimpleHibernateProxyHandler();
 
     protected AbstractHibernateQuery(Criteria criteria, AbstractHibernateSession session, PersistentEntity entity) {
         super(session, entity);
         this.criteria = criteria;
+        if(entity != null) {
+            initializeJoinStatus();
+        }
     }
 
     protected AbstractHibernateQuery(DetachedCriteria criteria) {
@@ -88,6 +99,16 @@
         this.detachedCriteria = criteria;
     }
 
+    private void initializeJoinStatus() {
+        Boolean cachedStatus = JOIN_STATUS_CACHE.get(entity.getName());
+        if(cachedStatus != null) hasJoins = cachedStatus;
+        else {
+            for(Association a : entity.getAssociations()) {
+                if( a.getFetchStrategy() == FetchType.EAGER ) hasJoins = true;
+            }
+        }
+    }
+
     protected AbstractHibernateQuery(Criteria subCriteria, AbstractHibernateSession session, PersistentEntity associatedEntity, String newAlias) {
         this(subCriteria, session, associatedEntity);
         alias = newAlias;
@@ -494,24 +515,88 @@
     }
 
     @Override
+    public Query cache(boolean cache) {
+        criteria.setCacheable(true);
+
+        return super.cache(cache);
+    }
+
+    @Override
+    public Query lock(boolean lock) {
+        criteria.setCacheable(false);
+        criteria.setLockMode(LockMode.PESSIMISTIC_WRITE);
+        return super.lock(lock);
+    }
+
+    @Override
     public Query order(Order order) {
         super.order(order);
-        if(criteria != null) {
 
-            criteria.addOrder(order.getDirection() == Order.Direction.ASC ?
-                    org.hibernate.criterion.Order.asc(calculatePropertyName(order.getProperty())) :
-                    org.hibernate.criterion.Order.desc(calculatePropertyName(order.getProperty())));
-        }else if(detachedCriteria != null) {
-            detachedCriteria.addOrder(order.getDirection() == Order.Direction.ASC ?
-                    org.hibernate.criterion.Order.asc(calculatePropertyName(order.getProperty())) :
-                    org.hibernate.criterion.Order.desc(calculatePropertyName(order.getProperty())));
+        String property = order.getProperty();
+
+        int i = property.indexOf('.');
+        if(i > -1) {
+            String sortHead = property.substring(0,i);
+            String sortTail = property.substring(i + 1);
+
+            PersistentProperty persistentProperty = entity.getPropertyByName(sortHead);
+
+            if(persistentProperty instanceof Association) {
+                Association a = (Association) persistentProperty;
+                if(persistentProperty instanceof Embedded) {
+                    addSimpleOrder(order, property);
+                }
+                else {
+                    if(criteria != null) {
+                        Criteria subCriteria = criteria.createCriteria(sortHead);
+                        addOrderToCriteria(subCriteria, sortTail, order);
+                    }
+                    else if(detachedCriteria != null) {
+                        DetachedCriteria subDetachedCriteria = detachedCriteria.createCriteria(sortHead);
+                        addOrderToDetachedCriteria(subDetachedCriteria, sortTail, order);
+                    }
+                }
+            }
 
         }
+        else {
+            addSimpleOrder(order, property);
+        }
+
         return this;
     }
 
+    private void addSimpleOrder(Order order, String property) {
+        Criteria c = criteria;
+        if(c != null) {
+            addOrderToCriteria(c, property, order);
+        }else {
+            DetachedCriteria dc = detachedCriteria;
+            addOrderToDetachedCriteria(dc, property, order);
+        }
+    }
+
+    private void addOrderToDetachedCriteria(DetachedCriteria dc, String property, Order order) {
+        if(dc != null) {
+            org.hibernate.criterion.Order hibernateOrder = order.getDirection() == Order.Direction.ASC ?
+                    org.hibernate.criterion.Order.asc(calculatePropertyName(property)) :
+                    org.hibernate.criterion.Order.desc(calculatePropertyName(property));
+            dc.addOrder(order.isIgnoreCase() ? hibernateOrder.ignoreCase() : hibernateOrder);
+
+        }
+    }
+
+    private void addOrderToCriteria(Criteria c, String property, Order order) {
+        org.hibernate.criterion.Order hibernateOrder = order.getDirection() == Order.Direction.ASC ?
+                org.hibernate.criterion.Order.asc(calculatePropertyName(property)) :
+                org.hibernate.criterion.Order.desc(calculatePropertyName(property));
+
+        c.addOrder(order.isIgnoreCase() ? hibernateOrder.ignoreCase() : hibernateOrder);
+    }
+
     @Override
     public Query join(String property) {
+        this.hasJoins = true;
         if(criteria != null)
             criteria.setFetchMode(property, FetchMode.JOIN);
         else if(detachedCriteria != null)
@@ -521,6 +606,7 @@
 
     @Override
     public Query select(String property) {
+        this.hasJoins = true;
         if(criteria != null)
             criteria.setFetchMode(property, FetchMode.SELECT);
         else if(detachedCriteria != null)
@@ -536,17 +622,37 @@
         if (hibernateProjectionList != null) {
             org.hibernate.criterion.ProjectionList projectionList = hibernateProjectionList.getHibernateProjectionList();
             projectionLength = projectionList.getLength();
-            criteria.setProjection(projectionList);
+            if(projectionLength > 0) {
+                criteria.setProjection(projectionList);
+            }
         }
 
         if (projectionLength < 2) {
             criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
         }
 
+        applyDefaultSortOrderAndCaching();
         applyFetchStrategies();
+
+
         return criteria.list();
     }
 
+    protected void applyDefaultSortOrderAndCaching() {
+        if(this.orderBy.isEmpty() && entity != null) {
+            Mapping mapping = AbstractGrailsDomainBinder.getMapping(entity.getJavaClass());
+            if(mapping != null) {
+                if(queryCache == null && mapping.getCache() != null && mapping.getCache().isEnabled()) {
+                    criteria.setCacheable(true);
+                }
+
+                Map sortMap = mapping.getSort().getNamesAndDirections();
+                DynamicFinder.applySortForMap(this, sortMap, true);
+
+            }
+        }
+    }
+
     protected void applyFetchStrategies() {
         for (Map.Entry<String, FetchType> entry : fetchStrategies.entrySet()) {
             switch(entry.getValue()) {
@@ -579,10 +685,31 @@
             criteria.setProjection(hibernateProjectionList.getHibernateProjectionList());
         }
         criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
+        applyDefaultSortOrderAndCaching();
         applyFetchStrategies();
-        return criteria.uniqueResult();
+
+        if(hasJoins) {
+            try {
+                return proxyHandler.unwrapIfProxy(criteria.uniqueResult());
+            } catch (NonUniqueResultException e) {
+                return singleResultViaListCall();
+            }
+        }
+        else {
+            return singleResultViaListCall();
+        }
     }
 
+    private Object singleResultViaListCall() {
+        criteria.setMaxResults(1);
+        List results = criteria.list();
+        if(results.size()>0) {
+            return proxyHandler.unwrapIfProxy(results.get(0));
+        }
+        return null;
+    }
+
+
     @Override
     protected List executeQuery(PersistentEntity entity, Junction criteria) {
         return list();
@@ -779,6 +906,19 @@
         }
 
         @Override
+        public Query order(Order order) {
+
+            Order.Direction direction = order.getDirection();
+            switch(direction) {
+                case ASC:
+                    assocationCriteria.addOrder(org.hibernate.criterion.Order.asc(order.getProperty()));
+                case DESC:
+                    assocationCriteria.addOrder(org.hibernate.criterion.Order.desc(order.getProperty()));
+            }
+            return super.order(order);
+        }
+
+        @Override
         public Query isEmpty(String property) {
             org.hibernate.criterion.Criterion criterion = Restrictions.isEmpty(calculatePropertyName(property));
             addToCriteria(criterion);
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/GrailsHibernateQueryUtils.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/GrailsHibernateQueryUtils.java
new file mode 100644
index 0000000..78287b9
--- /dev/null
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/query/GrailsHibernateQueryUtils.java
@@ -0,0 +1,217 @@
+package org.codehaus.groovy.grails.orm.hibernate.query;
+
+import grails.util.GrailsClassUtils;
+import org.codehaus.groovy.grails.orm.hibernate.cfg.AbstractGrailsDomainBinder;
+import org.codehaus.groovy.grails.orm.hibernate.cfg.Mapping;
+import org.grails.datastore.gorm.finders.DynamicFinder;
+import org.grails.datastore.mapping.model.PersistentEntity;
+import org.grails.datastore.mapping.model.PersistentProperty;
+import org.grails.datastore.mapping.model.types.Association;
+import org.grails.datastore.mapping.model.types.Embedded;
+import org.hibernate.Criteria;
+import org.hibernate.FetchMode;
+import org.hibernate.FlushMode;
+import org.hibernate.LockMode;
+import org.hibernate.criterion.Order;
+import org.springframework.core.convert.ConversionService;
+import org.springframework.util.ReflectionUtils;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+
+/**
+ * Utility methods for configuring Hibernate queries
+ *
+ * @author Graeme Rocher
+ * @since 4.0
+ */
+public class GrailsHibernateQueryUtils {
+
+    /**
+     * Populates criteria arguments for the given target class and arguments map
+     *
+     * @param entity The {@link org.grails.datastore.mapping.model.PersistentEntity} instance
+     * @param c The criteria instance
+     * @param argMap The arguments map
+     */
+    @SuppressWarnings("rawtypes")
+    public static void populateArgumentsForCriteria(PersistentEntity entity, Criteria c, Map argMap, ConversionService conversionService, boolean useDefaultMapping) {
+        Integer maxParam = null;
+        Integer offsetParam = null;
+        if (argMap.containsKey(DynamicFinder.ARGUMENT_MAX)) {
+            maxParam = conversionService.convert(argMap.get(DynamicFinder.ARGUMENT_MAX),Integer.class);
+        }
+        if (argMap.containsKey(DynamicFinder.ARGUMENT_OFFSET)) {
+            offsetParam = conversionService.convert(argMap.get(DynamicFinder.ARGUMENT_OFFSET),Integer.class);
+        }
+        if (argMap.containsKey(DynamicFinder.ARGUMENT_FETCH_SIZE)) {
+            c.setFetchSize(conversionService.convert(argMap.get(DynamicFinder.ARGUMENT_FETCH_SIZE),Integer.class));
+        }
+        if (argMap.containsKey(DynamicFinder.ARGUMENT_TIMEOUT)) {
+            c.setTimeout(conversionService.convert(argMap.get(DynamicFinder.ARGUMENT_TIMEOUT),Integer.class));
+        }
+        if (argMap.containsKey(DynamicFinder.ARGUMENT_FLUSH_MODE)) {
+            c.setFlushMode(convertFlushMode(argMap.get(DynamicFinder.ARGUMENT_FLUSH_MODE)));
+        }
+        if (argMap.containsKey(DynamicFinder.ARGUMENT_READ_ONLY)) {
+            c.setReadOnly(GrailsClassUtils.getBooleanFromMap(DynamicFinder.ARGUMENT_READ_ONLY, argMap));
+        }
+        String orderParam = (String)argMap.get(DynamicFinder.ARGUMENT_ORDER);
+        Object fetchObj = argMap.get(DynamicFinder.ARGUMENT_FETCH);
+        if (fetchObj instanceof Map) {
+            Map fetch = (Map)fetchObj;
+            for (Object o : fetch.keySet()) {
+                String associationName = (String) o;
+                c.setFetchMode(associationName, getFetchMode(fetch.get(associationName)));
+            }
+        }
+
+        final int max = maxParam == null ? -1 : maxParam;
+        final int offset = offsetParam == null ? -1 : offsetParam;
+        if (max > -1) {
+            c.setMaxResults(max);
+        }
+        if (offset > -1) {
+            c.setFirstResult(offset);
+        }
+        if (GrailsClassUtils.getBooleanFromMap(DynamicFinder.ARGUMENT_LOCK, argMap)) {
+            c.setLockMode(LockMode.PESSIMISTIC_WRITE);
+            c.setCacheable(false);
+        }
+        else {
+            if (argMap.containsKey(DynamicFinder.ARGUMENT_CACHE)) {
+                c.setCacheable(GrailsClassUtils.getBooleanFromMap(DynamicFinder.ARGUMENT_CACHE, argMap));
+            } else {
+                cacheCriteriaByMapping(entity.getJavaClass(), c);
+            }
+        }
+
+        final Object sortObj = argMap.get(DynamicFinder.ARGUMENT_SORT);
+        if (sortObj != null) {
+            boolean ignoreCase = true;
+            Object caseArg = argMap.get(DynamicFinder.ARGUMENT_IGNORE_CASE);
+            if (caseArg instanceof Boolean) {
+                ignoreCase = (Boolean) caseArg;
+            }
+            if (sortObj instanceof Map) {
+                Map sortMap = (Map) sortObj;
+                for (Object sort : sortMap.keySet()) {
+                    final String order = DynamicFinder.ORDER_DESC.equalsIgnoreCase((String) sortMap.get(sort)) ? DynamicFinder.ORDER_DESC : DynamicFinder.ORDER_ASC;
+                    addOrderPossiblyNested(c, entity, (String) sort, order, ignoreCase);
+                }
+            } else {
+                final String sort = (String) sortObj;
+                final String order = DynamicFinder.ORDER_DESC.equalsIgnoreCase(orderParam) ? DynamicFinder.ORDER_DESC : DynamicFinder.ORDER_ASC;
+                addOrderPossiblyNested( c, entity, sort, order, ignoreCase);
+            }
+        }
+        else if (useDefaultMapping) {
+            Mapping m = AbstractGrailsDomainBinder.getMapping(entity.getJavaClass());
+            if (m != null) {
+                Map sortMap = m.getSort().getNamesAndDirections();
+                for (Object sort : sortMap.keySet()) {
+                    final String order = DynamicFinder.ORDER_DESC.equalsIgnoreCase((String) sortMap.get(sort)) ? DynamicFinder.ORDER_DESC : DynamicFinder.ORDER_ASC;
+                    addOrderPossiblyNested(c, entity, (String) sort, order, true);
+                }
+            }
+        }
+    }
+
+    /**
+     * Add order to criteria, creating necessary subCriteria if nested sort property (ie. sort:'nested.property').
+     */
+    private static void addOrderPossiblyNested(Criteria c, PersistentEntity entity, String sort, String order, boolean ignoreCase) {
+        int firstDotPos = sort.indexOf(".");
+        if (firstDotPos == -1) {
+            addOrder(c, sort, order, ignoreCase);
+        } else { // nested property
+            String sortHead = sort.substring(0,firstDotPos);
+            String sortTail = sort.substring(firstDotPos+1);
+            PersistentProperty property = entity.getPropertyByName(sortHead);
+            if (property instanceof Embedded) {
+                // embedded objects cannot reference entities (at time of writing), so no more recursion needed
+                addOrder(c, sort, order, ignoreCase);
+            } else if(property instanceof Association) {
+                Association a = (Association) property;
+                Criteria subCriteria = c.createCriteria(sortHead);
+                PersistentEntity associatedEntity = a.getAssociatedEntity();
+                Class<?> propertyTargetClass = associatedEntity.getJavaClass();
+                cacheCriteriaByMapping(propertyTargetClass, subCriteria);
+                addOrderPossiblyNested( subCriteria, associatedEntity, sortTail, order, ignoreCase); // Recurse on nested sort
+            }
+        }
+    }
+
+    /**
+     * Configures the criteria instance to cache based on the configured mapping.
+     *
+     * @param targetClass The target class
+     * @param criteria The criteria
+     */
+    private static void cacheCriteriaByMapping(Class<?> targetClass, Criteria criteria) {
+        Mapping m = AbstractGrailsDomainBinder.getMapping(targetClass);
+        if (m != null && m.getCache() != null && m.getCache().getEnabled()) {
+            criteria.setCacheable(true);
+        }
+    }
+
+    private static FlushMode convertFlushMode(Object object) {
+        if (object == null) {
+            return null;
+        }
+        if (object instanceof FlushMode) {
+            return (FlushMode)object;
+        }
+        return FlushModeConverter.valueOf(object.toString());
+    }
+    /**
+     * Add order directly to criteria.
+     */
+    private static void addOrder(Criteria c, String sort, String order, boolean ignoreCase) {
+        if (DynamicFinder.ORDER_DESC.equals(order)) {
+            c.addOrder(ignoreCase ? Order.desc(sort).ignoreCase() : Order.desc(sort));
+        }
+        else {
+            c.addOrder(ignoreCase ? Order.asc(sort).ignoreCase() : Order.asc(sort));
+        }
+    }
+
+    /**
+     * Retrieves the fetch mode for the specified instance; otherwise returns the default FetchMode.
+     *
+     * @param object The object, converted to a string
+     * @return The FetchMode
+     */
+    public static FetchMode getFetchMode(Object object) {
+        String name = object != null ? object.toString() : "default";
+        if (name.equalsIgnoreCase(FetchMode.JOIN.toString()) || name.equalsIgnoreCase("eager")) {
+            return FetchMode.JOIN;
+        }
+        if (name.equalsIgnoreCase(FetchMode.SELECT.toString()) || name.equalsIgnoreCase("lazy")) {
+            return FetchMode.SELECT;
+        }
+        return FetchMode.DEFAULT;
+    }
+
+    static class FlushModeConverter {
+        static Method conversionMethod;
+        static {
+            try {
+                conversionMethod = ReflectionUtils.findMethod(FlushMode.class, "parse", String.class);
+            } catch(Throwable t) {
+                conversionMethod = ReflectionUtils.findMethod(FlushMode.class, "valueOf", String.class);
+            }
+
+            ReflectionUtils.makeAccessible(conversionMethod);
+        }
+
+        static FlushMode valueOf(String str) {
+            try {
+                return (FlushMode)conversionMethod.invoke(FlushMode.class, str);
+            } catch (Throwable t) {
+                return FlushMode.COMMIT;
+            }
+        }
+    }
+}
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractAggregatePersistenceContextInterceptor.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractAggregatePersistenceContextInterceptor.java
index 1d5f063..b1a550a 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractAggregatePersistenceContextInterceptor.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractAggregatePersistenceContextInterceptor.java
@@ -18,7 +18,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor;
+import grails.persistence.support.PersistenceContextInterceptor;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractMultipleDataSourceAggregatePersistenceContextInterceptor.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractMultipleDataSourceAggregatePersistenceContextInterceptor.java
index 522d74e..4488f9b 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractMultipleDataSourceAggregatePersistenceContextInterceptor.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/AbstractMultipleDataSourceAggregatePersistenceContextInterceptor.java
@@ -15,29 +15,38 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
+import grails.config.Config;
+import grails.core.GrailsDomainClassProperty;
+import grails.core.support.GrailsConfigurationAware;
+import grails.persistence.support.PersistenceContextInterceptor;
 import grails.util.Holders;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor;
 import org.hibernate.SessionFactory;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
 
 /**
- * Abstract implementation of the {@link org.codehaus.groovy.grails.support.PersistenceContextInterceptor} interface that supports multiple data sources
+ * Abstract implementation of the {@link grails.persistence.support.PersistenceContextInterceptor} interface that supports multiple data sources
  *
  * @author Graeme Rocher
  * @since 2.0.7
  */
-public abstract class AbstractMultipleDataSourceAggregatePersistenceContextInterceptor implements PersistenceContextInterceptor, InitializingBean, ApplicationContextAware {
+public abstract class AbstractMultipleDataSourceAggregatePersistenceContextInterceptor implements PersistenceContextInterceptor, InitializingBean, ApplicationContextAware, GrailsConfigurationAware {
 
     protected List<PersistenceContextInterceptor> interceptors = new ArrayList<PersistenceContextInterceptor>();
     protected ApplicationContext applicationContext;
+    protected Config config;
+
+
+    @Override
+    public void setConfiguration(Config co) {
+        this.config = co;
+    }
 
     public boolean isOpen() {
         for (PersistenceContextInterceptor interceptor : interceptors) {
@@ -132,13 +141,15 @@
 
     private List<String> aggregateDataSourceNames() {
         List<String> dataSourceNames = new ArrayList<String>();
-        Set<String> configKeys = Holders.getConfig().keySet();
-        if (configKeys.contains("dataSource") && applicationContext.containsBean("dataSource")) {
-            dataSourceNames.add(GrailsDomainClassProperty.DEFAULT_DATA_SOURCE);
-        }
-        for (String name : configKeys) {
-            if (name.startsWith("dataSource_") && applicationContext.containsBean(name)) {
-                dataSourceNames.add(name.replaceFirst("dataSource_", ""));
+        if(config != null && applicationContext != null) {
+            Set<String> configKeys = config.keySet();
+            if (configKeys.contains("dataSource") && applicationContext.containsBean("dataSource")) {
+                dataSourceNames.add(GrailsDomainClassProperty.DEFAULT_DATA_SOURCE);
+            }
+            for (String name : configKeys) {
+                if (name.startsWith("dataSource_") && applicationContext.containsBean(name)) {
+                    dataSourceNames.add(name.replaceFirst("dataSource_", ""));
+                }
             }
         }
         return dataSourceNames;
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateRuntimeUtils.groovy b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateRuntimeUtils.groovy
new file mode 100644
index 0000000..264efc4
--- /dev/null
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateRuntimeUtils.groovy
@@ -0,0 +1,130 @@
+package org.codehaus.groovy.grails.orm.hibernate.support
+
+import grails.core.GrailsDomainClassProperty
+import grails.core.support.proxy.ProxyHandler
+import grails.validation.ValidationErrors
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.grails.orm.hibernate.proxy.SimpleHibernateProxyHandler
+import org.codehaus.groovy.runtime.StringGroovyMethods
+import org.grails.datastore.mapping.model.PersistentEntity
+import org.grails.datastore.mapping.model.types.Association
+import org.grails.datastore.mapping.model.types.OneToOne
+import org.springframework.beans.BeanWrapper
+import org.springframework.beans.BeanWrapperImpl
+import org.springframework.core.convert.ConversionService
+import org.springframework.validation.Errors
+import org.springframework.validation.FieldError
+
+/**
+ * Utility methods used at runtime by the GORM for Hibernate implementation
+ *
+ * @author Graeme Rocher
+ * @since 4.0
+ */
+@CompileStatic
+class HibernateRuntimeUtils {
+    private static ProxyHandler proxyHandler = new SimpleHibernateProxyHandler();
+
+    /**
+     * Initializes the Errors property on target.  The target will be assigned a new
+     * Errors property.  If the target contains any binding errors, those binding
+     * errors will be copied in to the new Errors property.
+     *
+     * @param target object to initialize
+     * @return the new Errors object
+     */
+    public static Errors setupErrorsProperty(Object target) {
+        MetaClass mc = GroovySystem.metaClassRegistry.getMetaClass(target.getClass())
+
+        def errors = new ValidationErrors(target)
+
+        Errors originalErrors = (Errors) mc.getProperty(target, GrailsDomainClassProperty.ERRORS)
+        for (Object o in originalErrors.fieldErrors) {
+            FieldError fe = (FieldError)o
+            if (fe.isBindingFailure()) {
+                errors.addError(new FieldError(fe.getObjectName(),
+                        fe.field,
+                        fe.rejectedValue,
+                        fe.bindingFailure,
+                        fe.codes,
+                        fe.arguments,
+                        fe.defaultMessage))
+            }
+        }
+
+        mc.setProperty(target, GrailsDomainClassProperty.ERRORS, errors);
+        return errors;
+    }
+
+    public static void autoAssociateBidirectionalOneToOnes(PersistentEntity entity, Object target) {
+        for (Association association :  entity.associations) {
+            if (!(association instanceof OneToOne) || !association.bidirectional || !association.owningSide) {
+                continue
+            }
+
+            def propertyName = association.name
+            if (!proxyHandler.isInitialized(target, propertyName)) {
+                continue
+            }
+
+            def otherSide = association.inverseSide
+
+            if (otherSide == null) {
+                continue
+            }
+
+            BeanWrapper bean = new BeanWrapperImpl(target)
+            Object inverseObject = bean.getPropertyValue(propertyName)
+            if (inverseObject == null) {
+                continue
+            }
+
+            def otherSidePropertyName = otherSide.getName()
+            if (!proxyHandler.isInitialized(inverseObject, otherSidePropertyName)) {
+                continue
+            }
+
+            def inverseBean = new BeanWrapperImpl(inverseObject)
+            def propertyValue = inverseBean.getPropertyValue(otherSidePropertyName)
+            if (propertyValue == null) {
+                inverseBean.setPropertyValue(otherSidePropertyName, target)
+            }
+        }
+    }
+
+    static Object convertValueToType(Object passedValue, Class targetType, ConversionService conversionService) {
+        // workaround for GROOVY-6127, do not assign directly in parameters before it's fixed
+        Object value = passedValue
+        if(targetType != null && value != null && !(value in targetType)) {
+            if (value instanceof CharSequence) {
+                value = value.toString()
+                if(value in targetType) {
+                    return value
+                }
+            }
+            try {
+                if (value instanceof Number && (targetType==Long || targetType==Integer)) {
+                    if(targetType == Long) {
+                        value = ((Number)value).toLong()
+                    } else {
+                        value = ((Number)value).toInteger()
+                    }
+                } else if (value instanceof String && targetType in Number) {
+                    String strValue = value.trim()
+                    if(targetType == Long) {
+                        value = Long.parseLong(strValue)
+                    } else if (targetType == Integer) {
+                        value = Integer.parseInt(strValue)
+                    } else {
+                        value = StringGroovyMethods.asType(strValue, targetType)
+                    }
+                } else {
+                    value = conversionService.convert(value, targetType)
+                }
+            } catch (e) {
+                // ignore
+            }
+        }
+        return value
+    }
+}
diff --git a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/SessionFactoryAwarePersistenceContextInterceptor.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/SessionFactoryAwarePersistenceContextInterceptor.java
index 5f2c579..8cd1dbc 100644
--- a/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/SessionFactoryAwarePersistenceContextInterceptor.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/SessionFactoryAwarePersistenceContextInterceptor.java
@@ -15,16 +15,16 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor;
+import grails.persistence.support.PersistenceContextInterceptor;
 import org.hibernate.SessionFactory;
 
 /**
- * Interface for {@link org.codehaus.groovy.grails.support.PersistenceContextInterceptor} instances that are aware of the {@link org.hibernate.SessionFactory}
+ * Interface for {@link grails.persistence.support.PersistenceContextInterceptor} instances that are aware of the {@link org.hibernate.SessionFactory}
  *
  * @author Graeme Rocher
  * @since 2.0.7
  */
-public interface SessionFactoryAwarePersistenceContextInterceptor extends PersistenceContextInterceptor{
+public interface SessionFactoryAwarePersistenceContextInterceptor extends PersistenceContextInterceptor {
 
     void setSessionFactory(SessionFactory sessionFactory);
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java
similarity index 73%
rename from grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java
rename to grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java
index bc124ae..d7a645d 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java
@@ -1,5 +1,4 @@
-/*
- * Copyright 2004-2005 Graeme Rocher
+/* Copyright 2004-2005 Graeme Rocher
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,13 +14,13 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.validation;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClass;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractGrailsHibernateDomainClass;
+import org.codehaus.groovy.grails.orm.hibernate.IHibernateTemplate;
 import org.codehaus.groovy.grails.validation.AbstractConstraint;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.grails.core.lifecycle.ShutdownOperations;
 import org.hibernate.SessionFactory;
 import org.springframework.beans.BeansException;
 import org.springframework.context.ApplicationContext;
@@ -50,14 +49,7 @@
         this.applicationContext = applicationContext;
     }
 
-    public GrailsHibernateTemplate getHibernateTemplate() {
-        SessionFactory sf = sessionFactory.get();
-        if (sf == null) {
-            sf = applicationContext.getBean("sessionFactory", SessionFactory.class);
-        }
-        GrailsApplication app = applicationContext.getBean("grailsApplication", GrailsApplication.class);
-        return new GrailsHibernateTemplate(sf, app, GrailsHibernateTemplate.FLUSH_NEVER);
-    }
+    public abstract IHibernateTemplate getHibernateTemplate();
 
     /**
      * Returns whether the constraint supports being applied against the specified type;
@@ -74,7 +66,6 @@
      *
      * @return true if it is
      */
-    @Override
     public boolean isValid() {
         if (applicationContext.containsBean("sessionFactory")) {
             GrailsApplication grailsApplication = applicationContext.getBean(
@@ -83,8 +74,8 @@
                     DomainClassArtefactHandler.TYPE, constraintOwningClass.getName());
             if (domainClass != null) {
                 String mappingStrategy = domainClass.getMappingStrategy();
-                return mappingStrategy.equals(GrailsDomainClass.GORM) ||
-                       mappingStrategy.equals(GrailsHibernateDomainClass.HIBERNATE);
+                return mappingStrategy.equals(GrailsDomainClass.GORM)
+                    || mappingStrategy.equals(AbstractGrailsHibernateDomainClass.HIBERNATE);
             }
         }
         return false;
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java
similarity index 90%
rename from grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java
rename to grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java
index c3fe4ee..7335a91 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java
@@ -14,6 +14,7 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.validation;
 
+import org.codehaus.groovy.grails.orm.hibernate.IHibernateTemplate;
 import org.codehaus.groovy.grails.validation.Constraint;
 import org.springframework.context.ApplicationContextAware;
 import org.springframework.orm.hibernate3.HibernateTemplate;
@@ -31,5 +32,5 @@
      *
      * @return the template
      */
-    HibernateTemplate getHibernateTemplate();
+    IHibernateTemplate getHibernateTemplate();
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java
similarity index 97%
rename from grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java
rename to grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java
index 6535d91..4b13f44 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java
+++ b/grails-datastore-gorm-hibernate-core/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java
@@ -14,9 +14,9 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.validation;
 
-import org.codehaus.groovy.grails.exceptions.GrailsDomainException;
 import org.codehaus.groovy.grails.validation.Constraint;
 import org.codehaus.groovy.grails.validation.ConstraintFactory;
+import org.grails.core.exceptions.GrailsDomainException;
 import org.springframework.context.ApplicationContext;
 import org.springframework.util.Assert;
 
diff --git a/grails-datastore-gorm-hibernate/build.gradle b/grails-datastore-gorm-hibernate/build.gradle
index c450389..d7e1bc0 100644
--- a/grails-datastore-gorm-hibernate/build.gradle
+++ b/grails-datastore-gorm-hibernate/build.gradle
@@ -9,6 +9,12 @@
     optional("org.grails:grails-web:$grailsVersion") {
         transitive = false
     }
+    optional("org.grails:grails-web-common:$grailsVersion") {
+        transitive = false
+    }
+    optional("org.grails:grails-web-url-mappings:$grailsVersion") {
+        transitive = false
+    }
     optional("org.grails:grails-spring:$grailsVersion") {
         transitive = false
     }
@@ -60,4 +66,4 @@
 
 compileTestGroovy {
     groovyOptions.fork(memoryMaximumSize: '1024m')
-}
\ No newline at end of file
+}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy b/grails-datastore-gorm-hibernate/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy
index e7f3391..27ce185 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy
@@ -72,11 +72,11 @@
         super(persistentClasses.toList())
     }
 
-    HibernateDatastoreSpringInitializer(Properties hibernateProperties, Collection<Class> persistentClasses) {
+    HibernateDatastoreSpringInitializer(Map hibernateProperties, Collection<Class> persistentClasses) {
         super(hibernateProperties, persistentClasses)
     }
 
-    HibernateDatastoreSpringInitializer(Properties hibernateProperties, Class... persistentClasses) {
+    HibernateDatastoreSpringInitializer(Map hibernateProperties, Class... persistentClasses) {
         super(hibernateProperties, persistentClasses.toList())
     }
 
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/grails/plugin/hibernate3/HibernatePluginSupport.groovy b/grails-datastore-gorm-hibernate/src/main/groovy/grails/plugin/hibernate3/HibernatePluginSupport.groovy
index 265f2c6..6fb3b76 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/grails/plugin/hibernate3/HibernatePluginSupport.groovy
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/grails/plugin/hibernate3/HibernatePluginSupport.groovy
@@ -15,15 +15,14 @@
  */
 package grails.plugin.hibernate3
 
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
+import grails.validation.ConstrainedProperty
+import grails.validation.ConstraintsEvaluator
 import groovy.transform.CompileStatic
 import org.apache.commons.logging.Log
 import org.apache.commons.logging.LogFactory
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
-import org.codehaus.groovy.grails.commons.spring.DefaultRuntimeSpringConfiguration
-import org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator
-import org.codehaus.groovy.grails.commons.spring.RuntimeSpringConfiguration
 import org.codehaus.groovy.grails.orm.hibernate.ConfigurableLocalSessionFactoryBean
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTransactionManager
 import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
@@ -45,9 +44,10 @@
 import org.codehaus.groovy.grails.orm.hibernate.validation.HibernateDomainClassValidator
 import org.codehaus.groovy.grails.orm.hibernate.validation.PersistentConstraintFactory
 import org.codehaus.groovy.grails.orm.hibernate.validation.UniqueConstraint
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
-import org.codehaus.groovy.grails.validation.ConstraintsEvaluator
 import org.grails.datastore.mapping.model.MappingContext
+import org.grails.spring.DefaultRuntimeSpringConfiguration
+import org.grails.spring.RuntimeSpringConfiguration
+import org.grails.web.servlet.context.support.GrailsRuntimeConfigurator
 import org.hibernate.EmptyInterceptor
 import org.hibernate.cfg.ImprovedNamingStrategy
 import org.springframework.beans.factory.config.BeanDefinition
@@ -181,7 +181,7 @@
                         catch (Throwable t) {
                             hibConfig.cache.region.factory_class='net.sf.ehcache.hibernate.EhCacheRegionFactory'
                             log.error """WARNING: Your cache provider is set to '${cacheProvider}' in DataSource.groovy, however the class for this provider cannot be found.
-Using Grails' default cache region factory: 'net.sf.ehcache.hibernate.EhCacheRegionFactory'"""
+Using Grails' default cache region factory: 'net.sf.ehcache.hibernate.EhCacheRegionFactory'""",t
                         }
                     } else if (!(hibConfig.cache.useCacheProvider) && (cacheProvider=='org.hibernate.cache.EhCacheProvider' || cacheProvider=='net.sf.ehcache.hibernate.EhCacheProvider')) {
                         hibConfig.cache.region.factory_class = 'net.sf.ehcache.hibernate.EhCacheRegionFactory'
@@ -199,7 +199,7 @@
                 }
                 catch (Throwable t) {
                     log.error """WARNING: You've configured a custom Hibernate naming strategy '$namingStrategy' in DataSource.groovy, however the class cannot be found.
-Using Grails' default naming strategy: '${ImprovedNamingStrategy.name}'"""
+Using Grails' default naming strategy: '${ImprovedNamingStrategy.name}'""",t
                     grailsDomainBinder.configureNamingStrategy datasourceName, ImprovedNamingStrategy
                 }
 
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java
index e2dda10..f80ee75 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java
@@ -14,6 +14,8 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClassProperty;
 import groovy.lang.GroovySystem;
 import groovy.lang.MetaClassRegistry;
 
@@ -27,8 +29,6 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.DefaultGrailsDomainConfiguration;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainConfiguration;
 import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor;
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java
index f8f9ac9..b591e99 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java
@@ -15,6 +15,8 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.config.Config;
+import grails.core.GrailsDomainClass;
 import groovy.lang.GroovySystem;
 import groovy.util.ConfigObject;
 
@@ -22,14 +24,13 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import org.codehaus.groovy.grails.commons.AnnotationDomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
 import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventListener;
 import org.codehaus.groovy.grails.orm.hibernate.support.SoftKey;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.grails.core.artefact.AnnotationDomainClassArtefactHandler;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.grails.datastore.gorm.timestamp.DefaultTimestampProvider;
 import org.grails.datastore.gorm.timestamp.TimestampProvider;
 import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent;
@@ -63,10 +64,10 @@
     
     private TimestampProvider timestampProvider = new DefaultTimestampProvider();
 
-    public EventTriggeringInterceptor(HibernateDatastore datastore, ConfigObject co) {
+    public EventTriggeringInterceptor(HibernateDatastore datastore, Config co) {
         super(datastore);
 
-        Object failOnErrorConfig = co.flatten().get("grails.gorm.failOnError");
+        Object failOnErrorConfig = co.getProperty("grails.gorm.failOnError", Object.class);
         if (failOnErrorConfig instanceof List) {
             failOnError = true;
             failOnErrorPackages = (List<?>)failOnErrorConfig;
@@ -248,5 +249,5 @@
 
     public void setTimestampProvider(TimestampProvider timestampProvider) {
         this.timestampProvider = timestampProvider;
-    }    
+    }
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java
index b266238..e35a3fc 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java
@@ -17,7 +17,7 @@
 
 import java.util.Collection;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
+import grails.core.GrailsApplication;
 import org.hibernate.EntityMode;
 import org.hibernate.MappingException;
 import org.hibernate.SessionFactory;
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java
index 7cf9acc..cfca5bd 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java
@@ -15,13 +15,16 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
+import grails.core.GrailsApplication;
+import groovy.lang.Closure;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.hibernate.Criteria;
 import org.hibernate.FlushMode;
 import org.hibernate.Query;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
+import org.springframework.orm.hibernate3.HibernateCallback;
 import org.springframework.orm.hibernate3.HibernateTemplate;
 import org.springframework.transaction.support.TransactionSynchronizationManager;
 
@@ -54,6 +57,12 @@
         setFlushMode(defaultFlushMode);
     }
 
+    @Override
+    public <T> T execute(Closure<T> callable) {
+        HibernateCallback<T> hibernateCallback = DefaultGroovyMethods.asType(callable, HibernateCallback.class);
+        return execute(hibernateCallback);
+    }
+
     private void initialize(GrailsApplication application) {
         setExposeNativeSession(true);
         if (application != null) {
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java
index 53ea8bf..d14b796 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java
@@ -14,12 +14,13 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.config.Config;
+import grails.core.GrailsApplication;
+import grails.core.support.GrailsApplicationAware;
 import groovy.util.ConfigObject;
 
 import java.util.Map;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware;
 import org.grails.datastore.mapping.core.Session;
 import org.grails.datastore.mapping.model.MappingContext;
 import org.hibernate.SessionFactory;
@@ -39,15 +40,15 @@
     private int defaultFlushMode;
     
     
-    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config) {
+    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config) {
         super(mappingContext, sessionFactory, config);
     }
-     
-    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config, ApplicationContext applicationContext) {
+
+    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config, ApplicationContext applicationContext) {
         this(mappingContext, sessionFactory, config, applicationContext, GrailsHibernateTemplate.FLUSH_AUTO);
     }
  
-    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config, ApplicationContext applicationContext, int defaultFlushMode) {
+    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config, ApplicationContext applicationContext, int defaultFlushMode) {
         super(mappingContext, sessionFactory, config, applicationContext);
         this.defaultFlushMode = defaultFlushMode;
     }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy
index a2a15ef..1a6451c 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy
@@ -14,29 +14,11 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
-import grails.util.GrailsNameUtils
+import grails.core.GrailsApplication
 import groovy.transform.CompileStatic
-import groovy.transform.TypeCheckingMode
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsClassUtils
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.CountByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllByBooleanPropertyPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByBooleanPropertyPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindOrCreateByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindOrSaveByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ListOrderByPersistentMethod
 import org.grails.datastore.gorm.GormInstanceApi
 import org.grails.datastore.gorm.GormStaticApi
 import org.grails.datastore.gorm.GormValidationApi
-import org.grails.datastore.gorm.finders.FinderMethod
-import org.grails.datastore.mapping.core.Datastore
-import org.grails.datastore.mapping.model.PersistentEntity
-import org.springframework.beans.BeanUtils
-import org.springframework.context.ApplicationContext
 import org.springframework.transaction.PlatformTransactionManager
 
 /**
@@ -53,19 +35,6 @@
         super(datastore, transactionManager, grailsApplication)
     }
 
-    protected List<FinderMethod> createDynamicFinders() {
-        HibernateDatastore hibernateDatastore = (HibernateDatastore)datastore
-        def sessionFactory = hibernateDatastore.sessionFactory
-        [new FindAllByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindAllByBooleanPropertyPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindOrCreateByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindOrSaveByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindByBooleanPropertyPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new CountByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new ListOrderByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader)]
-    }
-
     protected <D> GormValidationApi<D> getValidationApi(Class<D> cls) {
         new HibernateGormValidationApi<D>(cls, (HibernateDatastore)datastore, classLoader)
     }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy
index a6df315..20e21f6 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy
@@ -15,18 +15,17 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import groovy.transform.CompileStatic
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod
-import org.hibernate.LockMode
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.hibernate.FlushMode
+import org.hibernate.Session
 import org.hibernate.engine.EntityEntry
 import org.hibernate.engine.SessionImplementor
+import org.hibernate.engine.Status
 import org.hibernate.proxy.HibernateProxy
-import org.springframework.dao.DataAccessException
 
 /**
  * The implementation of the GORM instance API contract for Hibernate.
@@ -37,28 +36,23 @@
 @CompileStatic
 class HibernateGormInstanceApi<D> extends AbstractHibernateGormInstanceApi<D> {
 
-    protected SavePersistentMethod saveMethod
-    protected MergePersistentMethod mergeMethod
     protected GrailsHibernateTemplate hibernateTemplate
     protected InstanceApiHelper instanceApiHelper
 
     HibernateGormInstanceApi(Class<D> persistentClass, HibernateDatastore datastore, ClassLoader classLoader) {
-        super(persistentClass, datastore, classLoader)
+        super(persistentClass, datastore, classLoader, null)
 
-        def mappingContext = datastore.mappingContext
         def grailsApplication = datastore.getGrailsApplication()
         if (grailsApplication) {
             GrailsDomainClass domainClass = (GrailsDomainClass)grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, persistentClass.name)
             config = (Map)grailsApplication.getFlatConfig().get('grails.gorm')
-            saveMethod = new SavePersistentMethod(sessionFactory, classLoader, grailsApplication, domainClass, datastore)
-            mergeMethod = new MergePersistentMethod(sessionFactory, classLoader, grailsApplication, domainClass, datastore)
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, grailsApplication, datastore.getDefaultFlushMode())
-            cacheQueriesByDefault = GrailsHibernateUtil.isCacheQueriesByDefault(grailsApplication)
         }
         else {
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory)
             hibernateTemplate.setFlushMode(datastore.getDefaultFlushMode())
         }
+        super.hibernateTemplate = hibernateTemplate
         instanceApiHelper = new InstanceApiHelper(hibernateTemplate)
     }
 
@@ -142,107 +136,25 @@
     }
 
     @Override
-    D lock(D instance) {
-        hibernateTemplate.lock(instance, LockMode.UPGRADE)
-    }
+    void setObjectToReadWrite(Object target) {
+        hibernateTemplate.execute { Session session ->
+            if (session.contains(target) && proxyHandler.isInitialized(target)) {
+                SessionImplementor sessionImpl = (SessionImplementor) session;
+                EntityEntry ee = sessionImpl.persistenceContext.getEntry(target)
 
-    @Override
-    D refresh(D instance) {
-        hibernateTemplate.refresh(instance)
-        return instance
-    }
+                if (ee && ee.status == Status.READ_ONLY) {
+                    Object actualTarget = target
+                    if (target instanceof HibernateProxy) {
+                        actualTarget = ((HibernateProxy)target).hibernateLazyInitializer.implementation
+                    }
 
-    @Override
-    D save(D instance) {
-        if (saveMethod) {
-            return (D)saveMethod.invoke(instance, "save", EMPTY_ARRAY)
+                    session.setReadOnly actualTarget, false
+                    session.flushMode = FlushMode.AUTO
+                    incrementVersion target
+                }
+            }
+            return null
         }
-        else {
-            return super.save(instance)
-        }
-    }
-
-    D save(D instance, boolean validate) {
-        if (saveMethod) {
-            return (D)saveMethod.invoke(instance, "save", [validate] as Object[])
-        }
-        else {
-            return super.save(instance, validate)
-        }
-    }
-
-    @Override
-    D merge(D instance) {
-        if (mergeMethod) {
-            return (D)mergeMethod.invoke(instance, "merge", EMPTY_ARRAY)
-        }
-        else {
-            return super.merge(instance)
-        }
-    }
-
-    @Override
-    D merge(D instance, Map params) {
-        if (mergeMethod) {
-            return (D)mergeMethod.invoke(instance, "merge", [params] as Object[])
-        }
-        else {
-            return super.merge(instance, params)
-        }
-    }
-
-    @Override
-    D save(D instance, Map params) {
-        if (saveMethod) {
-            return (D)saveMethod.invoke(instance, "save", [params] as Object[])
-        }
-        return super.save(instance, params)
-    }
-
-    @Override
-    D attach(D instance) {
-        hibernateTemplate.lock(instance, LockMode.NONE)
-        return instance
-    }
-
-    @Override
-    void discard(D instance) {
-        hibernateTemplate.evict instance
-    }
-
-    @Override
-    void delete(D instance) {
-        boolean flush = shouldFlush()
-        try {
-            instanceApiHelper.delete instance, flush
-        }
-        catch (DataAccessException e) {
-            handleDataAccessException(hibernateTemplate, e)
-        }
-    }
-
-    @Override
-    void delete(D instance, Map params) {
-        boolean flush = shouldFlush(params)
-        try {
-            instanceApiHelper.delete instance, flush
-        }
-        catch (DataAccessException e) {
-            handleDataAccessException(hibernateTemplate, e)
-        }
-    }
-
-    @Override
-    boolean instanceOf(D instance, Class cls) {
-        if (instance instanceof HibernateProxy) {
-            return GrailsHibernateUtil.unwrapProxy(instance) in cls
-        }
-        return instance in cls
-    }
-
-    @Override
-    boolean isAttached(D instance) {
-        hibernateTemplate.contains instance
     }
 
     protected EntityEntry findEntityEntry(D instance, SessionImplementor session, boolean forDirtyCheck = true) {
@@ -258,22 +170,4 @@
         entry
     }
 
-    /**
-     * Session should no longer be flushed after a data access exception occurs (such a constriant violation)
-     */
-    protected void handleDataAccessException(GrailsHibernateTemplate template, DataAccessException e) {
-        try {
-            instanceApiHelper.setFlushModeManual()
-        }
-        finally {
-            throw e
-        }
-    }
-
-    protected boolean shouldFlush(Map map = [:]) {
-        if (map?.containsKey('flush')) {
-            return Boolean.TRUE == map.flush
-        }
-        return config?.autoFlush instanceof Boolean ? config.autoFlush : false
-    }
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy
index ba5e9fb..573e7b0 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy
@@ -15,32 +15,21 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
 import grails.orm.HibernateCriteriaBuilder
+import grails.orm.PagedResultList
+import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
-import groovy.transform.TypeCheckingMode
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.orm.hibernate.cfg.CompositeIdentity
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
-import org.codehaus.groovy.grails.orm.hibernate.cfg.HibernateUtils
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ExecuteQueryPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ExecuteUpdatePersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ListPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod
-import org.grails.datastore.gorm.GormStaticApi
+import org.codehaus.groovy.grails.orm.hibernate.query.GrailsHibernateQueryUtils
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.datastore.gorm.finders.DynamicFinder
 import org.grails.datastore.gorm.finders.FinderMethod
 import org.grails.datastore.mapping.query.api.BuildableCriteria as GrailsCriteria
 import org.hibernate.Criteria
 import org.hibernate.LockMode
 import org.hibernate.Session
 import org.hibernate.SessionFactory
-import org.hibernate.criterion.Projections
-import org.hibernate.criterion.Restrictions
-import org.hibernate.transform.DistinctRootEntityResultTransformer
 import org.springframework.core.convert.ConversionService
 import org.springframework.orm.hibernate3.HibernateCallback
 import org.springframework.orm.hibernate3.HibernateTemplate
@@ -56,150 +45,66 @@
  * @since 1.0
  */
 @CompileStatic
-class HibernateGormStaticApi<D> extends GormStaticApi<D> {
-    protected static final EMPTY_ARRAY = [] as Object[]
-
+class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> {
     protected GrailsHibernateTemplate hibernateTemplate
     protected SessionFactory sessionFactory
     protected ConversionService conversionService
     protected Class identityType
-    protected ListPersistentMethod listMethod
-    protected FindAllPersistentMethod findAllMethod
-    protected FindPersistentMethod findMethod
-    protected ExecuteQueryPersistentMethod executeQueryMethod
-    protected ExecuteUpdatePersistentMethod executeUpdateMethod
-    protected MergePersistentMethod mergeMethod
     protected ClassLoader classLoader
     protected GrailsApplication grailsApplication
-    protected GrailsDomainBinder grailsDomainBinder = new GrailsDomainBinder()
+    private HibernateGormInstanceApi<D> instanceApi
     protected int defaultFlushMode
 
     HibernateGormStaticApi(Class<D> persistentClass, HibernateDatastore datastore, List<FinderMethod> finders,
                 ClassLoader classLoader, PlatformTransactionManager transactionManager) {
-        super(persistentClass, datastore, finders, transactionManager)
+        super(persistentClass, datastore, finders, transactionManager, null)
         this.classLoader = classLoader
         sessionFactory = datastore.getSessionFactory()
         conversionService = datastore.mappingContext.conversionService
 
         identityType = persistentEntity.identity?.type
 
-        def mappingContext = datastore.mappingContext
         grailsApplication = datastore.getGrailsApplication()
         if (grailsApplication != null) {
             GrailsDomainClass domainClass = (GrailsDomainClass)grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, persistentClass.name)
             identityType = domainClass.identifier?.type
 
-            mergeMethod = new MergePersistentMethod(sessionFactory, classLoader, grailsApplication, domainClass, datastore)
-            listMethod = new ListPersistentMethod(grailsApplication, sessionFactory, classLoader, mappingContext.conversionService, datastore.getDefaultFlushMode())
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, grailsApplication, datastore.getDefaultFlushMode())
         } else {
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory)
             hibernateTemplate.setFlushMode(datastore.getDefaultFlushMode())
         }
-        
+        super.hibernateTemplate = hibernateTemplate
+
         this.defaultFlushMode = datastore.getDefaultFlushMode()
 
-        executeQueryMethod = new ExecuteQueryPersistentMethod(sessionFactory, classLoader, grailsApplication, conversionService, datastore.getDefaultFlushMode())
-        executeUpdateMethod = new ExecuteUpdatePersistentMethod(sessionFactory, classLoader, grailsApplication, datastore.getDefaultFlushMode())
-        findMethod = new FindPersistentMethod(sessionFactory, classLoader, grailsApplication, conversionService, datastore.getDefaultFlushMode())
-        findAllMethod = new FindAllPersistentMethod(sessionFactory, classLoader, grailsApplication, conversionService, datastore.getDefaultFlushMode())
+        instanceApi = new HibernateGormInstanceApi<>(persistentClass, datastore, classLoader)
     }
 
-
-//    /**
-//     * Property missing handling used to relay property access onto target entity for named queries etc.
-//     *
-//     * @param property The name of the property
-//     */
-//    @CompileStatic(TypeCheckingMode.SKIP)
-//    def propertyMissing(String property) {
-//        if(persistentClass.hasProperty(property)) {
-//            return this.persistentClass."$property"
-//        }
-//        else {
-//            throw new MissingPropertyException(property, HibernateGormStaticApi)
-//        }
-//    }
-
     @Override
-    D get(Serializable id) {
-        if (id || (id instanceof Number)) {
-            id = convertIdentifier(id)
-            D result = (D)hibernateTemplate.get((Class)persistentClass, id)
-            return (D)GrailsHibernateUtil.unwrapIfProxy(result)
+    List<D> list(Map params = Collections.emptyMap()) {
+        hibernateTemplate.execute { Session session ->
+            Criteria c = session.createCriteria(persistentEntity.javaClass)
+            hibernateTemplate.applySettings c
+
+            params = params ? new HashMap(params) : Collections.emptyMap()
+            setResultTransformer(c)
+            if(params.containsKey(DynamicFinder.ARGUMENT_MAX)) {
+
+                c.setMaxResults(Integer.MAX_VALUE)
+                GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, c, params, datastore.mappingContext.conversionService, true)
+                return new PagedResultList(hibernateTemplate, c)
+            }
+            else {
+                GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, c, params, datastore.mappingContext.conversionService, true)
+                return c.list()
+            }
         }
     }
 
-    protected Serializable convertIdentifier(Serializable id) {
-        (Serializable)HibernateUtils.convertValueToType(id, identityType, conversionService)
-    }
-
-    @Override
-    D read(Serializable id) {
-        if (id == null) {
-            return null
-        }
-
-        hibernateTemplate.execute({ Session session ->
-            def o = get(id)
-            if (o && session.contains(o)) {
-                session.setReadOnly(o, true)
-            }
-            return o
-        } as HibernateCallback)
-    }
-
-    @Override
-    D load(Serializable id) {
-        id = convertIdentifier(id)
-        if (id != null) {
-            return hibernateTemplate.load((Class)persistentClass, id)
-        }
-    }
-
-    @Override
-    List<D> getAll() {
-        (List<D>)hibernateTemplate.execute({ Session session ->
-            Criteria criteria = session.createCriteria(persistentClass)
-            hibernateTemplate.applySettings(criteria)
-            criteria.list()
-        } as HibernateCallback)
-    }
-
-    List<D> getAll(List ids) {
-        getAllInternal(ids)
-    }
-
-    List<D> getAll(Long... ids) {
-        getAllInternal(ids as List)
-    }
-
-    @Override
-    List<D> getAll(Serializable... ids) {
-        getAllInternal(ids as List)
-    }
-
-    protected List getAllInternal(List ids) {
-        if (!ids) return []
-
-        ids = ids.collect { convertIdentifier((Serializable)it) }
-
-        (List)hibernateTemplate.execute({Session session ->
-            def criteria = session.createCriteria(persistentClass)
-            hibernateTemplate.applySettings(criteria)
-            def identityName = persistentEntity.identity.name
-            criteria.add(Restrictions.'in'(identityName, ids))
-            def results = criteria.list()
-            def idsMap = [:]
-            for (object in results) {
-                idsMap[object[identityName]] = object
-            }
-            results.clear()
-            for (id in ids) {
-                results << idsMap[id]
-            }
-            results
-        } as HibernateCallback)
+    @CompileDynamic
+    protected void setResultTransformer(Criteria c) {
+        c.resultTransformer = Criteria.DISTINCT_ROOT_ENTITY
     }
 
     @Override
@@ -207,7 +112,6 @@
         def builder = new HibernateCriteriaBuilder(persistentClass, sessionFactory)
         builder.grailsApplication = grailsApplication
         builder.conversionService = conversionService
-        builder.defaultFlushMode = defaultFlushMode
         builder
     }
 
@@ -218,250 +122,8 @@
     }
 
     @Override
-    D merge(o) {
-        (D)mergeMethod.invoke(o, "merge", [] as Object[])
-    }
-
-    @Override
-    Integer count() {
-        (Integer)hibernateTemplate.execute({Session session ->
-            def criteria = session.createCriteria(persistentClass)
-            hibernateTemplate.applySettings(criteria)
-            criteria.setProjection(Projections.rowCount())
-            def num = criteria.uniqueResult()
-            num == null ? 0 : num
-        } as HibernateCallback)
-    }
-
-    @Override
-    boolean exists(Serializable id) {
-        id = convertIdentifier(id)
-        hibernateTemplate.execute({ Session session ->
-            Criteria criteria = session.createCriteria(persistentEntity.javaClass)
-            hibernateTemplate.applySettings(criteria)
-            criteria.add(Restrictions.idEq(id))
-                .setProjection(Projections.rowCount())
-                .uniqueResult()
-        } as HibernateCallback) == 1
-    }
-
-    @Override
-    List<D> list(Map params) {
-        (List<D>)listMethod.invoke(persistentClass, "list", [params] as Object[])
-    }
-
-    @Override
-    List<D> list() {
-        (List<D>)listMethod.invoke(persistentClass, "list", EMPTY_ARRAY)
-    }
-
-    @Override
-    List<D> findAll(example, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [example, args] as Object[])
-    }
-
-    @Override
-    D find(example, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [example, args] as Object[])
-    }
-
-    D first(Map m) {
-        def entityMapping = grailsDomainBinder.getMapping(persistentEntity.javaClass)
-        if (entityMapping?.identity instanceof CompositeIdentity) {
-            throw new UnsupportedOperationException('The first() method is not supported for domain classes that have composite keys.')
-        }
-        super.first(m)
-    }
-
-    D last(Map m) {
-        def entityMapping = grailsDomainBinder.getMapping(persistentEntity.javaClass)
-        if (entityMapping?.identity instanceof CompositeIdentity) {
-            throw new UnsupportedOperationException('The last() method is not supported for domain classes that have composite keys.')
-        }
-        super.last(m)
-    }
-
-    /**
-     * Finds a single result for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [foo:'bar], [max:10]) instead
-     */
-    @Deprecated
-    D find(String query, Map args, Integer max) {
-        (D)findMethod.invoke(persistentClass, "find", [query, args, max] as Object[])
-    }
-
-    /**
-     * Finds a single result for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @param offset The offset
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [foo:'bar], [max:10, offset:5]) instead
-     */
-    @Deprecated
-    D find(String query, Map args, Integer max, Integer offset) {
-        (D)findMethod.invoke(persistentClass, "find", [query, args, max, offset] as Object[])
-    }
-
-    /**
-     * Finds a single result for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [max:10]) instead
-     */
-    @Deprecated
-    D find(String query, Integer max) {
-        (D)findMethod.invoke(persistentClass, "find", [query, max] as Object[])
-    }
-
-    /**
-     * Finds a single result for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @param offset The offset to use
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [max:10, offset:5]) instead
-     */
-    @Deprecated
-    D find(String query, Integer max, Integer offset) {
-        (D)findMethod.invoke(persistentClass, "find", [query, max, offset] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [foo:'bar], [max:10]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Map args, Integer max) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, args, max] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @param offset The offset
-     *
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [foo:'bar], [max:10, offset:5]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Map args, Integer max, Integer offset) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, args, max, offset] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [max:10]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Integer max) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, max] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [max:10, offset:5]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Integer max, Integer offset) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, max, offset] as Object[])
-    }
-
-    @Override
-    List<D> findAllWhere(Map queryMap, Map args) {
-        if (!queryMap) return null
-        (List<D>)hibernateTemplate.execute({Session session ->
-            Map<String, Object> processedQueryMap = [:]
-            queryMap.each{ key, value -> processedQueryMap[key.toString()] = value }
-            Map queryArgs = filterQueryArgumentMap(processedQueryMap)
-            List<String> nullNames = removeNullNames(queryArgs)
-            Criteria criteria = session.createCriteria(persistentClass)
-            hibernateTemplate.applySettings(criteria)
-            criteria.add(Restrictions.allEq(queryArgs))
-            for (name in nullNames) {
-                criteria.add Restrictions.isNull(name)
-            }
-            criteria.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE)
-            criteria.list()
-        } as HibernateCallback)
-    }
-
-    @Override
-    D findWhere(Map queryMap, Map args) {
-        if (!queryMap) return null
-        (D)hibernateTemplate.execute({Session session ->
-            Map<String, Object> processedQueryMap = [:]
-            queryMap.each{ key, value -> processedQueryMap[key.toString()] = value }
-            Map queryArgs = filterQueryArgumentMap(processedQueryMap)
-            List<String> nullNames = removeNullNames(queryArgs)
-            Criteria criteria = session.createCriteria(persistentClass)
-            hibernateTemplate.applySettings(criteria)
-            criteria.add(Restrictions.allEq(queryArgs))
-            for (name in nullNames) {
-                criteria.add Restrictions.isNull(name)
-            }
-            criteria.setMaxResults(1)
-            GrailsHibernateUtil.unwrapIfProxy(criteria.uniqueResult())
-        } as HibernateCallback)
-    }
-
-    protected Map filterQueryArgumentMap(Map query) {
-        def queryArgs = [:]
-        for (entry in query.entrySet()) {
-            if (entry.value instanceof CharSequence) {
-                queryArgs[entry.key] = entry.value.toString()
-            }
-            else {
-                queryArgs[entry.key] = entry.value
-            }
-        }
-        return queryArgs
-    }
-
-    protected List<String> removeNullNames(Map query) {
-        List<String> nullNames = []
-        Set<String> allNames = new HashSet(query.keySet())
-        for (String name in allNames) {
-            if (query[name] == null) {
-                query.remove name
-                nullNames << name
-            }
-        }
-        nullNames
+    D merge( D o ) {
+        instanceApi.merge(o)
     }
 
     @Override
@@ -475,6 +137,44 @@
     }
 
     @Override
+    Integer executeUpdate(String query, Map params, Map args) {
+        def template = hibernateTemplate
+        return (Integer) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+            SessionFactoryUtils.applyTransactionTimeout q, template.sessionFactory
+
+
+            populateQueryArguments(q, params)
+            populateQueryArguments(q, args)
+            populateQueryWithNamedArguments(q, params)
+
+            return q.executeUpdate()
+        }
+    }
+
+    @Override
+    Integer executeUpdate(String query, Collection params, Map args) {
+        def template = hibernateTemplate
+        return (Integer) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+            SessionFactoryUtils.applyTransactionTimeout q, template.sessionFactory
+
+            params.eachWithIndex { val, int i ->
+                if (val instanceof CharSequence) {
+                    q.setParameter i, val.toString()
+                }
+                else {
+                    q.setParameter i, val
+                }
+            }
+            populateQueryArguments(q, args)
+            return q.executeUpdate()
+        }
+    }
+
+    @Override
     def withNewSession(Closure callable) {
         HibernateTemplate template  = new GrailsHibernateTemplate(sessionFactory, grailsApplication, defaultFlushMode)
         template.setExposeNativeSession(false)
@@ -511,112 +211,4 @@
         }
     }
 
-    @Override
-    List<D> executeQuery(String query) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query] as Object[])
-    }
-
-    List<D> executeQuery(String query, arg) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, arg] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Map args) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, args] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Map params, Map args) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, params, args] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Collection params) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, params] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Collection params, Map args) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, params, args] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Map args) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, args] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Map params, Map args) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, params, args] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Collection params) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, params] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Collection params, Map args) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, params, args] as Object[])
-    }
-
-    @Override
-    D find(String query) {
-        (D)findMethod.invoke(persistentClass, "find", [query] as Object[])
-    }
-
-    D find(String query, Object[] params) {
-        (D)findMethod.invoke(persistentClass, "find", [query, params] as Object[])
-    }
-
-    @Override
-    D find(String query, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [query, args] as Object[])
-    }
-
-    @Override
-    D find(String query, Map params, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [query, params, args] as Object[])
-    }
-
-    @Override
-    Object find(String query, Collection params) {
-        findMethod.invoke(persistentClass, "find", [query, params] as Object[])
-    }
-
-    @Override
-    D find(String query, Collection params, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [query, params, args] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, args] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Map params, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, params, args] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Collection params) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, params] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Collection params, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, params, args] as Object[])
-    }
-
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy
index 4fcb082..6881ddf 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy
@@ -17,22 +17,10 @@
 
 import groovy.transform.CompileStatic
 
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ValidatePersistentMethod
-
 @CompileStatic
 class HibernateGormValidationApi<D> extends AbstractHibernateGormValidationApi<D> {
 
-    ValidatePersistentMethod validateMethod
-
     HibernateGormValidationApi(Class<D> persistentClass, HibernateDatastore datastore, ClassLoader classLoader) {
         super(persistentClass, datastore, classLoader)
-
-        def mappingContext = datastore.mappingContext
-        def grailsApplication = datastore.grailsApplication
-        if (grailsApplication) {
-            def validator = mappingContext.getEntityValidator(mappingContext.getPersistentEntity(persistentClass.name))
-            validateMethod = new ValidatePersistentMethod(datastore.getSessionFactory(),
-                classLoader, grailsApplication, validator, datastore)
-        }
     }
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java
index 1e2ba28..dc9f96a 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java
@@ -21,10 +21,10 @@
 
 import javax.persistence.FlushModeType;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
+import grails.core.GrailsApplication;
+import grails.core.support.proxy.ProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.HibernateProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.query.HibernateQuery;
-import org.codehaus.groovy.grails.support.proxy.ProxyHandler;
 import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.query.Query;
 import org.grails.datastore.mapping.query.api.QueryableCriteria;
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java
index 7c8c9c1..6ed1806 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java
@@ -14,20 +14,25 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
+import grails.core.GrailsApplication;
+import grails.core.GrailsClass;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import groovy.lang.Closure;
 import groovy.util.Eval;
 
 import java.util.HashSet;
+import java.util.Properties;
 import java.util.Set;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwarePojoEntityTuplizer;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
 import org.hibernate.MappingException;
 import org.hibernate.cfg.Configuration;
 import org.hibernate.cfg.Mappings;
+import org.hibernate.cfg.Settings;
 
 /**
  * Creates runtime configuration mapping for the Grails domain classes
@@ -123,6 +128,20 @@
             }
         }
     }
+
+    @Override
+    public Settings buildSettings() {
+        Settings settings = super.buildSettings();
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
+
+    @Override
+    public Settings buildSettings(Properties props) throws HibernateException {
+        Settings settings = super.buildSettings(props);
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
     
     @Override
     protected void reset() {
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java
index a966725..693fc0e 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java
@@ -14,25 +14,23 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
+import grails.core.*;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.*;
+import org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwarePojoEntityTuplizer;
+import org.grails.core.artefact.AnnotationDomainClassArtefactHandler;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.hibernate.EntityMode;
 import org.hibernate.HibernateException;
 import org.hibernate.MappingException;
 import org.hibernate.SessionFactory;
-import org.hibernate.cfg.Configuration;
-import org.hibernate.cfg.ImprovedNamingStrategy;
-import org.hibernate.cfg.Mappings;
-import org.hibernate.cfg.NamingStrategy;
+import org.hibernate.cfg.*;
 import org.hibernate.engine.FilterDefinition;
 import org.hibernate.mapping.JoinedSubclass;
 import org.hibernate.mapping.PersistentClass;
 import org.hibernate.mapping.RootClass;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
+import java.util.*;
 
 /**
  * Allows configuring Grails' hibernate support to work in conjunction with Hibernate's annotation
@@ -63,6 +61,9 @@
         if (shouldMapWithGorm(domainClass)) {
             domainClasses.add(domainClass);
         }
+        else {
+            addAnnotatedClass(domainClass.getClazz());
+        }
 
         return this;
     }
@@ -142,6 +143,20 @@
         return sessionFactory;
     }
 
+    @Override
+    public Settings buildSettings() {
+        Settings settings = super.buildSettings();
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
+
+    @Override
+    public Settings buildSettings(Properties props) throws HibernateException {
+        Settings settings = super.buildSettings(props);
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
+
     /**
      * Overrides the default behaviour to including binding of Grails domain classes.
      */
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java
index a6c4dc0..4d033fd 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java
@@ -17,13 +17,13 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.validation.ConstrainedProperty;
+import grails.validation.Constraint;
 import org.codehaus.groovy.grails.orm.hibernate.persister.entity.GroovyAwareJoinedSubclassEntityPersister;
 import org.codehaus.groovy.grails.orm.hibernate.persister.entity.GroovyAwareSingleTableEntityPersister;
 import org.codehaus.groovy.grails.orm.hibernate.validation.UniqueConstraint;
-import org.codehaus.groovy.grails.validation.ConstrainedProperty;
-import org.codehaus.groovy.grails.validation.Constraint;
 import org.hibernate.mapping.Column;
 import org.hibernate.mapping.Table;
 
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java
index 1bbe7eb..7ad663e 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java
@@ -14,19 +14,25 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
+import grails.core.GrailsApplication;
+import grails.core.GrailsClass;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import grails.util.CollectionUtils;
+import grails.util.GrailsClassUtils;
 import grails.util.Holders;
 import groovy.lang.GroovyObject;
 import groovy.lang.GroovySystem;
 import groovy.lang.MetaClass;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.*;
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateDomainClass;
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistProxyFactory;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.HibernateProxyHandler;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.grails.core.DefaultGrailsDomainClass;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.hibernate.*;
 import org.hibernate.criterion.Order;
 import org.hibernate.engine.EntityEntry;
@@ -246,7 +252,7 @@
      * @param c The criteria instance
      * @param argMap The arguments map
      *
-     * @deprecated Use {@link #populateArgumentsForCriteria(org.codehaus.groovy.grails.commons.GrailsApplication, Class, org.hibernate.Criteria, java.util.Map)} instead
+     * @deprecated Use {@link #populateArgumentsForCriteria(GrailsApplication, Class, org.hibernate.Criteria, java.util.Map)} instead
      */
     @Deprecated
     @SuppressWarnings("rawtypes")
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy
index 61cc81b..750bee8 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy
@@ -16,23 +16,24 @@
 package org.codehaus.groovy.grails.orm.hibernate.cfg
 
 import grails.artefact.Enhanced
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
+import grails.util.GrailsClassUtils
+import grails.util.GrailsMetaClassUtils
 import grails.util.GrailsNameUtils
 import groovy.transform.CompileStatic
 import groovy.transform.TypeCheckingMode
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsClassUtils
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
 import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormEnhancer
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormInstanceApi
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormStaticApi
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormValidationApi
 import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor
+import org.codehaus.groovy.grails.orm.hibernate.support.HibernateRuntimeUtils
 import org.codehaus.groovy.runtime.InvokerHelper
-import org.codehaus.groovy.runtime.StringGroovyMethods
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.grails.datastore.mapping.core.Datastore
 import org.grails.datastore.mapping.model.MappingContext
 import org.grails.datastore.mapping.model.PersistentEntity
@@ -185,13 +186,14 @@
     // http://jira.codehaus.org/browse/GROOVY-6138 prevents using CompileStatic for this method
     @CompileStatic(TypeCheckingMode.SKIP)
     static void enhanceProxyClass(Class proxyClass) {
-        MetaMethod grailsEnhancedMetaMethod = proxyClass.metaClass.getStaticMetaMethod("grailsEnhanced", (Class[])null)
+        MetaClass mc = GrailsMetaClassUtils.getExpandoMetaClass(proxyClass)
+        MetaMethod grailsEnhancedMetaMethod = mc.getStaticMetaMethod("grailsEnhanced", (Class[])null)
         if (grailsEnhancedMetaMethod != null && grailsEnhancedMetaMethod.invoke(proxyClass, null) == proxyClass) {
             return
         }
 
-        MetaClass mc = (MetaClass)InvokerHelper.getMetaClass(proxyClass)
-        MetaClass superMc = InvokerHelper.getMetaClass(proxyClass.getSuperclass())
+        MetaClass superMc = GrailsMetaClassUtils.getExpandoMetaClass(proxyClass.getSuperclass())
+
 
         // hasProperty
         registerMetaMethod(mc, 'hasProperty', { String name ->
@@ -328,38 +330,6 @@
     }
 
     static Object convertValueToType(Object passedValue, Class targetType, ConversionService conversionService) {
-        // workaround for GROOVY-6127, do not assign directly in parameters before it's fixed
-        Object value = passedValue
-        if(targetType != null && value != null && !(value in targetType)) {
-            if (value instanceof CharSequence) {
-                value = value.toString()
-                if(value in targetType) {
-                    return value
-                }
-            }
-            try {
-                if (value instanceof Number && (targetType==Long || targetType==Integer)) {
-                    if(targetType == Long) {
-                        value = ((Number)value).toLong()
-                    } else {
-                        value = ((Number)value).toInteger()
-                    }
-                } else if (value instanceof String && targetType in Number) {
-                    String strValue = value.trim()
-                    if(targetType == Long) {
-                        value = Long.parseLong(strValue)
-                    } else if (targetType == Integer) {
-                        value = Integer.parseInt(strValue)
-                    } else {
-                        value = StringGroovyMethods.asType(strValue, targetType)
-                    }
-                } else {
-                    value = conversionService.convert(value, targetType)
-                }
-            } catch (e) {
-                // ignore
-            }
-        }
-        return value
+        HibernateRuntimeUtils.convertValueToType(passedValue, targetType, conversionService)
     }
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractClausedStaticPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractClausedStaticPersistentMethod.java
deleted file mode 100644
index 6d575a7..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractClausedStaticPersistentMethod.java
+++ /dev/null
@@ -1,548 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.orm.RlikeExpression;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-import groovy.lang.Range;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.*;
-import org.hibernate.Criteria;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.CriteriaQuery;
-import org.hibernate.criterion.Criterion;
-import org.hibernate.criterion.Restrictions;
-import org.hibernate.engine.TypedValue;
-import org.springframework.beans.TypeMismatchException;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.util.Assert;
-
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @author Graeme Rocher
- * @since 31-Aug-2005
- */
-public abstract class AbstractClausedStaticPersistentMethod extends AbstractStaticPersistentMethod {
-
-    protected static final Log LOG = LogFactory.getLog(AbstractClausedStaticPersistentMethod.class);
-
-    /**
-     * @author Graeme Rocher
-     */
-    protected abstract static class GrailsMethodExpression {
-        protected static final String LESS_THAN = "LessThan";
-        protected static final String LESS_THAN_OR_EQUAL = "LessThanEquals";
-        protected static final String GREATER_THAN = "GreaterThan";
-        protected static final String GREATER_THAN_OR_EQUAL = "GreaterThanEquals";
-        protected static final String LIKE = "Like";
-        protected static final String ILIKE = "Ilike";
-        protected static final String RLIKE = "Rlike";
-        protected static final String BETWEEN = "Between";
-        protected static final String IN_LIST= "InList";
-        protected static final String IS_NOT_NULL = "IsNotNull";
-        protected static final String IS_NULL = "IsNull";
-        protected static final String NOT = "Not";
-        protected static final String EQUAL = "Equal";
-        protected static final String NOT_EQUAL = "NotEqual";
-        protected static final String IN_RANGE = "InRange";
-
-        protected String propertyName;
-        protected Object[] arguments;
-        protected int argumentsRequired;
-        protected boolean negation;
-        protected String type;
-        protected Class<?> targetClass;
-        private GrailsApplication application;
-        protected final ConversionService conversionService;
-
-        /**
-         * Used as an indication that an expression will return no results, so stop processing and return nothing.
-         */
-        static final Criterion FORCE_NO_RESULTS = new Criterion() {
-            private static final long serialVersionUID = 1L;
-            public TypedValue[] getTypedValues(Criteria c, CriteriaQuery q) { return null; }
-            public String toSqlString(Criteria c, CriteriaQuery q) { return null; }
-        };
-
-        GrailsMethodExpression(GrailsApplication application, Class<?> targetClass,
-                String propertyName, String type, int argumentsRequired, boolean negation, ConversionService conversionService) {
-            this.application = application;
-            this.targetClass = targetClass;
-            this.propertyName = propertyName;
-            this.type = type;
-            this.argumentsRequired = argumentsRequired;
-            this.negation = negation;
-            this.conversionService = conversionService;
-        }
-
-        GrailsMethodExpression(GrailsApplication application, Class<?> targetClass,
-                String queryParameter, String type, int argumentsRequired, ConversionService conversionService) {
-            this(application, targetClass, calcPropertyName(queryParameter, type), type,
-                 argumentsRequired, isNegation(queryParameter, type), conversionService);
-        }
-
-        public String getPropertyName() {
-            return propertyName;
-        }
-
-        public Object[] getArguments() {
-            Object[] copy = new Object[arguments.length];
-            System.arraycopy(arguments, 0, copy, 0, arguments.length);
-            return copy;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder buf = new StringBuilder("[GrailsMethodExpression] ");
-            buf.append(propertyName)
-               .append(" ")
-               .append(type)
-               .append(" ");
-
-            for (int i = 0; i < arguments.length; i++) {
-                buf.append(arguments[i]);
-                if (i != arguments.length) {
-                    buf.append(" and ");
-                }
-            }
-            return buf.toString();
-        }
-
-        @SuppressWarnings("unchecked")
-        protected void setArguments(Object[] args) throws IllegalArgumentException {
-            if (args.length != argumentsRequired) {
-                throw new IllegalArgumentException("Method expression '" + type + "' requires " +
-                        argumentsRequired + " arguments");
-            }
-
-            GrailsDomainClass dc = (GrailsDomainClass)application.getArtefact(
-                    DomainClassArtefactHandler.TYPE, targetClass.getName());
-            GrailsDomainClassProperty prop = dc.getPropertyByName(propertyName);
-
-            if (prop == null) {
-                throw new IllegalArgumentException("Property " + propertyName +
-                        " doesn't exist for method expression '"+ type + "'");
-            }
-
-            for (int i = 0; i < args.length; i++) {
-                Object currentArg = args[i];
-                if (currentArg == null) continue;
-                // convert GStrings to strings
-                if (prop.getType() == String.class && (currentArg instanceof CharSequence)) {
-                    args[i] = currentArg.toString();
-                }
-                else if (!prop.getType().isAssignableFrom(currentArg.getClass()) && !(GrailsClassUtils.isMatchBetweenPrimativeAndWrapperTypes(prop.getType(), currentArg.getClass()))) {
-                    try {
-                        if (type.equals(IN_LIST)) {
-                            if(currentArg instanceof Collection) {
-                                currentArg = convertArgumentList(prop, (Collection)currentArg);
-                            }
-                            args[i] = conversionService.convert(currentArg, Collection.class);
-                        }
-                        else {
-                            args[i] = conversionService.convert(currentArg, prop.getType());
-                        }
-                    }
-                    catch (TypeMismatchException tme) {
-                        // if we cannot perform direct conversion and argument is subclass of Number
-                        // we can try to convert it through its String representation
-                        if (Number.class.isAssignableFrom(currentArg.getClass())) {
-                            try {
-                                args[i] = conversionService.convert(currentArg.toString(), prop.getType());
-                            }
-                            catch(TypeMismatchException tme1) {
-                                throw new IllegalArgumentException("Cannot convert value " + currentArg + " of property '"+propertyName+"' to required type " + prop.getType() + ": " + tme1.getMessage());
-                            }
-                        }
-                        else {
-                            throw new IllegalArgumentException("Cannot convert value " + currentArg + " of property '"+propertyName+"' to required type " + prop.getType());
-                        }
-                    }
-                }
-                else if(type.equals(IN_LIST) && (currentArg instanceof Collection)) {
-                    currentArg = convertArgumentList(prop, (Collection) currentArg);
-                }
-            }
-
-            arguments = args;
-        }
-
-        protected List convertArgumentList(GrailsDomainClassProperty prop, Collection argList) {
-            List convertedList = new ArrayList(argList.size());
-            for (Object item : argList) {
-                if(item instanceof CharSequence) {
-                    item = item.toString();
-                }
-                convertedList.add(conversionService.convert(item, prop.getType()));
-            }
-            return convertedList;
-        }
-
-        abstract Criterion createCriterion();
-
-        protected Criterion getCriterion() {
-            Assert.notNull(arguments, "Parameters array must be set before retrieving Criterion");
-            return negation ? Restrictions.not(createCriterion()) : createCriterion();
-        }
-
-        protected static GrailsMethodExpression create(final GrailsApplication application,
-                Class<?> clazz, String queryParameter, ConversionService conversionService) {
-
-            if (queryParameter.endsWith(LESS_THAN_OR_EQUAL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, LESS_THAN_OR_EQUAL, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.le(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(LESS_THAN)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, LESS_THAN, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.lt(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(GREATER_THAN_OR_EQUAL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, GREATER_THAN_OR_EQUAL, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.ge(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(GREATER_THAN)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, GREATER_THAN, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.gt(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(LIKE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, LIKE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.like(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(ILIKE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, ILIKE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.ilike(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(RLIKE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, RLIKE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return new RlikeExpression(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IS_NOT_NULL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IS_NOT_NULL, 0, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.isNotNull(propertyName);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IS_NULL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IS_NULL, 0, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.isNull(propertyName);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(BETWEEN)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, BETWEEN, 2, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.between(propertyName,arguments[0], arguments[1]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IN_LIST)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IN_LIST, 1, conversionService) {
-                    @SuppressWarnings("rawtypes")
-                    @Override
-                    Criterion createCriterion() {
-                        Collection collection = (Collection)arguments[0];
-                        if (collection == null || collection.isEmpty()) {
-                            return FORCE_NO_RESULTS;
-                        }
-                        return Restrictions.in(propertyName, collection);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(NOT_EQUAL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, NOT_EQUAL, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNotNull(propertyName);
-                        return Restrictions.ne(propertyName,arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IN_RANGE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IN_RANGE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.between(propertyName, arguments[0], arguments[1]);
-                    }
-                    @Override
-                    protected void setArguments(Object[] args) throws IllegalArgumentException {
-                        if (args != null && args.length > 0 && args[0] instanceof Range) {
-                            Range<?> range = (Range<?>) args[0];
-                            args = new Object[] { range.getFrom(), range.getTo() };
-                            argumentsRequired = 2;
-                        }
-                        super.setArguments(args);
-                    }
-                };
-            }
-
-            return new GrailsMethodExpression(application, clazz,
-                    calcPropertyName(queryParameter, null),
-                    EQUAL, 1, isNegation(queryParameter, EQUAL), conversionService) {
-                @Override
-                Criterion createCriterion() {
-                    if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                    return Restrictions.eq(propertyName,arguments[0]);
-                }
-            };
-        }
-
-        private static boolean isNegation(String queryParameter, String clause) {
-            String propName;
-            if (clause != null && !clause.equals(EQUAL)) {
-                int i = queryParameter.indexOf(clause);
-                propName = queryParameter.substring(0,i);
-            }
-            else {
-                propName = queryParameter;
-            }
-            return propName.endsWith(NOT);
-        }
-
-        private static String calcPropertyName(String queryParameter, String clause) {
-            String propName;
-            if (clause != null && !clause.equals(EQUAL)) {
-                int i = queryParameter.indexOf(clause);
-                propName = queryParameter.substring(0,i);
-            }
-            else {
-                propName = queryParameter;
-            }
-            if (propName.endsWith(NOT)) {
-                int i = propName.lastIndexOf(NOT);
-                propName = propName.substring(0, i);
-            }
-            return propName.substring(0,1).toLowerCase(Locale.ENGLISH) + propName.substring(1);
-        }
-    }
-
-    private final String[] operators;
-    private final Pattern[] operatorPatterns;
-    protected final ConversionService conversionService;
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     * @param pattern
-     * @param operators
-     */
-    public AbstractClausedStaticPersistentMethod(GrailsApplication application, SessionFactory sessionFactory, ClassLoader classLoader, Pattern pattern, String[] operators, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, pattern, application, defaultFlushMode);
-        this.operators = operators;
-        operatorPatterns = new Pattern[operators.length];
-        for (int i = 0; i < operators.length; i++) {
-            operatorPatterns[i] = Pattern.compile("(\\w+)("+operators[i]+")(\\p{Upper})(\\w+)");
-        }
-        this.conversionService = conversionService;
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractStaticPersistentMethod#doInvokeInternal(java.lang.Class, java.lang.String, java.lang.Object[])
-     */
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName,
-                                      Closure additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz, methodName, null, additionalCriteria, arguments);
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz, methodName, additionalCriteria,null, arguments);
-    }
-
-    protected Object doInvokeInternal(Class<?> clazz, String methodName, DetachedCriteria<?> detachedCriteria, Closure<?> additionalCriteria, Object[] arguments) {
-        List<GrailsMethodExpression> expressions = new ArrayList<GrailsMethodExpression>();
-        if (arguments == null) arguments = new Object[0];
-        Matcher match = super.getPattern().matcher(methodName);
-        // find match
-        match.find();
-
-        String[] queryParameters;
-        int totalRequiredArguments = 0;
-        // get the sequence clauses
-        final String querySequence;
-        int groupCount = match.groupCount();
-        if (groupCount == 6) {
-            String booleanProperty = match.group(3);
-            if (booleanProperty == null) {
-                booleanProperty = match.group(6);
-                querySequence = null;
-            }
-            else {
-                querySequence = match.group(5);
-            }
-            Boolean arg = Boolean.TRUE;
-            if (booleanProperty.matches("Not[A-Z].*")) {
-                booleanProperty = booleanProperty.substring(3);
-                arg = Boolean.FALSE;
-            }
-            GrailsMethodExpression booleanExpression = GrailsMethodExpression.create(
-                    application, clazz, booleanProperty, conversionService);
-            booleanExpression.setArguments(new Object[]{arg});
-            expressions.add(booleanExpression);
-        }
-        else {
-            querySequence = match.group(2);
-        }
-        // if it contains operator and split
-        boolean containsOperator = false;
-        String operatorInUse = null;
-
-        if (querySequence != null) {
-            for (int i = 0; i < operators.length; i++) {
-                Matcher currentMatcher = operatorPatterns[i].matcher(querySequence);
-                if (currentMatcher.find()) {
-                    containsOperator = true;
-                    operatorInUse = operators[i];
-
-                    queryParameters = querySequence.split(operatorInUse);
-
-                    // loop through query parameters and create expressions
-                    // calculating the number of arguments required for the expression
-                    int argumentCursor = 0;
-                    for (String queryParameter : queryParameters) {
-                        GrailsMethodExpression currentExpression = GrailsMethodExpression.create(
-                                application, clazz, queryParameter, conversionService);
-                        totalRequiredArguments += currentExpression.argumentsRequired;
-                        // populate the arguments into the GrailsExpression from the argument list
-                        Object[] currentArguments = new Object[currentExpression.argumentsRequired];
-                        if ((argumentCursor + currentExpression.argumentsRequired) > arguments.length) {
-                            throw new MissingMethodException(methodName, clazz, arguments);
-                        }
-
-                        for (int k = 0; k < currentExpression.argumentsRequired; k++, argumentCursor++) {
-                            currentArguments[k] = arguments[argumentCursor];
-                        }
-                        try {
-                            currentExpression.setArguments(currentArguments);
-                        }
-                        catch (IllegalArgumentException iae) {
-                            LOG.debug(iae.getMessage(), iae);
-                            throw new MissingMethodException(methodName, clazz, arguments);
-                        }
-                        // add to list of expressions
-                        expressions.add(currentExpression);
-                    }
-                    break;
-                }
-            }
-        }
-
-        // otherwise there is only one expression
-        if (!containsOperator && querySequence != null) {
-            GrailsMethodExpression solo = GrailsMethodExpression.create(application, clazz, querySequence, conversionService);
-
-            if (solo.argumentsRequired > arguments.length) {
-                throw new MissingMethodException(methodName, clazz, arguments);
-            }
-
-            totalRequiredArguments += solo.argumentsRequired;
-            Object[] soloArgs = new Object[solo.argumentsRequired];
-
-            System.arraycopy(arguments, 0, soloArgs, 0, solo.argumentsRequired);
-            try {
-                solo.setArguments(soloArgs);
-            }
-            catch (IllegalArgumentException iae) {
-                LOG.debug(iae.getMessage(), iae);
-                throw new MissingMethodException(methodName,clazz,arguments);
-            }
-            expressions.add(solo);
-        }
-
-        // if the total of all the arguments necessary does not equal the number of arguments throw exception
-        if (totalRequiredArguments > arguments.length) {
-            throw new MissingMethodException(methodName,clazz,arguments);
-        }
-
-        // calculate the remaining arguments
-        Object[] remainingArguments = new Object[arguments.length - totalRequiredArguments];
-        if (remainingArguments.length > 0) {
-            for (int i = 0, j = totalRequiredArguments; i < remainingArguments.length; i++,j++) {
-                remainingArguments[i] = arguments[j];
-            }
-        }
-
-        if (LOG.isTraceEnabled()) {
-            LOG.trace("Calculated expressions: " + expressions);
-        }
-
-        return doInvokeInternalWithExpressions(clazz, methodName, remainingArguments, expressions, operatorInUse, detachedCriteria, additionalCriteria);
-    }
-
-    @SuppressWarnings("rawtypes")
-    protected abstract Object doInvokeInternalWithExpressions(Class clazz, String methodName, Object[] arguments, List expressions, String operatorInUse, DetachedCriteria detachedCriteria, Closure additionalCriteria);
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractDynamicPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractDynamicPersistentMethod.java
deleted file mode 100644
index 1dd3b6d..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractDynamicPersistentMethod.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.validation.ValidationErrors;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodInvocation;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.SessionFactory;
-import org.springframework.orm.hibernate3.HibernateTemplate;
-import org.springframework.util.Assert;
-import org.springframework.validation.Errors;
-import org.springframework.validation.FieldError;
-
-/**
- * @author Steven Devijver
- */
-public abstract class AbstractDynamicPersistentMethod extends AbstractDynamicMethodInvocation {
-
-    public static final String ERRORS_PROPERTY = "errors";
-
-    private ClassLoader classLoader;
-    private HibernateTemplate hibernateTemplate;
-    GrailsApplication application;
-    int defaultFlushMode;
-
-    public AbstractDynamicPersistentMethod(Pattern pattern, SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, int defaultFlushMode) {
-        super(pattern);
-        Assert.notNull(sessionFactory, "Session factory is required!");
-        this.classLoader = classLoader;
-        Assert.notNull(application, "Constructor argument 'application' cannot be null");
-        this.application = application;
-        hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, application, defaultFlushMode);
-    }
-
-    protected HibernateTemplate getHibernateTemplate() {
-        return hibernateTemplate;
-    }
-
-    @Override
-    public Object invoke(Object target, String methodName, Object[] arguments) {
-        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try {
-            Thread.currentThread().setContextClassLoader(classLoader);
-            return doInvokeInternal(target, arguments);
-        }
-        finally {
-            Thread.currentThread().setContextClassLoader(originalClassLoader);
-        }
-    }
-
-    protected abstract Object doInvokeInternal(Object target, Object[] arguments);
-
-    /**
-     * This method will set the target object to read-only if it is contained with the Hibernate session,
-     * Preventing Hibernate dirty-checking from persisting the instance
-     *
-     * @param target The target object
-     */
-    protected void setObjectToReadOnly(final Object target) {
-        GrailsHibernateUtil.setObjectToReadyOnly(target, getHibernateTemplate().getSessionFactory());
-    }
-
-    protected void setObjectToReadWrite(final Object target) {
-        GrailsHibernateUtil.setObjectToReadWrite(target, getHibernateTemplate().getSessionFactory());
-    }
-
-    /**
-     * Initializes the Errors property on target.  The target will be assigned a new
-     * Errors property.  If the target contains any binding errors, those binding
-     * errors will be copied in to the new Errors property.
-     *
-     * @param target object to initialize
-     * @return the new Errors object
-     */
-    protected Errors setupErrorsProperty(Object target) {
-        MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass());
-
-        ValidationErrors errors = new ValidationErrors(target);
-
-        Errors originalErrors = (Errors) mc.getProperty(target, ERRORS_PROPERTY);
-        for (Object o : originalErrors.getFieldErrors()) {
-            FieldError fe = (FieldError)o;
-            if (fe.isBindingFailure()) {
-                errors.addError(new FieldError(fe.getObjectName(),
-                                               fe.getField(),
-                                               fe.getRejectedValue(),
-                                               fe.isBindingFailure(),
-                                               fe.getCodes(),
-                                               fe.getArguments(),
-                                               fe.getDefaultMessage()));
-            }
-        }
-
-        mc.setProperty(target, ERRORS_PROPERTY, errors);
-        return errors;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethod.java
deleted file mode 100644
index 10d780e..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethod.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.NonUniqueResultException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Disjunction;
-import org.hibernate.criterion.Restrictions;
-import org.hibernate.impl.CriteriaImpl;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-public abstract class AbstractFindByPersistentMethod extends AbstractClausedStaticPersistentMethod {
-    public static final String OPERATOR_OR = "Or";
-    public static final String OPERATOR_AND = "And";
-    public static final String[] OPERATORS = { OPERATOR_AND, OPERATOR_OR };
-    private HibernateDatastore datastore;
-    private static final Map<String, Boolean> useLimitCache = new ConcurrentHashMap<String, Boolean>();
-
-    public AbstractFindByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,
-                                          SessionFactory sessionFactory, ClassLoader classLoader,
-                                          Pattern pattern, String[] operators) {
-        super(application, sessionFactory, classLoader, pattern, operators, datastore.getMappingContext().getConversionService(), datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternalWithExpressions(final Class clazz, String methodName, final Object[] arguments, final List expressions, String operatorInUse, final DetachedCriteria detachedCriteria, final Closure additionalCriteria) {
-        final String operator = OPERATOR_OR.equals(operatorInUse) ? OPERATOR_OR : OPERATOR_AND;
-        return getHibernateTemplate().execute(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Criteria crit = buildCriteria(session, detachedCriteria, additionalCriteria, clazz, arguments, operator, expressions);
-
-                boolean useLimit = establishWhetherToUseLimit(clazz);
-                return getResult(crit, useLimit);
-            }
-        });
-    }
-
-    private boolean establishWhetherToUseLimit(Class<?> clazz) {
-        boolean useLimit = true;
-        GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE, clazz.getName());
-        if (domainClass != null) {
-            Boolean aBoolean = useLimitCache.get(domainClass.getName());
-            if (aBoolean != null) {
-                useLimit = aBoolean;
-            }
-            else {
-
-                for (GrailsDomainClassProperty property : domainClass.getPersistentProperties()) {
-                    if ((property.isOneToMany()||property.isManyToMany()) && property.getFetchMode() == GrailsDomainClassProperty.FETCH_EAGER) {
-                        useLimit = false;
-                        useLimitCache.put(domainClass.getName(), useLimit);
-                        break;
-                    }
-                }
-            }
-        }
-        return useLimit;
-    }
-
-    protected Object getResult(Criteria crit) {
-        CriteriaImpl impl = (CriteriaImpl) crit;
-        String entityOrClassName = impl.getEntityOrClassName();
-        GrailsClass domainClass = application.getArtefact(DomainClassArtefactHandler.TYPE, entityOrClassName);
-        boolean useLimit = establishWhetherToUseLimit(domainClass.getClazz());
-
-        return getResult(crit, useLimit);
-    }
-
-    protected Object getResult(Criteria crit, boolean useLimit) {
-        if (useLimit) {
-            final List<?> list = crit.list();
-            if (!list.isEmpty()) {
-                return GrailsHibernateUtil.unwrapIfProxy(list.get(0));
-            }
-        }
-        else {
-            try {
-                return crit.uniqueResult();
-            } catch (NonUniqueResultException e) {
-                return null;
-            }
-        }
-        return null;
-    }
-
-    protected Criteria buildCriteria(Session session, DetachedCriteria<?> detachedCriteria,
-            Closure<?> additionalCriteria, Class<?> clazz, Object[] arguments,
-            String operator, List<?> expressions) {
-        Criteria crit = getCriteria(datastore, application, session, detachedCriteria, additionalCriteria, clazz);
-
-        boolean useLimit = establishWhetherToUseLimit(clazz);
-
-        if (arguments.length > 0) {
-            if (arguments[0] instanceof Map<?, ?>) {
-                Map<?, ?> argMap = (Map<?, ?>)arguments[0];
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit, argMap, conversionService);
-                if (!argMap.containsKey(GrailsHibernateUtil.ARGUMENT_FETCH)) {
-                    if (useLimit) {
-                        crit.setMaxResults(1);
-                    }
-                }
-            }
-            else {
-                if (useLimit) {
-                    crit.setMaxResults(1);
-                }
-            }
-        }
-        else {
-            if (useLimit) {
-                crit.setMaxResults(1);
-            }
-        }
-
-        if (operator.equals(OPERATOR_OR)) {
-            if (firstExpressionIsRequiredBoolean()) {
-                GrailsMethodExpression expression = (GrailsMethodExpression) expressions.remove(0);
-                crit.add(expression.getCriterion());
-            }
-            Disjunction dis = Restrictions.disjunction();
-            for (Object expression : expressions) {
-                GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                dis.add(current.getCriterion());
-            }
-            crit.add(dis);
-        }
-        else {
-            for (Object expression : expressions) {
-                GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                crit.add(current.getCriterion());
-            }
-        }
-        return crit;
-    }
-
-    /**
-     * Indicates if the first expression in the query is a required boolean property and as such should
-     * be ANDed to the other expressions, not ORed.
-     *
-     * @return true if the first expression is a required boolean property, false otherwise
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByBooleanPropertyPersistentMethod
-     */
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return false;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractSavePersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractSavePersistentMethod.java
deleted file mode 100644
index 2c3a202..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractSavePersistentMethod.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.validation.DeferredBindingActions;
-import grails.validation.ValidationException;
-import groovy.lang.GroovyObject;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-
-import java.io.Serializable;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass;
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.validation.AbstractPersistentConstraint;
-import org.codehaus.groovy.grails.validation.CascadingValidator;
-import org.grails.datastore.mapping.engine.event.ValidationEvent;
-import org.hibernate.SessionFactory;
-import org.springframework.beans.BeanWrapper;
-import org.springframework.beans.BeanWrapperImpl;
-import org.springframework.beans.InvalidPropertyException;
-import org.springframework.orm.hibernate3.HibernateTemplate;
-import org.springframework.validation.Errors;
-import org.springframework.validation.Validator;
-
-/**
- * Abstract class for different implementations that perform saving to implement.
- *
- * @author Graeme Rocher
- * @since 0.3
- */
-public abstract class AbstractSavePersistentMethod extends AbstractDynamicPersistentMethod {
-
-    private HibernateDatastore datastore;
-    private static final String ARGUMENT_VALIDATE = "validate";
-    private static final String ARGUMENT_DEEP_VALIDATE = "deepValidate";
-    private static final String ARGUMENT_FLUSH = "flush";
-    private static final String ARGUMENT_INSERT = "insert";
-    private static final String ARGUMENT_FAIL_ON_ERROR = "failOnError";
-    private static final String FAIL_ON_ERROR_CONFIG_PROPERTY = "grails.gorm.failOnError";
-    private static final String AUTO_FLUSH_CONFIG_PROPERTY = "grails.gorm.autoFlush";
-
-    /**
-     * When a domain instance is saved without validation, we put it
-     * into this thread local variable. Any code that needs to know
-     * whether the domain instance should be validated can just check
-     * the value. Note that this only works because the session is
-     * flushed when a domain instance is saved without validation.
-     */
-    private static ThreadLocal<Set<Integer>> disableAutoValidationFor = new ThreadLocal<Set<Integer>>();
-
-    static {
-        ShutdownOperations.addOperation(new Runnable() {
-            public void run() {
-                disableAutoValidationFor.remove();
-            }
-        });
-    }
-
-    private static Set<Integer> getDisableAutoValidationFor() {
-        Set<Integer> identifiers = disableAutoValidationFor.get();
-        if (identifiers == null)
-            disableAutoValidationFor.set(identifiers = new HashSet<Integer>());
-        return identifiers;
-    }
-
-    public static boolean isAutoValidationDisabled(Object obj) {
-        Set<Integer> identifiers = getDisableAutoValidationFor();
-        return obj != null && identifiers.contains(System.identityHashCode(obj));
-    }
-
-    public static void clearDisabledValidations(Object obj) {
-        getDisableAutoValidationFor().remove(System.identityHashCode(obj));
-    }
-
-    public static void clearDisabledValidations() {
-        getDisableAutoValidationFor().clear();
-    }
-
-    public AbstractSavePersistentMethod(Pattern pattern, SessionFactory sessionFactory,
-              ClassLoader classLoader, GrailsApplication application,
-              GrailsDomainClass domainClass, HibernateDatastore datastore) {
-        super(pattern, sessionFactory, classLoader, application, datastore.getDefaultFlushMode());
-
-        this.datastore = datastore;
-    }
-
-    public AbstractSavePersistentMethod(Pattern pattern, SessionFactory sessionFactory,
-             ClassLoader classLoader, GrailsApplication application, HibernateDatastore datastore) {
-       this(pattern, sessionFactory, classLoader, application, null, datastore);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private boolean shouldFail(GrailsApplication grailsApplication, GrailsDomainClass domainClass) {
-        boolean shouldFail = false;
-        final Map config = grailsApplication.getFlatConfig();
-        if (config.containsKey(FAIL_ON_ERROR_CONFIG_PROPERTY)) {
-            Object configProperty = config.get(FAIL_ON_ERROR_CONFIG_PROPERTY);
-            if (configProperty instanceof Boolean) {
-                shouldFail = Boolean.TRUE == configProperty;
-            }
-            else if (configProperty instanceof List) {
-                if (domainClass != null) {
-                    final Class theClass = domainClass.getClazz();
-                    List packageList = (List) configProperty;
-                    shouldFail = GrailsClassUtils.isClassBelowPackage(theClass, packageList);
-                }
-            }
-        }
-        return shouldFail;
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod#doInvokeInternal(java.lang.Object, java.lang.Object[])
-     */
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(final Object target, Object[] arguments) {
-        GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,
-                target.getClass().getName());
-
-        DeferredBindingActions.runActions();
-        boolean shouldFlush = shouldFlush(arguments);
-        boolean shouldValidate = shouldValidate(arguments, domainClass);
-        if (shouldValidate) {
-            Validator validator = domainClass.getValidator();
-
-            if (domainClass instanceof DefaultGrailsDomainClass) {
-                GrailsHibernateUtil.autoAssociateBidirectionalOneToOnes((DefaultGrailsDomainClass) domainClass, target);
-            }
-            Errors errors = setupErrorsProperty(target);
-
-            if (validator != null) {
-                application.getMainContext().publishEvent(new ValidationEvent(datastore, target));
-
-                boolean deepValidate = true;
-                Map argsMap = null;
-                if (arguments.length > 0 && arguments[0] instanceof Map) {
-                    argsMap = (Map) arguments[0];
-                }
-                if (argsMap != null && argsMap.containsKey(ARGUMENT_DEEP_VALIDATE)) {
-                    deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, argsMap);
-                }
-
-                AbstractPersistentConstraint.sessionFactory.set(datastore.getSessionFactory());
-                try {
-                    if (deepValidate && (validator instanceof CascadingValidator)) {
-                        ((CascadingValidator)validator).validate(target, errors, deepValidate);
-                    }
-                    else {
-                        validator.validate(target,errors);
-                    }
-                }
-                finally {
-                    AbstractPersistentConstraint.sessionFactory.remove();
-                }
-
-                if (errors.hasErrors()) {
-                    handleValidationError(domainClass,target,errors);
-                    boolean shouldFail = shouldFail(application, domainClass);
-                    if (argsMap != null && argsMap.containsKey(ARGUMENT_FAIL_ON_ERROR)) {
-                        shouldFail = GrailsClassUtils.getBooleanFromMap(ARGUMENT_FAIL_ON_ERROR, argsMap);
-                    }
-                    if (shouldFail) {
-                        throw new ValidationException("Validation Error(s) occurred during save()", errors);
-                    }
-                    return null;
-                }
-
-                setObjectToReadWrite(target);
-            }
-        }
-
-        // this piece of code will retrieve a persistent instant
-        // of a domain class property is only the id is set thus
-        // relieving this burden off the developer
-        if (domainClass != null) {
-            autoRetrieveAssocations(domainClass, target);
-        }
-
-        if (!shouldValidate) {
-            Set<Integer> identifiers = getDisableAutoValidationFor();
-            identifiers.add(System.identityHashCode(target));
-        }
-
-        if (shouldInsert(arguments)) {
-            return performInsert(target, shouldFlush);
-        }
-
-        return performSave(target, shouldFlush);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private boolean shouldInsert(Object[] arguments) {
-        return arguments.length > 0 && arguments[0] instanceof Map &&
-            GrailsClassUtils.getBooleanFromMap(ARGUMENT_INSERT, (Map) arguments[0]);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private boolean shouldFlush(Object[] arguments) {
-        final boolean shouldFlush;
-        if (arguments.length > 0 && arguments[0] instanceof Boolean) {
-            shouldFlush = (Boolean)arguments[0];
-        }
-        else if (arguments.length > 0 && arguments[0] instanceof Map && ((Map) arguments[0]).containsKey(ARGUMENT_FLUSH)) {
-            shouldFlush = GrailsClassUtils.getBooleanFromMap(ARGUMENT_FLUSH, ((Map) arguments[0]));
-        }
-        else {
-            final Map config = application.getFlatConfig();
-            shouldFlush = Boolean.TRUE == config.get(AUTO_FLUSH_CONFIG_PROPERTY);
-        }
-        return shouldFlush;
-    }
-
-    /**
-     * Performs automatic association retrieval
-     * @param domainClass The domain class to retrieve associations for
-     * @param target The target object
-     */
-    @SuppressWarnings("unchecked")
-    private void autoRetrieveAssocations(GrailsDomainClass domainClass, Object target) {
-        BeanWrapper bean = new BeanWrapperImpl(target);
-        HibernateTemplate t = getHibernateTemplate();
-        GrailsDomainClassProperty[] props = domainClass.getPersistentProperties();
-        for (int i = 0; i < props.length; i++) {
-            GrailsDomainClassProperty prop = props[i];
-            if (!prop.isManyToOne() && !prop.isOneToOne()) {
-                continue;
-            }
-
-            Object propValue = bean.getPropertyValue(prop.getName());
-            if (propValue == null || t.contains(propValue)) {
-                continue;
-            }
-
-            GrailsDomainClass otherSide = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,
-                    prop.getType().getName());
-            if (otherSide == null) {
-                continue;
-            }
-
-            BeanWrapper propBean = new BeanWrapperImpl(propValue);
-            try {
-                Serializable id = (Serializable)propBean.getPropertyValue(otherSide.getIdentifier().getName());
-                if (id != null) {
-                    final Object propVal = t.get(prop.getType(), id);
-                    if (propVal != null) {
-                        bean.setPropertyValue(prop.getName(), propVal);
-                    }
-                }
-            }
-            catch (InvalidPropertyException ipe) {
-                // property is not accessable
-            }
-        }
-    }
-
-    /**
-     * Sets the flush mode to manual. which ensures that the database changes are not persisted to the database
-     * if a validation error occurs. If save() is called again and validation passes the code will check if there
-     * is a manual flush mode and flush manually if necessary
-     *
-     * @param domainClass The domain class
-     * @param target The target object that failed validation
-     * @param errors The Errors instance  @return This method will return null signaling a validation failure
-     */
-    protected Object handleValidationError(GrailsDomainClass domainClass, final Object target, Errors errors) {
-        // if a validation error occurs set the object to read-only to prevent a flush
-        setObjectToReadOnly(target);
-        if (domainClass instanceof DefaultGrailsDomainClass) {
-            DefaultGrailsDomainClass dgdc = (DefaultGrailsDomainClass) domainClass;
-            List<GrailsDomainClassProperty> associations = dgdc.getAssociations();
-            for (GrailsDomainClassProperty association : associations) {
-                if (association.isOneToOne() || association.isManyToOne()) {
-                    BeanWrapper bean = new BeanWrapperImpl(target);
-                    Object propertyValue = bean.getPropertyValue(association.getName());
-                    if (propertyValue != null) {
-                        setObjectToReadOnly(propertyValue);
-                    }
-                }
-            }
-        }
-        setErrorsOnInstance(target, errors);
-        return null;
-    }
-
-    /**
-     * Associates the Errors object on the instance
-     *
-     * @param target The target instance
-     * @param errors The Errors object
-     */
-    protected void setErrorsOnInstance(Object target, Errors errors) {
-        if (target instanceof GroovyObject) {
-            ((GroovyObject)target).setProperty(ERRORS_PROPERTY,errors);
-        }
-        else {
-            MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass());
-            metaClass.setProperty(target.getClass() ,target, ERRORS_PROPERTY,errors, false, false);
-        }
-    }
-
-    /**
-     * Checks whether validation should be performed
-     * @return true if the domain class should be validated
-     * @param arguments  The arguments to the validate method
-     * @param domainClass The domain class
-     */
-    @SuppressWarnings("rawtypes")
-    private boolean shouldValidate(Object[] arguments, GrailsDomainClass domainClass) {
-        if (domainClass == null) {
-            return false;
-        }
-
-        if (arguments.length == 0) {
-            return true;
-        }
-
-        if (arguments[0] instanceof Boolean) {
-            return (Boolean)arguments[0];
-        }
-
-        if (arguments[0] instanceof Map) {
-            Map argsMap = (Map)arguments[0];
-            if (argsMap.containsKey(ARGUMENT_VALIDATE)) {
-                return GrailsClassUtils.getBooleanFromMap(ARGUMENT_VALIDATE, argsMap);
-            }
-
-            return true;
-        }
-
-        return true;
-    }
-
-    /**
-     * Subclasses should override and perform a save operation, flushing the session if the second argument is true
-     *
-     * @param target The target object to save
-     * @param shouldFlush Whether to flush
-     * @return The target object
-     */
-    protected abstract Object performSave(Object target, boolean shouldFlush);
-
-    /**
-     * Subclasses should override and perform an insert operation, flushing the session if the second argument is true
-     *
-     * @param target The target object to save
-     * @param shouldFlush Whether to flush
-     * @return The target object
-     */
-    protected abstract Object performInsert(Object target, boolean shouldFlush);
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractStaticPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractStaticPersistentMethod.java
deleted file mode 100644
index 58b128c..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractStaticPersistentMethod.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.orm.HibernateCriteriaBuilder;
-import groovy.lang.Closure;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.metaclass.AbstractStaticMethodInvocation;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateSession;
-import org.codehaus.groovy.grails.orm.hibernate.query.HibernateQuery;
-import org.grails.datastore.gorm.finders.DynamicFinder;
-import org.grails.datastore.gorm.finders.FinderMethod;
-import org.grails.datastore.mapping.model.PersistentEntity;
-import org.hibernate.Criteria;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.util.Assert;
-
-/**
- * Abstract base class for static persistent methods.
- *
- * @author Steven Devijver
- * @author Graeme Rocher
- */
-@SuppressWarnings("rawtypes")
-public abstract class AbstractStaticPersistentMethod extends AbstractStaticMethodInvocation implements FinderMethod {
-
-    private ClassLoader classLoader;
-    private GrailsHibernateTemplate hibernateTemplate;
-    private SessionFactory sessionFactory;
-    protected final GrailsApplication application;
-
-    protected AbstractStaticPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, Pattern pattern, GrailsApplication application, int defaultFlushMode) {
-        Assert.notNull(sessionFactory, "Session factory is required!");
-        Assert.notNull(application, "Constructor argument 'application' cannot be null");
-        this.application = application;
-        setPattern(pattern);
-        this.classLoader = classLoader;
-        this.sessionFactory = sessionFactory;
-        hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, application, defaultFlushMode);
-    }
-
-    protected SessionFactory getSessionFactory() {
-        return sessionFactory;
-    }
-
-    protected GrailsHibernateTemplate getHibernateTemplate() {
-        return hibernateTemplate;
-    }
-
-    @Override
-    public Object invoke(Class clazz, String methodName, Object[] arguments) {
-        return invoke(clazz, methodName, (Closure) null, arguments);
-    }
-
-    public Object invoke(Class clazz, String methodName, Closure additionalCriteria, Object[] arguments) {
-        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try {
-            Thread.currentThread().setContextClassLoader(classLoader);
-            return doInvokeInternal(clazz, methodName, additionalCriteria, arguments);
-        }
-        finally {
-            Thread.currentThread().setContextClassLoader(originalClassLoader);
-        }
-    }
-
-    public Object invoke(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try {
-            Thread.currentThread().setContextClassLoader(classLoader);
-            return doInvokeInternal(clazz, methodName, additionalCriteria, arguments);
-        }
-        finally {
-            Thread.currentThread().setContextClassLoader(originalClassLoader);
-        }
-    }
-
-    protected Criteria getCriteria(HibernateDatastore datastore, GrailsApplication appliation, Session session, DetachedCriteria detachedCriteria, Closure additionalCriteria, Class<?> clazz) {
-        if (additionalCriteria != null) {
-            HibernateCriteriaBuilder builder = new HibernateCriteriaBuilder(clazz, session.getSessionFactory());
-            builder.setGrailsApplication(appliation);
-            builder.setConversionService(datastore.getMappingContext().getConversionService());
-            builder.setDefaultFlushMode(datastore.getDefaultFlushMode());
-            return builder.buildCriteria(additionalCriteria);
-        }
-
-        Criteria criteria = session.createCriteria(clazz);
-        if (detachedCriteria != null) {
-            HibernateSession hibernateSession = new HibernateSession(datastore, session.getSessionFactory());
-            PersistentEntity persistentEntity = datastore.getMappingContext().getPersistentEntity(clazz.getName());
-            if (persistentEntity != null) {
-                DynamicFinder.applyDetachedCriteria(new HibernateQuery(criteria, hibernateSession, persistentEntity), detachedCriteria);
-            }
-        }
-        hibernateTemplate.applySettings(criteria);
-        return criteria;
-    }
-
-    protected abstract Object doInvokeInternal(Class clazz, String methodName, Closure additionalCriteria, Object[] arguments);
-
-    protected abstract Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments);
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/CountByPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/CountByPersistentMethod.java
deleted file mode 100644
index cb54d19..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/CountByPersistentMethod.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Disjunction;
-import org.hibernate.criterion.Projections;
-import org.hibernate.criterion.Restrictions;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * Dynamic method that allows counting the values of the specified property names
- *
- * eg. Account.countByBranch('London') // returns how many accounts are in london
- *
- * @author Graeme Rocher
- */
-public class CountByPersistentMethod extends AbstractClausedStaticPersistentMethod {
-
-    private static final String OPERATOR_OR = "Or";
-    private static final String OPERATOR_AND = "And";
-
-    private static final Pattern METHOD_PATTERN = Pattern.compile("(countBy)(\\w+)");
-    private static final String[] OPERATORS = { OPERATOR_AND, OPERATOR_OR };
-    private HibernateDatastore datastore;
-
-    public CountByPersistentMethod(HibernateDatastore datastore, GrailsApplication application, SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(application, sessionFactory, classLoader, METHOD_PATTERN, OPERATORS, datastore.getMappingContext().getConversionService(), datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Long doInvokeInternalWithExpressions(final Class clazz, final String methodName, final Object[] arguments,
-            final List expressions, final String operatorInUse, final DetachedCriteria detachedCriteria, final Closure additionalCriteria) {
-
-        return getHibernateTemplate().execute(new HibernateCallback<Long>() {
-            public Long doInHibernate(Session session) throws HibernateException, SQLException {
-                final Criteria crit = getCriteria(datastore, application, session, detachedCriteria, additionalCriteria, clazz);
-                crit.setProjection(Projections.rowCount());
-                String operator = OPERATOR_OR.equals(operatorInUse) ? OPERATOR_OR : OPERATOR_AND;
-                Map argsMap = (arguments.length > 1 && (arguments[1] instanceof Map)) ? (Map) arguments[1] : Collections.EMPTY_MAP;
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit,  argsMap, conversionService, false);
-
-                populateCriteriaWithExpressions(crit, operator, expressions);
-                return (Long) crit.uniqueResult();
-            }
-        });
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    protected void populateCriteriaWithExpressions(Criteria crit, String operator, List expressions) {
-        if (operator.equals(OPERATOR_OR)) {
-            Disjunction dis = Restrictions.disjunction();
-            for (GrailsMethodExpression current : (List<GrailsMethodExpression>)expressions) {
-                dis.add(current.getCriterion());
-            }
-            crit.add(dis);
-        }
-        else {
-            for (GrailsMethodExpression current : (List<GrailsMethodExpression>)expressions) {
-                crit.add(current.getCriterion());
-            }
-        }
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteQueryPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteQueryPersistentMethod.java
deleted file mode 100644
index d529918..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteQueryPersistentMethod.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * Allows the executing of arbitrary HQL queries.
- * <p/>
- * eg. Account.executeQuery("select distinct a.number from Account a where a.branch = ?", 'London') or
- * Account.executeQuery("select distinct a.number from Account a where a.branch = :branch", [branch:'London'])
- *
- * @author Graeme Rocher
- * @author Sergey Nebolsin
- * @see <a href="http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html">http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html</a>
- * @since 30-Apr-2006
- */
-public class ExecuteQueryPersistentMethod extends AbstractStaticPersistentMethod {
-    private static final String METHOD_SIGNATURE = "executeQuery";
-    private static final Pattern METHOD_PATTERN = Pattern.compile("^executeQuery$");
-
-    private static final List<String> QUERY_META_PARAMS = Arrays.asList(
-            GrailsHibernateUtil.ARGUMENT_MAX,
-            GrailsHibernateUtil.ARGUMENT_OFFSET,
-            GrailsHibernateUtil.ARGUMENT_CACHE,
-            GrailsHibernateUtil.ARGUMENT_FLUSH_MODE,
-            GrailsHibernateUtil.ARGUMENT_TIMEOUT,
-            GrailsHibernateUtil.ARGUMENT_FETCH_SIZE,
-            GrailsHibernateUtil.ARGUMENT_READ_ONLY);
-
-    private final ConversionService conversionService;
-
-    public ExecuteQueryPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, METHOD_PATTERN, application, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, Closure additionalCriteria, Object[] arguments) {
-        checkMethodSignature(clazz, arguments);
-
-        final String query = arguments[0].toString();
-        final Map queryMetaParams = extractQueryMetaParams(arguments);
-        final List positionalParams = extractPositionalParams(arguments);
-        final Map namedParams = extractNamedParams(arguments);
-
-        return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Query q = session.createQuery(query);
-                getHibernateTemplate().applySettings(q);
-                // process paginate params
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_MAX)) {
-                    Integer maxParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_MAX), Integer.class);
-                    q.setMaxResults(maxParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_OFFSET)) {
-                    Integer offsetParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_OFFSET), Integer.class);
-                    q.setFirstResult(offsetParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_CACHE)) {
-                    q.setCacheable((Boolean)queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_CACHE));
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_FETCH_SIZE)) {
-                    Integer fetchSizeParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_FETCH_SIZE), Integer.class);
-                    q.setFetchSize(fetchSizeParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_TIMEOUT)) {
-                    Integer timeoutParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_TIMEOUT), Integer.class);
-                    q.setTimeout(timeoutParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_READ_ONLY)) {
-                    q.setReadOnly((Boolean)queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_READ_ONLY));
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_FLUSH_MODE)) {
-                    q.setFlushMode((FlushMode)queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_FLUSH_MODE));
-                }
-                // process positional HQL params
-                int index = 0;
-                for (Object parameter : positionalParams) {
-                    q.setParameter(index++, parameter instanceof CharSequence ? parameter.toString() : parameter);
-                }
-
-                // process named HQL params
-                for (Object o : namedParams.entrySet()) {
-                    Map.Entry entry = (Map.Entry) o;
-                    if (!(entry.getKey() instanceof String)) {
-                        throw new GrailsQueryException("Named parameter's name must be of type String");
-                    }
-                    String parameterName = (String) entry.getKey();
-                    if (!QUERY_META_PARAMS.contains(parameterName)) {
-                        Object parameterValue = entry.getValue();
-                        if (parameterValue == null) {
-                            throw new IllegalArgumentException("Named parameter [" + entry.getKey() + "] value may not be null");
-                        }
-                        if (Collection.class.isAssignableFrom(parameterValue.getClass())) {
-                            q.setParameterList(parameterName, (Collection) parameterValue);
-                        }
-                        else if (parameterValue.getClass().isArray()) {
-                            q.setParameterList(parameterName, (Object[]) parameterValue);
-                        }
-                        else if (parameterValue instanceof CharSequence) {
-                            q.setParameter(parameterName, parameterValue.toString());
-                        }
-                        else {
-                            q.setParameter(parameterName, parameterValue);
-                        }
-                    }
-                }
-                return q.list();
-            }
-        });
-    }
-
-    @SuppressWarnings("rawtypes")
-    private void checkMethodSignature(Class clazz, Object[] arguments) {
-        boolean valid = true;
-        if (arguments.length < 1) valid = false;
-        else if (arguments.length == 3 && !(arguments[2] instanceof Map)) valid = false;
-        else if (arguments.length > 3) valid = false;
-
-        if (!valid) throw new MissingMethodException(METHOD_SIGNATURE, clazz, arguments);
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private Map extractQueryMetaParams(Object[] arguments) {
-        Map result = new HashMap();
-        int metaParamsIndex = 0;
-        if (arguments.length == 2 && arguments[1] instanceof Map) metaParamsIndex = 1;
-        else if (arguments.length == 3) metaParamsIndex = 2;
-        if (metaParamsIndex > 0) {
-            Map sourceMap = (Map) arguments[metaParamsIndex];
-            for (String queryMetaParam : QUERY_META_PARAMS) {
-                if (sourceMap.containsKey(queryMetaParam)) {
-                    result.put(queryMetaParam, sourceMap.get(queryMetaParam));
-                }
-            }
-        }
-        return result;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private List extractPositionalParams(Object[] arguments) {
-        List result = new ArrayList();
-        if (arguments.length < 2 || arguments[1] instanceof Map) return result;
-        if (arguments[1] instanceof Collection) {
-            result.addAll((Collection) arguments[1]);
-        }
-        else if (arguments[1].getClass().isArray()) {
-            result.addAll(Arrays.asList((Object[]) arguments[1]));
-        }
-        else {
-            result.add(arguments[1]);
-        }
-        return result;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private Map extractNamedParams(Object[] arguments) {
-        Map result = new HashMap();
-        if (arguments.length < 2 || !(arguments[1] instanceof Map)) return result;
-        result.putAll((Map) arguments[1]);
-        return result;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteUpdatePersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteUpdatePersistentMethod.java
deleted file mode 100644
index 5126bf9..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteUpdatePersistentMethod.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.orm.hibernate3.HibernateCallback;
-import org.springframework.orm.hibernate3.SessionFactoryUtils;
-
-/**
- * Allows the executing of arbitrary HQL updates.
- * <p/>
- * eg. Account.executeUpdate("delete from Account a where a.branch = ?", 'London') or
- * Account.executeUpdate("delete from Account a where a.branch = :branch", [branch:'London'])
- *
- * @author Burt Beckwith
- */
-@SuppressWarnings({ "unchecked", "rawtypes" })
-public class ExecuteUpdatePersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String METHOD_SIGNATURE = "executeUpdate";
-    private static final Pattern METHOD_PATTERN = Pattern.compile("^executeUpdate$");
-
-    public ExecuteUpdatePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, int defaultFlushMode) {
-        super(sessionFactory, classLoader, METHOD_PATTERN, application, defaultFlushMode);
-    }
-
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @Override
-    protected Object doInvokeInternal(final Class clazz, final String methodName, Closure additionalCriteria, final Object[] arguments) {
-
-        checkMethodSignature(clazz, arguments);
-
-        return getHibernateTemplate().execute(new HibernateCallback() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Query q = session.createQuery(arguments[0].toString());
-                getHibernateTemplate().applySettings(q);
-                SessionFactoryUtils.applyTransactionTimeout(q, getHibernateTemplate().getSessionFactory());
-
-                // process positional HQL params
-                int index = 0;
-                for (Object parameter : extractPositionalParams(arguments)) {
-                    q.setParameter(index++, parameter);
-                }
-
-                // process named HQL params
-                for (Map.Entry entry : (Set<Map.Entry>)extractNamedParams(arguments).entrySet()) {
-                    if (!(entry.getKey() instanceof String)) {
-                        throw new GrailsQueryException("Named parameter's name must be of type String");
-                    }
-
-                    String parameterName = (String)entry.getKey();
-                    Object parameterValue = entry.getValue();
-                    if (Collection.class.isAssignableFrom(parameterValue.getClass())) {
-                        q.setParameterList(parameterName, (Collection)parameterValue);
-                    }
-                    else if (parameterValue.getClass().isArray()) {
-                        q.setParameterList(parameterName, (Object[])parameterValue);
-                    }
-                    else if (parameterValue instanceof CharSequence) {
-                        q.setParameter(parameterName, parameterValue.toString());
-                    }
-                    else {
-                        q.setParameter(parameterName, parameterValue);
-                    }
-                }
-                return q.executeUpdate();
-            }
-        });
-    }
-
-    private void checkMethodSignature(Class clazz, Object[] arguments) {
-        boolean valid = true;
-        if (arguments.length == 0 || arguments.length > 2) {
-            valid = false;
-        }
-        else if (arguments.length == 2 && !(arguments[1] instanceof Map || arguments[1] instanceof Collection)) {
-            valid = false;
-        }
-
-        if (!valid) {
-            throw new MissingMethodException(METHOD_SIGNATURE, clazz, arguments);
-        }
-    }
-
-    private List extractPositionalParams(Object[] arguments) {
-        if (arguments.length == 1 || arguments[1] instanceof Map) {
-            return Collections.EMPTY_LIST;
-        }
-
-        List result = new ArrayList();
-        if (arguments[1] instanceof Collection) {
-            result.addAll((Collection)arguments[1]);
-        }
-        else if (arguments[1].getClass().isArray()) {
-            result.addAll(Arrays.asList((Object[])arguments[1]));
-        }
-        else {
-            result.add(arguments[1]);
-        }
-
-        return result;
-    }
-
-    private Map extractNamedParams(Object[] arguments) {
-        if (arguments.length == 1 || !(arguments[1] instanceof Map)) {
-            return Collections.EMPTY_MAP;
-        }
-
-        return (Map)arguments[1];
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByBooleanPropertyPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByBooleanPropertyPersistentMethod.java
deleted file mode 100644
index 985fe1e..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByBooleanPropertyPersistentMethod.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-/**
- * The "findAll<booleanProperty>By*" static persistent method. This method allows querying for
- * instances of grails domain classes based on a boolean property and any other arbitrary
- * properties.
- *
- * eg.
- * Account.findAllActiveByHolder("Joe Blogs"); // Where class "Account" has a properties called "active" and "holder"
- * Account.findAllActiveByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "active', "holder" and "branch"
- *
- * In both of those queries, the query will only select Account objects where active=true.
- *
- * @author Jeff Brown
- */
-public class FindAllByBooleanPropertyPersistentMethod extends FindAllByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findAll)((\\w+)(By)([A-Z]\\w*)|(\\w+))";
-
-    public FindAllByBooleanPropertyPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore, application,sessionFactory, classLoader);
-        setPattern(Pattern.compile(METHOD_PATTERN));
-    }
-
-    @Override
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByPersistentMethod.java
deleted file mode 100644
index 9b18a7a..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByPersistentMethod.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Disjunction;
-import org.hibernate.criterion.Restrictions;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * The "findBy*" static persistent method. This method allows querying for
- * instances of grails domain classes based on their properties. This method returns a list of all found results
- *
- * eg.
- * Account.findAllByHolder("Joe Blogs"); // Where class "Account" has a property called "holder"
- * Account.findAllByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "holder" and "branch"
- *
- * @author Graeme Rocher
- */
-public class FindAllByPersistentMethod extends AbstractClausedStaticPersistentMethod {
-
-    private static final String OPERATOR_OR = "Or";
-    private static final String OPERATOR_AND = "And";
-    private static final String METHOD_PATTERN = "(findAllBy)([A-Z]\\w*)";
-    private static final String[] OPERATORS = { OPERATOR_AND, OPERATOR_OR };
-    private HibernateDatastore datastore;
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     */
-    public FindAllByPersistentMethod(HibernateDatastore datastore,GrailsApplication application, SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(application, sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), OPERATORS, datastore.getMappingContext().getConversionService(), datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternalWithExpressions(final Class clazz, String methodName,
-                                                     final Object[] arguments, final List expressions, String operatorInUse,
-                                                     final DetachedCriteria detachedCriteria, final Closure additionalCriteria) {
-
-        final String operator = OPERATOR_OR.equals(operatorInUse) ? OPERATOR_OR : OPERATOR_AND;
-        return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-
-                final Criteria c = getCriteria(datastore,application, session,detachedCriteria, additionalCriteria, clazz);
-
-                Map argsMap = (arguments.length > 0 && (arguments[0] instanceof Map)) ? (Map) arguments[0] : Collections.EMPTY_MAP;
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, argsMap, conversionService);
-
-                if (operator.equals(OPERATOR_OR)) {
-                    if (firstExpressionIsRequiredBoolean()) {
-                        GrailsMethodExpression expression = (GrailsMethodExpression) expressions.remove(0);
-                        c.add(expression.getCriterion());
-                    }
-
-                    Disjunction dis = Restrictions.disjunction();
-                    int numberOfForceNoResultsCriterion = 0;
-                    for (Object expression : expressions) {
-                        GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                        if (GrailsMethodExpression.FORCE_NO_RESULTS == current.getCriterion()) {
-                            numberOfForceNoResultsCriterion++;
-                        } else {
-                            dis.add(current.getCriterion());
-                        }
-                    }
-                    if (numberOfForceNoResultsCriterion > 0 && numberOfForceNoResultsCriterion == expressions.size()) {
-                        return Collections.EMPTY_LIST;
-                    }
-                    c.add(dis);
-                }
-                else {
-                    for (Object expression : expressions) {
-                        GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                        if (GrailsMethodExpression.FORCE_NO_RESULTS == current.getCriterion()) {
-                            return Collections.emptyList();
-                        }
-                        c.add(current.getCriterion());
-                    }
-                }
-
-                c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                return c.list();
-            }
-        });
-    }
-
-    /**
-     * Indicates if the first expression in the query is a required boolean property and as such should
-     * be ANDed to the other expressions, not ORed.
-     *
-     * @return true if the first expression is a required boolean property, false otherwise
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllByBooleanPropertyPersistentMethod
-     */
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return false;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllPersistentMethod.java
deleted file mode 100644
index 8604572..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllPersistentMethod.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.util.GrailsNameUtils;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Example;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * <p>
- * The "findAll" persistent static method allows searching for instances using
- * either an example instance or an HQL query. Max results and offset parameters could
- * be specified. A GrailsQueryException is thrown if the query is not a valid query
- * for the domain class.
- * <p>
- * Syntax:
- *    DomainClass.findAll(query, params?)
- *    DomainClass.findAll(query, params?, max)
- *    DomainClass.findAll(query, params?, max, offset)
- *    DomainClass.findAll(query, params?, [max:10, offset:5])
- *
- * <p>
- * Examples in Groovy: <code>
- *         // retrieves all accounts
- *         def a = Account.findAll()
- *
- *         // retrieve all accounts ordered by account number
- *         def a = Account.findAll("from Account as a order by a.number asc")
- *
- *         // retrieve first 10 accounts ordered by account number
- *         def a = Account.findAll("from Account as a order by a.number asc",10)
- *
- *         // retrieve first 10 accounts ordered by account number started from 5th account
- *         def a = Account.findAll("from Account as a order by a.number asc",10,5)
- *
- *         // retrieve first 10 accounts ordered by account number started from 5th account
- *         def a = Account.findAll("from Account as a order by a.number asc",[max:10,offset:5])
- *
- *         // with query parameters
- *         def a = Account.find("from Account as a where a.number = ? and a.branch = ?", [38479, "London"])
- *
- *         // with query named parameters
- *         def a = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"])
- *
- *         // with query named parameters and max results and offset
- *         def a = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"], 10, 5)
- *
- *         // with query named parameters and max results and offset map
- *         def a = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"], [max:10, offset:5])
- *
- *         // query by example
- *         def a = new Account()
- *         a.number = 495749357
- *         def a = Account.find(a)
- *
- * </code>
- *
- * @author Graeme Rocher
- * @author Steven Devijver
- * @author Sergey Nebolsin
- *
- * @since 0.1
- */
-public class FindAllPersistentMethod extends AbstractStaticPersistentMethod {
-    private final ConversionService conversionService;
-
-    public FindAllPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, Pattern.compile("^findAll$"), application, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName, Closure additionalCriteria, final Object[] arguments) {
-        if (arguments.length == 0) {
-            return getHibernateTemplate().loadAll(clazz);
-        }
-
-        final Object arg = arguments[0] instanceof CharSequence ? arguments[0].toString() : arguments[0];
-
-        // if the arg is an instance of the class find by example
-        if (arg instanceof String) {
-            final String query = ((String) arg).trim();
-            final String shortName = GrailsNameUtils.getShortName(clazz);
-            if (!query.matches("(?i)from(?-i)\\s+[" + clazz.getName() + "|" + shortName + "].*")) {
-                throw new GrailsQueryException("Invalid query [" + query + "] for domain class [" + clazz + "]");
-            }
-
-            return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                    Query q = session.createQuery(query);
-                    getHibernateTemplate().applySettings(q);
-
-                    Object[] queryArgs = null;
-                    Map queryNamedArgs = null;
-                    int max = retrieveMaxValue();
-                    int offset = retrieveOffsetValue();
-                    boolean useCache = useCache();
-                    if (arguments.length > 1) {
-                        if (arguments[1] instanceof Collection) {
-                            queryArgs = GrailsClassUtils.collectionToObjectArray((Collection) arguments[1]);
-                        }
-                        else if (arguments[1].getClass().isArray()) {
-                            queryArgs = (Object[]) arguments[1];
-                        }
-                        else if (arguments[1] instanceof Map) {
-                            queryNamedArgs = (Map) arguments[1];
-                        }
-                    }
-
-                    if (queryArgs != null) {
-                        for (int i = 0; i < queryArgs.length; i++) {
-                            if (queryArgs[i] instanceof CharSequence) {
-                                q.setParameter(i, queryArgs[i].toString());
-                            } else {
-                                q.setParameter(i, queryArgs[i]);
-                            }
-                        }
-                    }
-                    if (queryNamedArgs != null) {
-                        for (Object o : queryNamedArgs.entrySet()) {
-                            Map.Entry entry = (Map.Entry) o;
-                            if (!(entry.getKey() instanceof String)) {
-                                throw new GrailsQueryException("Named parameter's name must be String: " + queryNamedArgs);
-                            }
-                            String stringKey = (String) entry.getKey();
-                            // Won't try to bind these parameters since they are processed separately
-                            if (GrailsHibernateUtil.ARGUMENT_MAX.equals(stringKey) || GrailsHibernateUtil.ARGUMENT_OFFSET.equals(stringKey) || GrailsHibernateUtil.ARGUMENT_CACHE.equals(stringKey))
-                                continue;
-                            Object value = entry.getValue();
-                            if (value == null) {
-                                q.setParameter(stringKey, null);
-                            } else if (value instanceof CharSequence) {
-                                q.setParameter(stringKey, value.toString());
-                            } else if (List.class.isAssignableFrom(value.getClass())) {
-                                q.setParameterList(stringKey, (List) value);
-                            } else if (value.getClass().isArray()) {
-                                q.setParameterList(stringKey, (Object[]) value);
-                            } else {
-                                q.setParameter(stringKey, value);
-                            }
-                        }
-                    }
-                    if (max > 0) {
-                        q.setMaxResults(max);
-                    }
-                    if (offset > 0) {
-                        q.setFirstResult(offset);
-                    }
-                    q.setCacheable(useCache);
-                    return q.list();
-                }
-
-                private boolean useCache() {
-                    boolean useCache = getHibernateTemplate().isCacheQueries();
-                    if (arguments.length > 1 && arguments[arguments.length - 1] instanceof Map) {
-                        useCache = retrieveBoolean(arguments[arguments.length - 1], GrailsHibernateUtil.ARGUMENT_CACHE);
-                    }
-                    return useCache;
-                }
-
-                private int retrieveMaxValue() {
-                    int result = -1;
-                    if (arguments.length > 1) {
-                        result = retrieveInt(arguments[1], GrailsHibernateUtil.ARGUMENT_MAX);
-                        if (arguments.length > 2 && result == -1) {
-                            result = retrieveInt(arguments[2], GrailsHibernateUtil.ARGUMENT_MAX);
-                        }
-                    }
-                    return result;
-                }
-
-                private int retrieveOffsetValue() {
-                    int result = -1;
-                    if (arguments.length > 1) {
-                        if (isMapWithValue(arguments[1], GrailsHibernateUtil.ARGUMENT_OFFSET)) {
-                            result = ((Number)((Map)arguments[1]).get(GrailsHibernateUtil.ARGUMENT_OFFSET)).intValue();
-                        }
-                        if (arguments.length > 2 && result == -1) {
-                            if (isMapWithValue(arguments[2], GrailsHibernateUtil.ARGUMENT_OFFSET)) {
-                                result = retrieveInt(arguments[2], GrailsHibernateUtil.ARGUMENT_OFFSET);
-                            }
-                            else if (isIntegerOrLong(arguments[1]) && isIntegerOrLong(arguments[2])) {
-                                result = ((Number)arguments[2]).intValue();
-                            }
-                        }
-                        if (arguments.length > 3 && result == -1) {
-                            if (isIntegerOrLong(arguments[3])) {
-                                result = ((Number)arguments[3]).intValue();
-                            }
-                        }
-                    }
-                    return result;
-                }
-
-                private boolean retrieveBoolean(Object param, String key) {
-                    boolean value = false;
-                    if (isMapWithValue(param, key)) {
-                        value = conversionService.convert(((Map)param).get(key), Boolean.class);
-                    }
-                    return value;
-                }
-
-                private int retrieveInt(Object param, String key) {
-                    if (isMapWithValue(param, key)) {
-                        return conversionService.convert(((Map) param).get(key),Integer.class);
-                    }
-                    if (isIntegerOrLong(param)) {
-                        return ((Number)param).intValue();
-                    }
-                    return -1;
-                }
-
-                private boolean isIntegerOrLong(Object param) {
-                    return (param instanceof Integer) || (param instanceof Long);
-                }
-
-                private boolean isMapWithValue(Object param, String key) {
-                    return (param instanceof Map) && ((Map)param).containsKey(key);
-                }
-            });
-        }
-
-        if (clazz.isAssignableFrom(arg.getClass())) {
-            return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-
-                    Example example = Example.create(arg).ignoreCase();
-
-                    Criteria crit = session.createCriteria(clazz);
-                    getHibernateTemplate().applySettings(crit);
-                    crit.add(example);
-
-                    Map argsMap = (arguments.length > 1 && (arguments[1] instanceof Map)) ? (Map) arguments[1] : Collections.EMPTY_MAP;
-                    GrailsHibernateUtil.populateArgumentsForCriteria(application,clazz, crit, argsMap, conversionService);
-                    return crit.list();
-                }
-            });
-        }
-
-        if (arguments[0] instanceof Map) {
-            return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                    Criteria crit = session.createCriteria(clazz);
-                    getHibernateTemplate().applySettings(crit);
-                    GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit, (Map)arguments[0], conversionService);
-                    return crit.list();
-                }
-            });
-        }
-
-        throw new MissingMethodException(methodName, clazz, arguments);
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByBooleanPropertyPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByBooleanPropertyPersistentMethod.java
deleted file mode 100644
index ed086a5..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByBooleanPropertyPersistentMethod.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-/**
- * The "find<booleanProperty>By*" static persistent method. This method allows querying for
- * instances of grails domain classes based on a boolean property and any other arbitrary
- * properties. This method returns the first result of the query.
- *
- * eg.
- * Account.findActiveByHolder("Joe Blogs"); // Where class "Account" has a properties called "active" and "holder"
- * Account.findActiveByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "active', "holder" and "branch"
- *
- * In both of those queries, the query will only select Account objects where active=true.
- *
- * @author Jeff Brown
- */
-public class FindByBooleanPropertyPersistentMethod extends FindByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(find)((\\w+)(By)([A-Z]\\w*)|(\\w++))";
-
-    public FindByBooleanPropertyPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore, application,sessionFactory, classLoader);
-        setPattern(Pattern.compile(METHOD_PATTERN));
-    }
-
-    @Override
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return true;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByPersistentMethod.java
deleted file mode 100644
index 973df99..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByPersistentMethod.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-/**
- * The "findBy*" static persistent method. This method allows querying for
- * instances of grails domain classes based on their properties. This method returns the first result of the query
- *
- * eg.
- * Account.findByHolder("Joe Blogs"); // Where class "Account" has a property called "holder"
- * Account.findByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "holder" and "branch"
- *
- * @author Graeme Rocher
- * @since 31-Aug-2005
- */
-public class FindByPersistentMethod extends AbstractFindByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findBy)([A-Z]\\w*)";
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     */
-    public FindByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore,application,sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), OPERATORS);
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrCreateByPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrCreateByPersistentMethod.java
deleted file mode 100644
index 306f352..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrCreateByPersistentMethod.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-import groovy.lang.MissingMethodException;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-@SuppressWarnings("rawtypes")
-public class FindOrCreateByPersistentMethod extends AbstractFindByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findOrCreateBy)([A-Z]\\w*)";
-
-    public FindOrCreateByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        this(datastore, application,sessionFactory, classLoader, METHOD_PATTERN);
-    }
-
-    public FindOrCreateByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader, String pattern) {
-        super(datastore, application,sessionFactory, classLoader, Pattern.compile(pattern), OPERATORS);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    protected Object doInvokeInternalWithExpressions(Class clazz,
-                                                     String methodName, Object[] arguments, List expressions,
-                                                     String operatorInUse, DetachedCriteria detachedCriteria, Closure additionalCriteria) {
-        boolean isValidMethod = true;
-
-        if (OPERATOR_OR.equals(operatorInUse)) {
-            isValidMethod = false;
-        }
-
-        Iterator iterator = expressions.iterator();
-        while (isValidMethod && iterator.hasNext()) {
-            GrailsMethodExpression gme = (GrailsMethodExpression) iterator.next();
-            isValidMethod = GrailsMethodExpression.EQUAL.equals(gme.type);
-        }
-
-        if (!isValidMethod) {
-            throw new MissingMethodException(methodName, clazz, arguments);
-        }
-        Object result = super.doInvokeInternalWithExpressions(clazz, methodName, arguments,
-                expressions, operatorInUse, detachedCriteria, additionalCriteria);
-
-        if (result == null) {
-            Map m = new HashMap();
-            for (Object o : expressions) {
-                GrailsMethodExpression gme = (GrailsMethodExpression) o;
-                m.put(gme.getPropertyName(), gme.getArguments()[0]);
-            }
-            MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(clazz);
-            result = metaClass.invokeConstructor(new Object[]{m});
-            if (shouldSaveOnCreate()) {
-                metaClass.invokeMethod(result, "save", null);
-            }
-        }
-
-        return result;
-    }
-
-    protected boolean shouldSaveOnCreate() {
-        return false;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrSaveByPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrSaveByPersistentMethod.java
deleted file mode 100644
index bae7713..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrSaveByPersistentMethod.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-public class FindOrSaveByPersistentMethod extends FindOrCreateByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findOrSaveBy)([A-Z]\\w*)";
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     */
-    public FindOrSaveByPersistentMethod(HibernateDatastore datastore,GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore, application,sessionFactory, classLoader, METHOD_PATTERN);
-    }
-
-    @Override
-    protected boolean shouldSaveOnCreate() {
-        return true;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindPersistentMethod.java
deleted file mode 100644
index 2028e74..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindPersistentMethod.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.util.GrailsNameUtils;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Example;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * <p>
- * The "find" persistent static method allows searching for instances using
- * either an example instance or an HQL query. This method returns the first
- * result of the query. A GrailsQueryException is thrown if the query is not a
- * valid query for the domain class.
- *
- * <p>
- * Examples in Groovy: <code>
- *         // retrieve the first account ordered by account number
- *         def a = Account.find("from Account as a order by a.number asc")
- *
- *         // with query parameters
- *         def a  = Account.find("from Account as a where a.number = ? and a.branch = ?", [38479, "London"])
- *
- *         // with query named parameters
- *         def a  = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"])
-
- *         // query by example
- *         def a = new Account()
- *         a.number = 495749357
- *         def a = Account.find(a)
- *
- * </code>
- *
- * @author Graeme Rocher
- * @author Sergey Nebolsin
- */
-public class FindPersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String    METHOD_PATTERN    = "^find$";
-    private final ConversionService conversionService;
-
-    public FindPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), application, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName, Closure additionalCriteria, final Object[] arguments) {
-
-        if (arguments.length == 0) {
-            throw new MissingMethodException(methodName, clazz, arguments);
-        }
-
-        final Object arg = arguments[0] instanceof CharSequence ? arguments[0].toString() : arguments[0];
-
-        if (arg instanceof String) {
-            final String query = (String) arg;
-            final String shortName = GrailsNameUtils.getShortName(clazz);
-            if (!query.matches("(?i)from(?-i)\\s+[" + clazz.getName() + "|" + shortName    + "].*")) {
-                throw new GrailsQueryException("Invalid query [" + query + "] for domain class [" + clazz + "]");
-            }
-
-            return getHibernateTemplate().execute(new HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                    Query q = session.createQuery(query);
-                    getHibernateTemplate().applySettings(q);
-                    Object[] queryArgs = null;
-                    Map queryNamedArgs = null;
-                    boolean useCache = useCache(arguments);
-
-                    if (arguments.length > 1) {
-                        if (arguments[1] instanceof Collection) {
-                            queryArgs = GrailsClassUtils.collectionToObjectArray((Collection) arguments[1]);
-                        }
-                        else if (arguments[1].getClass().isArray()) {
-                            queryArgs = (Object[]) arguments[1];
-                        }
-                        else if (arguments[1] instanceof Map) {
-                            queryNamedArgs = (Map) arguments[1];
-                        }
-                    }
-                    if (queryArgs != null) {
-                        for (int i = 0; i < queryArgs.length; i++) {
-                            if (queryArgs[i] instanceof CharSequence) {
-                                q.setParameter(i, queryArgs[i].toString());
-                            }
-                            else {
-                                q.setParameter(i, queryArgs[i]);
-                            }
-                        }
-                    }
-                    if (queryNamedArgs != null) {
-                        for (Iterator it = queryNamedArgs.entrySet().iterator(); it.hasNext();) {
-                            Map.Entry entry = (Map.Entry) it.next();
-                            if (!(entry.getKey() instanceof String)) {
-                                throw new GrailsQueryException("Named parameter's name must be String: " +
-                                        queryNamedArgs.toString());
-                            }
-                            String stringKey = (String) entry.getKey();
-                            Object value = entry.getValue();
-
-                            if (GrailsHibernateUtil.ARGUMENT_CACHE.equals(stringKey)) {
-                                continue;
-                            }
-                            else if (value instanceof CharSequence) {
-                                q.setParameter(stringKey, value.toString());
-                            }
-                            else if (List.class.isAssignableFrom(value.getClass())) {
-                                q.setParameterList(stringKey, (List) value);
-                            }
-                            else if (value.getClass().isArray()) {
-                                q.setParameterList(stringKey, (Object[]) value);
-                            }
-                            else {
-                                q.setParameter(stringKey, value);
-                            }
-                        }
-                    }
-                    // only want one result, could have used uniqueObject here
-                    // but it throws an exception if its not unique which is undesirable
-                    q.setMaxResults(1);
-                    q.setCacheable(useCache);
-                    List results = q.list();
-                    if (results.size() > 0) {
-                        return GrailsHibernateUtil.unwrapIfProxy(results.get(0));
-                    }
-                    return null;
-                }
-
-                private boolean useCache(Object[] args) {
-                    boolean useCache = getHibernateTemplate().isCacheQueries();
-                    if (args.length > 1 && args[args.length - 1] instanceof Map) {
-                        Object param = args[args.length - 1];
-                        String key = GrailsHibernateUtil.ARGUMENT_CACHE;
-                        boolean value = false;
-                        if ((param instanceof Map) && ((Map)param).containsKey(key)) {
-                            value = conversionService.convert(((Map)param).get(key), Boolean.class);
-                        }
-                        useCache = value;
-                    }
-                    return useCache;
-                }
-            });
-        }
-        else if (clazz.isAssignableFrom(arg.getClass())) {
-            // if the arg is an instance of the class find by example
-            return getHibernateTemplate().execute(new HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-
-                    Example example = Example.create(arg).ignoreCase();
-
-                    Criteria crit = session.createCriteria(clazz);
-                    getHibernateTemplate().applySettings(crit);
-                    crit.add(example);
-                    crit.setMaxResults(1);
-                    List results = crit.list();
-                    if (results.size() > 0) {
-                        return results.get(0);
-                    }
-                    return null;
-                }
-            });
-        }
-
-        throw new MissingMethodException(methodName, clazz, arguments);
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListOrderByPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListOrderByPersistentMethod.java
deleted file mode 100644
index 731d588..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListOrderByPersistentMethod.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Locale;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Order;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * The "listOrderBy*" static persistent method. Allows ordered listing of instances based on their properties.
- *
- * eg.
- * Account.listOrderByHolder();
- * Account.listOrderByHolder(max); // max results
- *
- * @author Graeme
- */
-public class ListOrderByPersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(listOrderBy)(\\w+)";
-    private final HibernateDatastore datastore;
-
-    public ListOrderByPersistentMethod(HibernateDatastore datastore, GrailsApplication grailsApplication, SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), grailsApplication, datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractStaticPersistentMethod#doInvokeInternal(java.lang.Class, java.lang.String, java.lang.Object[])
-     */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName, final Closure additionalCriteria, final Object[] arguments) {
-
-        Matcher match = getPattern().matcher(methodName);
-        match.find();
-
-        String nameInSignature = match.group(2);
-        final String propertyName = nameInSignature.substring(0,1).toLowerCase(Locale.ENGLISH) + nameInSignature.substring(1);
-
-        return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Criteria crit = getCriteria(datastore, application, session, null, additionalCriteria, clazz);
-
-                if (arguments != null && arguments.length > 0) {
-                    if (arguments[0] instanceof Map) {
-                        Map argMap = (Map)arguments[0];
-                        argMap.put(GrailsHibernateUtil.ARGUMENT_SORT,propertyName);
-                        GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit, argMap, datastore.getMappingContext().getConversionService());
-                    }
-                    else {
-                        crit.addOrder(Order.asc(propertyName));
-                    }
-                }
-                else {
-                    crit.addOrder(Order.asc(propertyName));
-                }
-                crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                return crit.list();
-            }
-        });
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListPersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListPersistentMethod.java
deleted file mode 100644
index 3871c6c..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListPersistentMethod.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.orm.PagedResultList;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * The "list" persistent static method. This method lists of of the persistent
- * instances up the maximum specified amount (if any)
- *
- * eg.
- * Account.list(); // list all
- * Account.list(max:10,offset:50,sort:"holder",order:"desc"); // list up to 10, offset by 50, sorted by holder and in descending order
- *
- * @author Graeme Rocher
- */
-public class ListPersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String METHOD_PATTERN = "^list$";
-    private final ConversionService conversionService;
-
-    public ListPersistentMethod(GrailsApplication grailsApplication, SessionFactory sessionFactory, ClassLoader classLoader, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), grailsApplication, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @Override
-    @SuppressWarnings("rawtypes")
-    protected Object doInvokeInternal(final Class clazz, String methodName, Closure additionalCriteria, final Object[] arguments) {
-        // and list up to the max
-        return getHibernateTemplate().executeFind(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Criteria c =  session.createCriteria(clazz);
-                getHibernateTemplate().applySettings(c);
-                if (arguments.length > 0 && arguments[0] instanceof Map) {
-                    Map argMap = (Map)arguments[0];
-                    if (argMap.containsKey(GrailsHibernateUtil.ARGUMENT_MAX)) {
-                        c.setMaxResults(Integer.MAX_VALUE);
-                        GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, argMap, conversionService);
-                        c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                        return new PagedResultList(getHibernateTemplate(), c);
-                    }
-
-                    GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, argMap, conversionService);
-                    c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                    return c.list();
-                }
-
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, Collections.EMPTY_MAP, conversionService);
-                c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                return c.list();
-            }
-        });
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/MergePersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/MergePersistentMethod.java
deleted file mode 100644
index 4c2cc8a..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/MergePersistentMethod.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.sql.SQLException;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.HibernateException;
-import org.hibernate.LockMode;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * The merge() method follows the semantics of merge which attempts to "merge" an object
- * with a long lived session.
- *
- * @author Graeme Rocher
- * @since 0.3
- */
-public class MergePersistentMethod extends AbstractSavePersistentMethod {
-
-    public static final String METHOD_SIGNATURE = "merge";
-    public static final Pattern METHOD_PATTERN = Pattern.compile('^'+METHOD_SIGNATURE+'$');
-
-    public MergePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-               GrailsApplication application, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, datastore);
-    }
-
-    public MergePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-               GrailsApplication application, GrailsDomainClass dc, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, dc, datastore);
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod#performSave(java.lang.Object)
-     */
-    @Override
-    protected Object performSave(final Object target, final boolean flush) {
-        return getHibernateTemplate().execute(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Object merged = session.merge(target);
-                session.lock(merged, LockMode.NONE);
-
-                if (flush) {
-                    session.flush();
-                }
-                return merged;
-            }
-        });
-    }
-
-    @Override
-    protected Object performInsert(Object target, boolean shouldFlush) {
-        throw new IllegalArgumentException("The [insert] argument is not supported by the [merge] method");
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/SavePersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/SavePersistentMethod.java
deleted file mode 100644
index 3329d96..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/SavePersistentMethod.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.sql.SQLException;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor;
-import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.orm.hibernate3.HibernateCallback;
-
-/**
- * Follows the semantics of saveOrUpdate of scheduling the object for persistence when a flush occurs.
- *
- * @author Steven Devijver
- * @author Graeme Rocher
- *
- * @since 0.1
- */
-public class SavePersistentMethod extends AbstractSavePersistentMethod {
-
-    public static final String METHOD_SIGNATURE = "save";
-    public static final Pattern METHOD_PATTERN = Pattern.compile('^'+METHOD_SIGNATURE+'$');
-
-    public SavePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-              GrailsApplication application, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, datastore);
-    }
-
-    public SavePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-              GrailsApplication application, GrailsDomainClass domainClass, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, domainClass, datastore);
-    }
-
-    @Override
-    protected Object performSave(final Object target, final boolean flush) {
-        return getHibernateTemplate().execute(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                session.saveOrUpdate(target);
-                if (flush) {
-                    flushSession(session);
-                }
-                return target;
-            }
-        });
-    }
-
-    @Override
-    protected Object performInsert(final Object target, final boolean shouldFlush) {
-        return getHibernateTemplate().execute(new HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                try {
-                    ClosureEventTriggeringInterceptor.markInsertActive();
-                    session.save(target);
-                    if (shouldFlush) {
-                        flushSession(session);
-                    }
-                    return target;
-                } finally {
-                    ClosureEventTriggeringInterceptor.resetInsertActive();
-                }
-            }
-        });
-    }
-
-    protected void flushSession(Session session) throws HibernateException {
-        try {
-            session.flush();
-        } catch (HibernateException e) {
-            // session should not be flushed again after a data acccess exception!
-            session.setFlushMode(FlushMode.MANUAL);
-            throw e;
-        }
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ValidatePersistentMethod.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ValidatePersistentMethod.java
deleted file mode 100644
index cc2d490..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ValidatePersistentMethod.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.validation.ValidationErrors;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.validation.AbstractPersistentConstraint;
-import org.codehaus.groovy.grails.validation.CascadingValidator;
-import org.grails.datastore.mapping.engine.event.ValidationEvent;
-import org.hibernate.SessionFactory;
-import org.springframework.util.Assert;
-import org.springframework.validation.Errors;
-import org.springframework.validation.FieldError;
-import org.springframework.validation.ObjectError;
-import org.springframework.validation.Validator;
-
-/**
- * Validates an instance of a domain class against its constraints.
- *
- * @author Graeme Rocher
- * @since 07-Nov-2005
- */
-public class ValidatePersistentMethod extends AbstractDynamicPersistentMethod {
-
-    public static final String METHOD_SIGNATURE = "validate";
-    public static final Pattern METHOD_PATTERN = Pattern.compile('^'+METHOD_SIGNATURE+'$');
-    public static final String ARGUMENT_DEEP_VALIDATE = "deepValidate";
-    private static final String ARGUMENT_EVICT = "evict";
-    private Validator validator;
-    private HibernateDatastore datastore;
-
-    public ValidatePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application) {
-        this(sessionFactory, classLoader, application, null, null);
-    }
-
-    public ValidatePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-             GrailsApplication application, Validator validator, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, datastore.getDefaultFlushMode());
-        Assert.notNull(application, "Constructor argument 'application' cannot be null");
-        this.validator = validator;
-        this.datastore = datastore;
-    }
-
-    @Override
-    @SuppressWarnings({"unchecked","rawtypes"})
-    protected Object doInvokeInternal(final Object target, Object[] arguments) {
-        Errors errors = setupErrorsProperty(target);
-
-        GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,
-                target.getClass().getName());
-
-        if (validator == null && domainClass != null) {
-            validator = domainClass.getValidator();
-        }
-
-        if (validator == null) {
-            return true;
-        }
-
-        Boolean valid = Boolean.TRUE;
-        // should evict?
-        boolean evict = false;
-        boolean deepValidate = true;
-        Set validatedFields = null;
-        List validatedFieldsList = null;
-
-        if (arguments.length > 0) {
-            if (arguments[0] instanceof Boolean) {
-                evict = (Boolean)arguments[0];
-            }
-            if (arguments[0] instanceof Map) {
-                Map argsMap = (Map)arguments[0];
-
-                if (argsMap.containsKey(ARGUMENT_DEEP_VALIDATE)) {
-                    deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, argsMap);
-                }
-
-                evict = GrailsClassUtils.getBooleanFromMap(ARGUMENT_EVICT, argsMap);
-            }
-            if (arguments[0] instanceof List) {
-                validatedFieldsList = (List)arguments[0];
-                validatedFields = new HashSet(validatedFieldsList);
-            }
-        }
-
-        fireEvent(target, validatedFieldsList);
-
-        AbstractPersistentConstraint.sessionFactory.set(datastore.getSessionFactory());
-        try {
-            if (deepValidate && (validator instanceof CascadingValidator)) {
-                ((CascadingValidator)validator).validate(target, errors, deepValidate);
-            }
-            else {
-                validator.validate(target,errors);
-            }
-        }
-        finally {
-            AbstractPersistentConstraint.sessionFactory.remove();
-        }
-
-        int oldErrorCount = errors.getErrorCount();
-        errors = filterErrors(errors, validatedFields, target);
-
-        if (errors.hasErrors()) {
-            valid = Boolean.FALSE;
-            if (evict) {
-                // if an boolean argument 'true' is passed to the method
-                // and validation fails then the object will be evicted
-                // from the session, ensuring it is not saved later when
-                // flush is called
-                if (getHibernateTemplate().contains(target)) {
-                    getHibernateTemplate().evict(target);
-                }
-            }
-        }
-
-        // If the errors have been filtered, update the 'errors' object attached to the target.
-        if (errors.getErrorCount() != oldErrorCount) {
-            MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass());
-            metaClass.setProperty(target, ERRORS_PROPERTY, errors);
-        }
-
-        return valid;
-    }
-
-    private void fireEvent(Object target, List<?> validatedFieldsList) {
-        ValidationEvent event = new ValidationEvent(datastore, target);
-        event.setValidatedFields(validatedFieldsList);
-        application.getMainContext().publishEvent(event);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private Errors filterErrors(Errors errors, Set validatedFields, Object target) {
-        if (validatedFields == null) return errors;
-
-        ValidationErrors result = new ValidationErrors(target);
-
-        final List allErrors = errors.getAllErrors();
-        for (Object allError : allErrors) {
-            ObjectError error = (ObjectError) allError;
-
-            if (error instanceof FieldError) {
-                FieldError fieldError = (FieldError) error;
-                if (!validatedFields.contains(fieldError.getField())) continue;
-            }
-
-            result.addError(error);
-        }
-
-        return result;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwarePojoEntityTuplizer.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwarePojoEntityTuplizer.java
new file mode 100644
index 0000000..1059dcd
--- /dev/null
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwarePojoEntityTuplizer.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2014 original authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.grails.orm.hibernate.proxy;
+
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.tuple.entity.PojoEntityTuplizer;
+
+/**
+ * Ensures a Groovy aware proxy factory is registered
+ *
+ * @author Graeme Rocher
+ * @since 4.0
+ */
+public class GroovyAwarePojoEntityTuplizer extends PojoEntityTuplizer {
+
+    public GroovyAwarePojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
+        super(entityMetamodel, mappedEntity);
+    }
+
+    @Override
+    protected ProxyFactory buildProxyFactoryInternal(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
+        return new GroovyAwareJavassistProxyFactory();
+    }
+}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java
index be752f0..bf8ffe5 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java
@@ -16,15 +16,8 @@
 package org.codehaus.groovy.grails.orm.hibernate.proxy;
 
 
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.support.proxy.EntityProxyHandler;
-import org.grails.datastore.mapping.reflect.ClassPropertyFetcher;
-import org.hibernate.Hibernate;
 import org.hibernate.collection.AbstractPersistentCollection;
 import org.hibernate.collection.PersistentCollection;
-import org.hibernate.proxy.HibernateProxy;
-import org.hibernate.proxy.HibernateProxyHelper;
-import org.hibernate.proxy.LazyInitializer;
 
 /**
  * Implementation of the ProxyHandler interface for Hibernate.
@@ -32,96 +25,36 @@
  * @author Graeme Rocher
  * @since 1.2.2
  */
-public class HibernateProxyHandler implements EntityProxyHandler {
+public class HibernateProxyHandler extends SimpleHibernateProxyHandler {
 
     public boolean isInitialized(Object o) {
-        if (o instanceof HibernateProxy) {
-            return !((HibernateProxy)o).getHibernateLazyInitializer().isUninitialized();
-        }
-
         if (o instanceof PersistentCollection) {
             return ((PersistentCollection)o).wasInitialized();
         }
 
-        return true;
-    }
-
-    public boolean isInitialized(Object obj, String associationName) {
-        try {
-            Object proxy = ClassPropertyFetcher.forClass(obj.getClass()).getPropertyValue(obj, associationName);
-            return Hibernate.isInitialized(proxy);
-        }
-        catch (RuntimeException e) {
-            return false;
-        }
+        return super.isInitialized(o);
     }
 
     public Object unwrapIfProxy(Object instance) {
-        if (instance instanceof HibernateProxy) {
-            final HibernateProxy proxy = (HibernateProxy)instance;
-            return unwrapProxy(proxy);
-        }
-
         if (instance instanceof AbstractPersistentCollection) {
             initialize(instance);
             return instance;
         }
 
-        return instance;
-    }
-
-    public Object unwrapProxy(final HibernateProxy proxy) {
-        final LazyInitializer lazyInitializer = proxy.getHibernateLazyInitializer();
-        if (lazyInitializer.isUninitialized()) {
-            lazyInitializer.initialize();
-        }
-        final Object obj = lazyInitializer.getImplementation();
-        if (obj != null) {
-            GrailsHibernateUtil.ensureCorrectGroovyMetaClass(obj,obj.getClass());
-        }
-        return obj;
-    }
-
-    public HibernateProxy getAssociationProxy(Object obj, String associationName) {
-        try {
-            Object proxy = ClassPropertyFetcher.forClass(obj.getClass()).getPropertyValue(obj, associationName);
-            if (proxy instanceof HibernateProxy) {
-                return (HibernateProxy) proxy;
-            }
-            return null;
-        }
-        catch (RuntimeException e) {
-            return null;
-        }
+        return super.unwrapIfProxy(instance);
     }
 
     public boolean isProxy(Object o) {
-        return (o instanceof HibernateProxy) || (o instanceof AbstractPersistentCollection);
+        return super.isProxy(o) || (o instanceof AbstractPersistentCollection);
     }
 
     public void initialize(Object o) {
-        if (o instanceof HibernateProxy) {
-            final LazyInitializer hibernateLazyInitializer = ((HibernateProxy)o).getHibernateLazyInitializer();
-            if (hibernateLazyInitializer.isUninitialized()) {
-                hibernateLazyInitializer.initialize();
-            }
-        }
-        else if (o instanceof AbstractPersistentCollection) {
+        if (o instanceof AbstractPersistentCollection) {
             final AbstractPersistentCollection col = (AbstractPersistentCollection)o;
             if (!col.wasInitialized()) {
                 col.forceInitialization();
             }
         }
-    }
-
-    public Object getProxyIdentifier(Object o) {
-        if (o instanceof HibernateProxy) {
-            return ((HibernateProxy)o).getHibernateLazyInitializer().getIdentifier();
-        }
-        return null;
-    }
-
-    public Class<?> getProxiedClass(Object o) {
-        return HibernateProxyHelper.getClassWithoutInitializingProxy(o);
+        super.initialize(o);
     }
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java
index 27149c7..0418349 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java
@@ -28,11 +28,11 @@
 import org.apache.commons.logging.LogFactory;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils;
 import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormValidationApi;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.Mapping;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ValidatePersistentMethod;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
 import org.grails.datastore.gorm.support.BeforeValidateHelper.BeforeValidateEventTriggerCaller;
 import org.grails.datastore.gorm.support.EventTriggerCaller;
@@ -90,7 +90,7 @@
     Map validateParams;
     MetaMethod validateMethod;
     TimestampProvider timestampProvider;
-    
+
     public ClosureEventListener(Class<?> domainClazz, boolean failOnError, List failOnErrorPackages) {
         this(domainClazz, failOnError, failOnErrorPackages, new DefaultTimestampProvider());
     }
@@ -122,11 +122,11 @@
         }
 
         validateParams = new HashMap();
-        validateParams.put(ValidatePersistentMethod.ARGUMENT_DEEP_VALIDATE, Boolean.FALSE);
+        validateParams.put(AbstractHibernateGormValidationApi.ARGUMENT_DEEP_VALIDATE, Boolean.FALSE);
 
-        errorsProperty = domainMetaClass.getMetaProperty(AbstractDynamicPersistentMethod.ERRORS_PROPERTY);
+        errorsProperty = domainMetaClass.getMetaProperty(GrailsDomainClassProperty.ERRORS);
 
-        validateMethod = domainMetaClass.getMetaMethod(ValidatePersistentMethod.METHOD_SIGNATURE,
+        validateMethod = domainMetaClass.getMetaMethod("validate",
                 new Object[] { Map.class });
         
         try {
@@ -155,7 +155,7 @@
             shouldTimestamp = false;
         }
     }
-
+            
     private boolean verifyTimestampFieldTypeSupport(Class<?> domainClazz, TimestampProvider timestampProvider, MetaProperty timestampField) {
         if(timestampProvider.supportsCreating(timestampField.getType())) {
             return true;
@@ -253,7 +253,7 @@
 
     public void onPostInsert(PostInsertEvent event) {
         final Object entity = event.getEntity();
-        AbstractSavePersistentMethod.clearDisabledValidations(entity);
+        AbstractHibernateGormInstanceApi.clearDisabledValidations(entity);
         if (postInsertEventListener == null) {
             return;
         }
@@ -269,7 +269,7 @@
 
     public void onPostUpdate(PostUpdateEvent event) {
         final Object entity = event.getEntity();
-        AbstractSavePersistentMethod.clearDisabledValidations(entity);
+        AbstractHibernateGormInstanceApi.clearDisabledValidations(entity);
         if (postUpdateEventListener == null) {
             return;
         }
@@ -285,7 +285,7 @@
 
     public void onPostDelete(PostDeleteEvent event) {
         final Object entity = event.getEntity();
-        AbstractSavePersistentMethod.clearDisabledValidations(entity);
+        AbstractHibernateGormInstanceApi.clearDisabledValidations(entity);
         if (postDeleteEventListener == null) {
             return;
         }
@@ -311,7 +311,7 @@
             }
         });
     }
-    
+
     public boolean onPreUpdate(final PreUpdateEvent event) {
         return doWithManualSession(event, new Closure<Boolean>(this) {
             @Override
@@ -323,7 +323,7 @@
                     synchronizePersisterState(event, event.getState());
                 }
                 handleTimestampingBeforeUpdate(event, entity);
-                if (!AbstractSavePersistentMethod.isAutoValidationDisabled(entity)
+                if (!AbstractHibernateGormInstanceApi.isAutoValidationDisabled(entity)
                         && !DefaultTypeTransformation.castToBoolean(validateMethod.invoke(entity, new Object[] { validateParams }))) {
                     evict = true;
                     if (failOnErrorEnabled) {
@@ -367,7 +367,7 @@
                 }
 
                 boolean evict = false;
-                if (!AbstractSavePersistentMethod.isAutoValidationDisabled(entity)
+                if (!AbstractHibernateGormInstanceApi.isAutoValidationDisabled(entity)
                         && !DefaultTypeTransformation.castToBoolean(validateMethod.invoke(entity,
                                 new Object[] { validateParams }))) {
                     evict = true;
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java
index dc484ac..4accc47 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java
@@ -18,6 +18,7 @@
 import grails.util.CollectionUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
 import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
 import org.codehaus.groovy.grails.orm.hibernate.SessionFactoryProxy;
 import org.codehaus.groovy.grails.orm.hibernate.events.SaveOrUpdateEventListener;
@@ -81,7 +82,7 @@
     private ApplicationContext ctx;
     private Map<SessionFactory, HibernateDatastore> datastores;
 
-    private static final ThreadLocal<Boolean> insertActiveThreadLocal = new ThreadLocal<Boolean>();
+
 
     public ClosureEventTriggeringInterceptor() {
         try {
@@ -322,7 +323,7 @@
      */
     @Override
     protected Boolean getAssumedUnsaved() {
-        return insertActiveThreadLocal.get();
+        return AbstractHibernateGormInstanceApi.getAssumedUnsaved();
     }
 
     /**
@@ -330,13 +331,13 @@
      * to set a ThreadLocal variable that determines the value for getAssumedUnsaved().
      */
     public static void markInsertActive() {
-        insertActiveThreadLocal.set(Boolean.TRUE);
+        AbstractHibernateGormInstanceApi.markInsertActive();
     }
 
     /**
      * Clears the ThreadLocal variable set by markInsertActive().
      */
     public static void resetInsertActive() {
-        insertActiveThreadLocal.remove();
+        AbstractHibernateGormInstanceApi.resetInsertActive();
     }
 }
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java
index 327db75..b28d9c4 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java
@@ -14,8 +14,8 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
+import grails.web.mapping.mvc.RedirectEventListener;
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.web.servlet.mvc.RedirectEventListener;
 import org.hibernate.FlushMode;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java
index bd5dba9..40adc5a 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java
@@ -14,13 +14,10 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
 
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod;
-import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest;
-import org.codehaus.groovy.grails.web.sitemesh.GrailsContentBufferingResponse;
+import org.grails.web.servlet.mvc.GrailsWebRequest;
 import org.hibernate.FlushMode;
 import org.hibernate.HibernateException;
 import org.hibernate.Session;
@@ -95,19 +92,6 @@
                 return;
             }
 
-            GrailsWebRequest webRequest = (GrailsWebRequest) request;
-            HttpServletResponse response = webRequest.getCurrentResponse();
-            GrailsContentBufferingResponse contentBufferingResponse = getContentBufferingResponse(response);
-            if (contentBufferingResponse == null) {
-                super.afterCompletion(request, ex);
-                return;
-            }
-
-            // if Sitemesh is still active disconnect the session, but don't close the session
-            if (!contentBufferingResponse.isActive()) {
-                super.afterCompletion(request, ex);
-                return;
-            }
 
             try {
                 Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
@@ -119,20 +103,10 @@
                 super.afterCompletion(request, ex);
             }
         } finally {
-            AbstractSavePersistentMethod.clearDisabledValidations();
+            AbstractHibernateGormInstanceApi.clearDisabledValidations();
         }
     }
 
-    private GrailsContentBufferingResponse getContentBufferingResponse(HttpServletResponse response) {
-        while(response instanceof HttpServletResponseWrapper) {
-            if (response instanceof GrailsContentBufferingResponse) {
-                return (GrailsContentBufferingResponse) response;
-            }
-            response = (HttpServletResponse) ((HttpServletResponseWrapper) response).getResponse();
-        }
-        return null;
-    }
-
     @Override
     protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
         if (session != null && !FlushMode.isManualFlushMode(session.getFlushMode())) {
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
index e34d374..9214eff 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
@@ -15,6 +15,9 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
+import grails.config.Config;
+import grails.core.GrailsApplication;
+import grails.core.support.GrailsApplicationAware;
 import groovy.util.ConfigObject;
 
 import java.sql.Connection;
@@ -22,9 +25,7 @@
 
 import javax.sql.DataSource;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
 import org.codehaus.groovy.grails.orm.hibernate.exceptions.CouldNotDetermineHibernateDialectException;
-import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware;
 import org.hibernate.HibernateException;
 import org.hibernate.dialect.Dialect;
 import org.hibernate.dialect.resolver.DialectFactory;
@@ -79,7 +80,7 @@
             connection = DataSourceUtils.getConnection(dataSource);
 
             try {
-                ConfigObject config = grailsApplication != null ? grailsApplication.getConfig() : null;
+                Config config = grailsApplication != null ? grailsApplication.getConfig() : null;
                 Properties properties = config != null ? config.toProperties() : new Properties();
                 hibernateDialect = DialectFactory.buildDialect(properties, connection);
                 hibernateDialectClassName = hibernateDialect.getClass().getName();
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java
index 0a55366..5b8b9d7 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java
@@ -15,14 +15,14 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
+import grails.core.GrailsDomainClassProperty;
+import grails.persistence.support.PersistenceContextInterceptor;
 import grails.validation.DeferredBindingActions;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod;
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor;
+import org.grails.core.lifecycle.ShutdownOperations;
 import org.hibernate.FlushMode;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
@@ -98,7 +98,7 @@
                 LOG.error("Unexpected exception on closing Hibernate Session", ex);
             }
         } finally {
-            AbstractSavePersistentMethod.clearDisabledValidations();
+            AbstractHibernateGormInstanceApi.clearDisabledValidations();
         }
     }
 
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java
deleted file mode 100644
index c57cdcb..0000000
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/AbstractPersistentConstraint.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/* Copyright 2004-2005 Graeme Rocher
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.validation;
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.validation.AbstractConstraint;
-import org.hibernate.SessionFactory;
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.orm.hibernate3.HibernateTemplate;
-
-/**
- * Constraints that require access to the HibernateTemplate should subclass this class.
- *
- * @author Graeme Rocher
- * @since 0.4
- */
-public abstract class AbstractPersistentConstraint extends AbstractConstraint implements PersistentConstraint {
-
-    public static ThreadLocal<SessionFactory> sessionFactory = new ThreadLocal<SessionFactory>();
-
-    static {
-        ShutdownOperations.addOperation(new Runnable() {
-            public void run() {
-                sessionFactory.remove();
-            }
-        });
-    }
-
-    protected ApplicationContext applicationContext;
-
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
-        this.applicationContext = applicationContext;
-    }
-
-    public HibernateTemplate getHibernateTemplate() {
-        SessionFactory sf = sessionFactory.get();
-        if (sf == null) {
-            sf = applicationContext.getBean("sessionFactory", SessionFactory.class);
-        }
-        GrailsApplication app = applicationContext.getBean("grailsApplication", GrailsApplication.class);
-        GrailsHibernateTemplate hibernateTemplate = new GrailsHibernateTemplate(sf, app, GrailsHibernateTemplate.FLUSH_NEVER);
-        hibernateTemplate.setAllowCreate(true);
-        return hibernateTemplate;
-    }
-
-    /**
-     * Returns whether the constraint supports being applied against the specified type;
-     *
-     * @param type The type to support
-     * @return true if the constraint can be applied against the specified type
-     */
-    public boolean supports(@SuppressWarnings("rawtypes") Class type) {
-        return true;
-    }
-
-    /**
-     * Return whether the constraint is valid for the owning class
-     *
-     * @return true if it is
-     */
-    public boolean isValid() {
-        if (applicationContext.containsBean("sessionFactory")) {
-            GrailsApplication grailsApplication = applicationContext.getBean(
-                    GrailsApplication.APPLICATION_ID, GrailsApplication.class);
-            GrailsDomainClass domainClass = (GrailsDomainClass)grailsApplication.getArtefact(
-                    DomainClassArtefactHandler.TYPE, constraintOwningClass.getName());
-            if (domainClass != null) {
-                String mappingStrategy = domainClass.getMappingStrategy();
-                return mappingStrategy.equals(GrailsDomainClass.GORM)
-                    || mappingStrategy.equals(GrailsHibernateDomainClass.HIBERNATE);
-            }
-        }
-        return false;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java
index 08c5d22..a548018 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java
@@ -16,11 +16,12 @@
 
 import java.util.Map;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClassProperty;
+import grails.validation.Constrained;
+import grails.validation.ConstrainedProperty;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.PropertyConfig;
-import org.codehaus.groovy.grails.validation.ConstrainedProperty;
-import org.codehaus.groovy.grails.validation.DefaultConstraintEvaluator;
+import org.grails.validation.DefaultConstraintEvaluator;
 
 /**
  * Extends default implementation to add Hibernate specific exceptions.
@@ -39,7 +40,7 @@
     }
 
     @Override
-    protected void applyDefaultNullableConstraint(GrailsDomainClassProperty p, ConstrainedProperty cp) {
+    protected void applyDefaultNullableConstraint(GrailsDomainClassProperty p, Constrained cp) {
         final PropertyConfig propertyConfig = new GrailsDomainBinder().getPropertyConfig(p);
         boolean insertable = propertyConfig != null ? propertyConfig.isInsertable() : true;
 
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java
index 7e125d1..7ca165b 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java
@@ -14,12 +14,12 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.validation;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.core.support.proxy.ProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.HibernateProxyHandler;
-import org.codehaus.groovy.grails.support.proxy.ProxyHandler;
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.grails.validation.GrailsDomainClassValidator;
 import org.hibernate.FlushMode;
 import org.hibernate.Hibernate;
 import org.hibernate.SessionFactory;
diff --git a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java
index 2204f01..b3e21fd 100644
--- a/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java
+++ b/grails-datastore-gorm-hibernate/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java
@@ -18,18 +18,19 @@
 import java.util.Collections;
 import java.util.List;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.exceptions.GrailsRuntimeException;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
-import org.codehaus.groovy.grails.validation.ConstrainedProperty;
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.util.GrailsClassUtils;
+import grails.validation.ConstrainedProperty;
+import groovy.lang.Closure;
+import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
+import org.codehaus.groovy.grails.orm.hibernate.IHibernateTemplate;
 import org.codehaus.groovy.runtime.InvokerHelper;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.grails.core.exceptions.GrailsRuntimeException;
+import org.grails.core.lifecycle.ShutdownOperations;
+import org.hibernate.*;
 import org.hibernate.criterion.Restrictions;
 import org.hibernate.metadata.ClassMetadata;
 import org.springframework.beans.BeanWrapper;
@@ -146,24 +147,23 @@
                   "domain classes and not custom user types or embedded instances");
         }
 
-        HibernateTemplate hibernateTemplate = getHibernateTemplate();
-        Assert.state(hibernateTemplate != null,
-              "Unable use [unique] constraint, no Hibernate SessionFactory found!");
-        List<?> results = hibernateTemplate.execute(new HibernateCallback<List<?>>() {
-            public List<?> doInHibernate(Session session) throws HibernateException {
+        IHibernateTemplate hibernateTemplate = getHibernateTemplate();
+        List<?> results = hibernateTemplate.execute(new Closure<List<?>>(this) {
+            public List<?> call(Object... args) {
+                Session session = (Session)args[0];
                 boolean shouldValidate = true;
                 Class<?> constraintClass = constraintOwningClass;
                 if (propertyValue != null && DomainClassArtefactHandler.isDomainClass(propertyValue.getClass())) {
                     shouldValidate = session.contains(propertyValue);
                 }
                 if (shouldValidate) {
-                    GrailsApplication application  = (GrailsApplication) applicationContext.getBean(GrailsApplication.APPLICATION_ID);
-                    GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,constraintClass.getName());
+                    GrailsApplication application = (GrailsApplication) applicationContext.getBean(GrailsApplication.APPLICATION_ID);
+                    GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE, constraintClass.getName());
                     if (domainClass != null && !domainClass.isRoot()) {
                         GrailsDomainClassProperty property = domainClass.getPropertyByName(constraintPropertyName);
                         while (property.isInherited() && domainClass != null) {
                             domainClass = (GrailsDomainClass) application.getArtefact(
-                                    DomainClassArtefactHandler.TYPE,domainClass.getClazz().getSuperclass().getName());
+                                    DomainClassArtefactHandler.TYPE, domainClass.getClazz().getSuperclass().getName());
                             if (domainClass != null) {
                                 property = domainClass.getPropertyByName(constraintPropertyName);
                             }
@@ -188,7 +188,7 @@
                         criteria.add(Restrictions.eq(constraintPropertyAlias + "." + identifierPropertyName, identifierPropertyValue));
                     } else {
                         criteria = session.createCriteria(constraintClass)
-                            .add(Restrictions.eq(constraintPropertyName, propertyValue));
+                                .add(Restrictions.eq(constraintPropertyName, propertyValue));
                     }
 
                     if (uniquenessGroup != null) {
@@ -202,8 +202,7 @@
                             }
                             if (shouldValidate) {
                                 criteria.add(Restrictions.eq(uniquenessGroupPropertyName, uniquenessGroupPropertyValue));
-                            }
-                            else {
+                            } else {
                                 break; // we aren't validating, so no point continuing
                             }
                         }
@@ -215,7 +214,7 @@
                     return Collections.EMPTY_LIST;
                 }
                 return Collections.EMPTY_LIST;
-            }
+           }
         });
 
         if (results.isEmpty()) {
@@ -249,4 +248,15 @@
         return uniquenessGroup;
     }
 
+    @Override
+    public IHibernateTemplate getHibernateTemplate() {
+        SessionFactory sf = sessionFactory.get();
+        if (sf == null) {
+            sf = applicationContext.getBean("sessionFactory", SessionFactory.class);
+        }
+        GrailsApplication app = applicationContext.getBean("grailsApplication", GrailsApplication.class);
+        GrailsHibernateTemplate hibernateTemplate = new GrailsHibernateTemplate(sf, app, GrailsHibernateTemplate.FLUSH_NEVER);
+        hibernateTemplate.setAllowCreate(true);
+        return hibernateTemplate;
+    }
 }
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy
index 54d0755..e1d0c83 100755
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy
@@ -1,8 +1,8 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
 import grails.gorm.tests.GormDatastoreSpec
 import junit.framework.Assert
-import org.codehaus.groovy.grails.commons.GrailsApplication
 import org.grails.datastore.mapping.core.DatastoreUtils
 import org.hibernate.Session
 import org.hibernate.SessionFactory
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy
index 4a993d6..1dc5ef0 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 import static junit.framework.Assert.*
 /**
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy
index 1dac0a7..515f640 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
+import grails.core.DefaultGrailsApplication
 import org.codehaus.groovy.grails.orm.hibernate.cfg.DefaultGrailsDomainConfiguration
 import org.hibernate.FetchMode
 import org.hibernate.engine.CascadeStyle
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy
index 0daf708..639107a 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 
 import static junit.framework.Assert.*
 import org.junit.Test
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy
index 54c8dfe..4d1d29b 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy
index 6b9dcdd..21efb82 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy
index 75c4869..5b6ca1d 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy
index e49edb8..1f49801 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy
index 0c2ebb2..d608071 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
 import grails.gorm.tests.Plant
-import org.codehaus.groovy.grails.web.util.StreamCharBuffer
+import org.grails.buffer.StreamCharBuffer
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
index 87e87ec..a80ad14 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
@@ -76,9 +76,12 @@
     }
 }
 
+trait SomeTrait {
+    void foo(){}
+}
 
 @Entity
-class CompositeIdentifierWithAssociationsParent implements Serializable {
+class CompositeIdentifierWithAssociationsParent implements Serializable, SomeTrait {
     Long id
     Long version
 
@@ -118,4 +121,4 @@
     String postCode
     CompositeIdentifierWithAssociationsParent parent
     static belongsTo = [parent:CompositeIdentifierWithAssociationsParent]
-}
\ No newline at end of file
+}
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy
index 9cf1acc..cd6974f 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy
@@ -1,9 +1,9 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
 import grails.persistence.Entity
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
 import org.hibernate.id.IdentifierGenerationException
 import org.springframework.orm.hibernate3.HibernateSystemException
 
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy
index 48121f0..9566cb7 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy
@@ -1,7 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy
index d28511b..5f995b2 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
 import grails.gorm.tests.GormDatastoreSpec
-import org.codehaus.groovy.grails.commons.GrailsApplication
 import org.hibernate.SessionFactory
 import org.springframework.context.ApplicationContext
 import spock.lang.Shared
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy
index f793bf3..7885dc8 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy
@@ -1,11 +1,9 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.orm.HibernateCriteriaBuilder
 import grails.persistence.Entity
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.junit.Test
 import static junit.framework.Assert.*
 
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy
index a0df03f..2c1e235 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy
@@ -1,7 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import grails.persistence.Entity
-
+import javax.persistence.Entity
 import javax.persistence.GeneratedValue
 import javax.persistence.Id
 import javax.persistence.JoinColumn
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy
index 5cd2994..e4527ac 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.apache.commons.beanutils.PropertyUtils
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
+import org.grails.core.util.ClassPropertyFetcher
 import org.hibernate.Hibernate
 import org.hibernate.proxy.HibernateProxy
 
@@ -19,6 +19,7 @@
 
     @Test
 	void testDynamicMethodOnProxiedObject() {
+        def cpf = ClassPropertyFetcher.forClass(LazyLoadedUserIdentifier)
 		def user = LazyLoadedUser.newInstance(name:"Fred")
 
 		assertNotNull user.save(flush:true)
@@ -29,7 +30,7 @@
 		session.clear()
 
 		id = LazyLoadedUserIdentifier.get(1)
-		def proxy = PropertyUtils.getProperty(id, "user")
+		def proxy = cpf.getPropertyValue(id, "user")
 		assertTrue "should be a hibernate proxy", (proxy instanceof HibernateProxy)
 		assertFalse "proxy should not be initialized", Hibernate.isInitialized(proxy)
 		assertNotNull "calling save() on the proxy should have worked",proxy.save()
@@ -37,6 +38,7 @@
 
     @Test
 	void testMethodCallsOnProxiedObjects() {
+        def cpf = ClassPropertyFetcher.forClass(LazyLoadedUserIdentifier)
 		def user = LazyLoadedUser.newInstance(name:"Fred")
 		assertNotNull user.save(flush:true)
 
@@ -47,7 +49,7 @@
 
 		id = LazyLoadedUserIdentifier.get(1)
 
-		def proxy = PropertyUtils.getProperty(id, "user")
+		def proxy = cpf.getPropertyValue(id, "user")
 		assertTrue "should be a hibernate proxy", (proxy instanceof HibernateProxy)
 		assertFalse "proxy should not be initialized", Hibernate.isInitialized(proxy)
 		assertEquals "Fred", proxy.name
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy
index 806d86d..6404ec3 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy
@@ -1,8 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
 import grails.persistence.Entity
-
-import org.apache.commons.beanutils.PropertyUtils
+import org.grails.core.util.ClassPropertyFetcher
 import org.hibernate.proxy.HibernateProxy
 
 import static junit.framework.Assert.*
@@ -30,6 +29,7 @@
     @Test
     void testMethodCallsOnProxiedObjects() {
 
+        def cpf = ClassPropertyFetcher.forClass(LazyProxiedAssociationsWithInheritanceBook)
         def addr = LazyProxiedAssociationsWithInheritanceAddress.newInstance(houseNumber:'52')
         def auth = LazyProxiedAssociationsWithInheritanceAuthor.newInstance(name:'Marc Palmer')
         assertNotNull addr.save()
@@ -44,7 +44,7 @@
         session.clear()
 
         book = LazyProxiedAssociationsWithInheritanceBook.get(1)
-        def proxy = PropertyUtils.getProperty(book, "author")
+        def proxy = cpf.getPropertyValue(book, "author")
         assertTrue "should be a hibernate proxy", (proxy instanceof HibernateProxy)
         assertFalse "proxy should not be initialized", org.hibernate.Hibernate.isInitialized(proxy)
 
@@ -61,6 +61,7 @@
 
     @Test
     void testSettersOnProxiedObjects() {
+        def cpf = ClassPropertyFetcher.forClass(LazyProxiedAssociationsWithInheritanceBook)
         def Author = ga.getDomainClass(LazyProxiedAssociationsWithInheritanceAuthor.name).clazz
         def Address = ga.getDomainClass(LazyProxiedAssociationsWithInheritanceAddress.name).clazz
         def Book = ga.getDomainClass(LazyProxiedAssociationsWithInheritanceBook.name).clazz
@@ -80,7 +81,7 @@
 
         book = Book.get(1)
 
-        def proxy = PropertyUtils.getProperty(book, "author")
+        def proxy = cpf.getPropertyValue(book, "author")
         // test setter with non-null value
         proxy.address.houseNumber = '123'
         book.save()
@@ -96,7 +97,7 @@
 
         // test setting property to null
         book = Book.get(1)
-        proxy = PropertyUtils.getProperty(book, "author")
+        proxy = cpf.getPropertyValue(book, "author")
         proxy.address.houseNumber = null
 
         book.save()
@@ -111,7 +112,7 @@
         // should delegate call to the closure defined in HibernatePluginSupport.enhanceProxy
         // this broke with previous code
         book = Book.get(1)
-        proxy = PropertyUtils.getProperty(book, "author")
+        proxy = cpf.getPropertyValue(book, "author")
         proxy.address = null
         book.save()
         session.flush()
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy
index d5035cc..b2c60d2 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy
@@ -1,6 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
+
 import static junit.framework.Assert.*
 import org.junit.Test
 
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy
index ed7286e..5e93b2c 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy
index f519e88..57b1c57 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy
@@ -1,10 +1,8 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
-import org.codehaus.groovy.grails.plugins.GrailsPlugin
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
 import org.hibernate.type.YesNoType
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/NamedCriteriaTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/NamedCriteriaTests.groovy
index 3e40cd9..97ebded 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/NamedCriteriaTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/NamedCriteriaTests.groovy
@@ -3,6 +3,7 @@
 import grails.orm.PagedResultList
 
 import org.hibernate.NonUniqueResultException
+import org.junit.Ignore
 
 import static junit.framework.Assert.*
 import org.junit.Test
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy
index 7fe0c03..baca56e 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy
@@ -1,6 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
+
 import static junit.framework.Assert.*
 import org.junit.Test
 
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy
index cac450e..76e6e70 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy
@@ -1,12 +1,11 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByPersistentMethod
 import org.codehaus.groovy.runtime.metaclass.MethodSelectionException
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.springframework.core.convert.ConversionFailedException
 import org.springframework.validation.Errors
 
@@ -24,15 +23,6 @@
     }
 
     @Test
-    void testMethodSignatures() {
-        FindByPersistentMethod findBy = new FindByPersistentMethod(grailsApplication.mainContext.hibernateDatastore,
-            grailsApplication, sessionFactory, new GroovyClassLoader())
-        assertTrue findBy.isMethodMatch("findByFirstName")
-        assertTrue findBy.isMethodMatch("findByFirstNameAndLastName")
-        assertFalse findBy.isMethodMatch("rubbish")
-    }
-
-    @Test
     void testSavePersistentMethod() {
         // init spring config
 
@@ -317,7 +307,7 @@
         assertEquals 1, returnList.size()
 
         // and case when automatic conversion cannot be applied
-        shouldFail(ConversionFailedException) {
+        shouldFail(MissingMethodException) {
             returnList = domainClass.findAllById("1.1")
         }
 
@@ -606,14 +596,14 @@
         // test find with max result
         namedArgs.clear()
         namedArgs.namesList = ["wilma","fred"] as Object[]
-        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, [max:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
         assertEquals 1, listResult.size()
 
         // test find with max result without params
-        returnValue = domainClass.findAll("from PersistentMethodTests as p", 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p", [max:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
@@ -643,7 +633,7 @@
         // test find with offset
         namedArgs.clear()
         namedArgs.namesList = ["wilma","fred"] as Object[]
-        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, 2, 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, [max:1, offset:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
@@ -651,7 +641,7 @@
         assertEquals 1, listResult.size()
 
         // test find with offset without params
-        returnValue = domainClass.findAll("from PersistentMethodTests as p", 2, 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p", [max:1, offset:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
@@ -783,12 +773,12 @@
             domainClass.executeQuery()
         }
 
-        shouldFail(MissingMethodException) {
+        shouldFail(IllegalArgumentException) {
             domainClass.executeQuery("query", "param", [:], "4")
         }
 
         // test query with wrong third param type (must be Map)
-        shouldFail(MissingMethodException) {
+        shouldFail(IllegalArgumentException) {
             domainClass.executeQuery("query", "param", "wrong third param")
         }
 
@@ -863,10 +853,6 @@
         assertEquals 1, listResult.size()
         assertEquals "fred", listResult[0].getProperty("firstName")
 
-        def msg = shouldFail(IllegalArgumentException) {
-            domainClass.executeQuery 'select distinct p from PersistentMethodTests as p where p.firstName = :firstName and p.lastName = :lastName', [firstName: null, lastName: 'King']
-        }
-        assertEquals 'Named parameter [firstName] value may not be null', msg
 
         // Test that executeQuery does not mutate List and Map arguments (GRAILS-7841)
         paginateParams = [max: 1]
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy
index 75e1e2c..a4a9d07 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy
@@ -142,7 +142,6 @@
     Long version
 
     String name
-    Set unibooks
 
     Set books
     static hasMany = [books:SortMappingBook]
@@ -174,7 +173,6 @@
     Long version
 
     String name
-    Set unibooks
 
     Set books
     static hasMany = [books:SortMappingBook2]
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy
index 90e2235..baa7736 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 
 import static junit.framework.Assert.*
 import org.junit.Test
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy
index e755679..af22ce6 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy
@@ -22,7 +22,7 @@
 
         a.addToBooks(MappedU2mBook.newInstance(title:"The Shining"))
          .addToBooks(MappedU2mBook.newInstance(title:"The Stand"))
-         .save(true)
+         .save(flush:true)
         assertEquals 2, MappedU2mBook.list().size()
 
         // now let's test the database state
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy
index 1c37eb0..5cb7205 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
+import grails.core.DefaultGrailsApplication
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
 
  /**
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy
index 26c4201..e9b4f8f 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy
@@ -49,7 +49,7 @@
     Long version
     String name
     Set books
-    def relatesToMany = [books:WithCriteriaMethodBook]
+    static hasMany = [books:WithCriteriaMethodBook]
     boolean equals(obj) { name == obj?.name }
     int hashCode() { name ? name.hashCode() : super.hashCode() }
     String toString() { name }
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy
index 4675335..27a6dc2 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy
@@ -15,20 +15,21 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg
 
+import grails.core.DefaultGrailsApplication
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
+import grails.plugins.GrailsPlugin
+import grails.plugins.GrailsPluginManager
+import grails.util.Holders
+import grails.validation.ConstrainedProperty
+import org.codehaus.groovy.grails.validation.TestClass
+import org.grails.core.DefaultGrailsDomainClass
+import org.grails.plugins.MockGrailsPluginManager
+import org.grails.support.MockApplicationContext
 import org.junit.Ignore
 
 import java.lang.reflect.Field
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
-import org.codehaus.groovy.grails.plugins.GrailsPluginManager
-import org.codehaus.groovy.grails.plugins.MockGrailsPluginManager
-import org.codehaus.groovy.grails.plugins.PluginManagerHolder
-import org.codehaus.groovy.grails.support.MockApplicationContext
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
-import org.codehaus.groovy.grails.validation.TestClass
 import org.hibernate.cfg.ImprovedNamingStrategy
 import org.hibernate.mapping.Bag
 import org.hibernate.mapping.Column
@@ -245,7 +246,7 @@
         super.setUp()
         ExpandoMetaClass.enableGlobally()
         MockGrailsPluginManager pluginManager = new MockGrailsPluginManager()
-        PluginManagerHolder.setPluginManager(pluginManager)
+        Holders.setPluginManager(pluginManager)
         previousNamingStrategyClass = grailsDomainBinder.NAMING_STRATEGIES[GrailsDomainClassProperty.DEFAULT_DATA_SOURCE].getClass()
     }
 
@@ -255,7 +256,7 @@
         grailsDomainBinder.NAMING_STRATEGIES.clear()
         grailsDomainBinder.NAMING_STRATEGIES.put(
                 GrailsDomainClassProperty.DEFAULT_DATA_SOURCE, ImprovedNamingStrategy.INSTANCE)
-        PluginManagerHolder.setPluginManager(null)
+        Holders.setPluginManager(null)
         grailsDomainBinder.configureNamingStrategy previousNamingStrategyClass
     }
 
@@ -856,11 +857,11 @@
 
         def myPluginMap = [:]
         myPluginMap.getName = { -> 'MyPlugin' }
-        def myPlugin = myPluginMap as org.codehaus.groovy.grails.plugins.GrailsPlugin
+        def myPlugin = myPluginMap as GrailsPlugin
 
         def publisherPluginMap = [:]
         publisherPluginMap.getName = { -> 'Publisher' }
-        def publisherPlugin = publisherPluginMap as org.codehaus.groovy.grails.plugins.GrailsPlugin
+        def publisherPlugin = publisherPluginMap as GrailsPlugin
 
         def pluginManagerMap = [setApplicationContext: { }]
         def myPluginDomainClassNames = ['GadgetClass', 'MyPluginPersonClass']
@@ -879,7 +880,7 @@
         // no config property specified
         def cfg = new ConfigSlurper().parse('''
 ''')
-        grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
         def config = getDomainConfig(grailsApplication, pluginManager)
         def persistentClass = config.getClassMapping("WidgetClass")
         assertEquals("widget_class", persistentClass.table.name)
@@ -894,7 +895,7 @@
         cfg = new ConfigSlurper().parse('''
 grails.gorm.table.prefix.enabled = true
 ''')
-        grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
         config = getDomainConfig(grailsApplication, pluginManager)
         persistentClass = config.getClassMapping("WidgetClass")
         assertEquals("widget_class", persistentClass.table.name)
@@ -909,7 +910,7 @@
         cfg = new ConfigSlurper().parse('''
 grails.gorm.table.prefix.enabled = false
 ''')
-        grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
         config = getDomainConfig(grailsApplication, pluginManager)
         persistentClass = config.getClassMapping("WidgetClass")
         assertEquals("widget_class", persistentClass.table.name)
@@ -924,7 +925,7 @@
         cfg = new ConfigSlurper().parse('''
 grails.gorm.publisher.table.prefix.enabled = true
 ''')
-        grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
         config = getDomainConfig(grailsApplication, pluginManager)
         persistentClass = config.getClassMapping("WidgetClass")
         assertEquals("widget_class", persistentClass.table.name)
@@ -940,7 +941,7 @@
 grails.gorm.table.prefix.enabled = true
 grails.gorm.myPlugin.table.prefix.enabled = false
 ''')
-        grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
         config = getDomainConfig(grailsApplication, pluginManager)
         persistentClass = config.getClassMapping("WidgetClass")
         assertEquals("widget_class", persistentClass.table.name)
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethodSpec.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethodSpec.groovy
deleted file mode 100644
index e706bc0..0000000
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethodSpec.groovy
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.codehaus.groovy.grails.orm.hibernate.metaclass
-
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.orm.hibernate.Customer
-import org.codehaus.groovy.grails.orm.hibernate.GormSpec
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
-import org.grails.datastore.mapping.model.MappingContext
-import org.hibernate.Criteria
-import org.hibernate.SessionFactory
-import org.hibernate.impl.CriteriaImpl
-
-import spock.lang.Issue
-
-class AbstractFindByPersistentMethodSpec extends GormSpec {
-
-    @Issue('GRAILS-8762')
-    void "Test that findBy configures a limit of 1"() {
-        given:"A finder method"
-            final datastore = new HibernateDatastore(applicationContext.getBean(MappingContext), sessionFactory, grailsApplication.config)
-            datastore.applicationContext = applicationContext
-            def finder = new TestFindBy(datastore, grailsApplication)
-        when:"The finder is invoked"
-            CriteriaImpl c  = finder.invoke(Customer, "findByName", "Bob")
-
-        then: "ensure that the limit is one"
-            c.maxResults == 1
-    }
-
-    @Override
-    List getDomainClasses() {
-        [Customer]
-    }
-}
-
-class TestFindBy extends AbstractFindByPersistentMethod {
-
-    TestFindBy(HibernateDatastore datastore, GrailsApplication application) {
-        super(datastore, application, datastore.getSessionFactory(), Thread.currentThread().contextClassLoader, ~/(findBy)([A-Z]\w*)/, ["Or", "And"] as String[])
-    }
-
-    @Override
-    protected Object getResult(Criteria crit, boolean useLimit) {
-        return crit
-    }
-}
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformerSpec.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/GormTransformerSpec.groovy
similarity index 92%
rename from grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformerSpec.groovy
rename to grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/GormTransformerSpec.groovy
index 35a5e67..be990a9 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformerSpec.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/GormTransformerSpec.groovy
@@ -1,12 +1,13 @@
-package org.codehaus.groovy.grails.compiler.gorm
+package org.grails.compiler.gorm
 
+import grails.compiler.ast.ClassInjector
 import grails.persistence.Entity
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
-import org.codehaus.groovy.grails.compiler.injection.ClassInjector
-import org.codehaus.groovy.grails.compiler.injection.DefaultGrailsDomainClassInjector
-import org.codehaus.groovy.grails.compiler.injection.GrailsAwareClassLoader
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
+import org.grails.compiler.gorm.GormTransformer;
+import org.grails.compiler.injection.DefaultGrailsDomainClassInjector
+import org.grails.compiler.injection.GrailsAwareClassLoader
+import org.grails.core.DefaultGrailsDomainClass
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.gorm.GormStaticApi
 import org.grails.datastore.gorm.GormValidationApi
@@ -14,8 +15,8 @@
 import org.springframework.validation.Errors
 
 import spock.lang.Specification
-import org.codehaus.groovy.grails.commons.spring.GrailsApplicationContext
 import grails.spring.BeanBuilder
+
 import org.springframework.context.ConfigurableApplicationContext
 
 class GormTransformerSpec extends Specification {
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformerSpec.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/GormValidationTransformerSpec.groovy
similarity index 85%
rename from grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformerSpec.groovy
rename to grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/GormValidationTransformerSpec.groovy
index ae6c64f..578f099 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformerSpec.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/GormValidationTransformerSpec.groovy
@@ -1,7 +1,9 @@
-package org.codehaus.groovy.grails.compiler.gorm
+package org.grails.compiler.gorm
 
-import org.codehaus.groovy.grails.compiler.injection.ClassInjector
-import org.codehaus.groovy.grails.compiler.injection.GrailsAwareClassLoader
+import grails.compiler.ast.ClassInjector
+
+import org.grails.compiler.gorm.GormValidationTransformer;
+import org.grails.compiler.injection.GrailsAwareClassLoader
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.gorm.GormValidationApi
 import org.grails.datastore.mapping.simple.SimpleMapDatastore
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/SessionFactoryProxySpec.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/SessionFactoryProxySpec.groovy
similarity index 97%
rename from grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/SessionFactoryProxySpec.groovy
rename to grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/SessionFactoryProxySpec.groovy
index 8c1e7ef..b2ff890 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/SessionFactoryProxySpec.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/compiler/gorm/SessionFactoryProxySpec.groovy
@@ -1,4 +1,4 @@
-package org.codehaus.groovy.grails.compiler.gorm
+package org.grails.compiler.gorm
 
 import grails.spring.BeanBuilder
 
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/HibernateSuite.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/HibernateSuite.groovy
index 542136a..1d5bfc4 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/HibernateSuite.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/HibernateSuite.groovy
@@ -7,6 +7,8 @@
 import grails.gorm.tests.CrudOperationsSpec
 import grails.gorm.tests.DetachedCriteriaSpec
 import grails.gorm.tests.DomainEventsSpec
+import grails.gorm.tests.EnumSpec
+import grails.gorm.tests.FindByExampleSpec
 import grails.gorm.tests.FindByMethodSpec
 import grails.gorm.tests.FindWhereSpec
 import grails.gorm.tests.GormEnhancerSpec
@@ -61,6 +63,7 @@
 //    OneToOneSpec
 //    FindWhereSpec
 //DetachedCriteriaSpec
-SizeQuerySpec
+//SizeQuerySpec
+    FindByExampleSpec
 ])
 class HibernateSuite {}
diff --git a/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/Setup.groovy b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
index 691423f..a95490d 100644
--- a/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
+++ b/grails-datastore-gorm-hibernate/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
@@ -1,12 +1,11 @@
 package org.grails.datastore.gorm
 
+import grails.core.DefaultGrailsApplication
 import groovy.sql.Sql
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
+import grails.validation.ConstrainedProperty
 import groovy.transform.CompileStatic
-
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.metaclass.MetaClassEnhancer
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTransactionManager
 import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormEnhancer
@@ -18,7 +17,9 @@
 import org.codehaus.groovy.grails.orm.hibernate.validation.HibernateDomainClassValidator
 import org.codehaus.groovy.grails.orm.hibernate.validation.PersistentConstraintFactory
 import org.codehaus.groovy.grails.orm.hibernate.validation.UniqueConstraint
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
+import org.grails.core.metaclass.MetaClassEnhancer
+
+//import org.codehaus.groovy.grails.plugins.web.api.ControllersDomainBindingApi
 import org.grails.datastore.gorm.config.GrailsDomainClassMappingContext
 import org.grails.datastore.mapping.core.Session
 import org.grails.datastore.mapping.model.MappingContext
@@ -88,14 +89,14 @@
             try { sql?.close() } catch (ignored) {}
         }
     }
-    
+
     static Session setup(List<Class> classes, ConfigObject grailsConfig = null, boolean isTransactional = true) {
         ExpandoMetaClass.enableGlobally()
 //        Log4jConfigurer.initLogging("classpath:log4j.properties")
 
         grailsApplication = new DefaultGrailsApplication(classes as Class[], new GroovyClassLoader(Setup.getClassLoader()))
         if(grailsConfig) {
-            grailsApplication.config.putAll(grailsConfig)
+            grailsApplication.config.merge(grailsConfig)
         }
 
         applicationContext = new GenericApplicationContext()
@@ -176,6 +177,7 @@
 
 
             def validator = new HibernateDomainClassValidator()
+
             validator.sessionFactory = sessionFactory
             validator.grailsApplication = grailsApplication
             validator.domainClass = dc
diff --git a/grails-datastore-gorm-hibernate4/build.gradle b/grails-datastore-gorm-hibernate4/build.gradle
index 6e8fd5e..a6841dd 100644
--- a/grails-datastore-gorm-hibernate4/build.gradle
+++ b/grails-datastore-gorm-hibernate4/build.gradle
@@ -15,6 +15,12 @@
     optional("org.grails:grails-web:$grailsVersion") {
         transitive = false
     }
+    optional("org.grails:grails-web-common:$grailsVersion") {
+        transitive = false
+    }
+    optional("org.grails:grails-web-url-mappings:$grailsVersion") {
+        transitive = false
+    }
     optional("org.grails:grails-spring:$grailsVersion") {
         transitive = false
     }
@@ -136,4 +142,4 @@
     if (!isTravisBuild) {
         forkEvery = 30
     }
-}
\ No newline at end of file
+}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy b/grails-datastore-gorm-hibernate4/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy
index 2c2eac1..53914a4 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializer.groovy
@@ -14,9 +14,11 @@
  */
 package grails.orm.bootstrap
 
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClassProperty
+import grails.util.Environment
 import groovy.transform.CompileStatic
 import groovy.util.logging.Commons
-import org.codehaus.groovy.grails.commons.GrailsApplication
 import org.codehaus.groovy.grails.orm.hibernate.*
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
 import org.codehaus.groovy.grails.orm.hibernate.proxy.HibernateProxyHandler
@@ -49,7 +51,7 @@
 class HibernateDatastoreSpringInitializer extends AbstractDatastoreInitializer {
     public static final String SESSION_FACTORY_BEAN_NAME = "sessionFactory"
 
-    String defaultDataSourceBeanName = "dataSource"
+    String defaultDataSourceBeanName = GrailsDomainClassProperty.DEFAULT_DATA_SOURCE
     String defaultSessionFactoryBeanName = SESSION_FACTORY_BEAN_NAME
     String ddlAuto = "update"
     Set<String> dataSources = [defaultDataSourceBeanName]
@@ -72,11 +74,11 @@
         super(persistentClasses.toList())
     }
 
-    HibernateDatastoreSpringInitializer(Properties hibernateProperties, Collection<Class> persistentClasses) {
+    HibernateDatastoreSpringInitializer(Map hibernateProperties, Collection<Class> persistentClasses) {
         super(hibernateProperties, persistentClasses)
     }
 
-    HibernateDatastoreSpringInitializer(Properties hibernateProperties, Class... persistentClasses) {
+    HibernateDatastoreSpringInitializer(Map hibernateProperties, Class... persistentClasses) {
         super(hibernateProperties, persistentClasses.toList())
     }
 
@@ -84,7 +86,7 @@
     ApplicationContext configureForDataSource(DataSource dataSource) {
         ExpandoMetaClass.enableGlobally()
         GenericApplicationContext applicationContext = new GenericApplicationContext()
-        applicationContext.beanFactory.registerSingleton(defaultDataSourceBeanName, dataSource)
+        applicationContext.beanFactory.registerSingleton("dataSource", dataSource)
         configureForBeanDefinitionRegistry(applicationContext)
         applicationContext.refresh()
         return applicationContext
@@ -152,7 +154,7 @@
                 // Used to detect the database dialect to use
                 if(noDialect) {
                     "dialectDetector$suffix"(HibernateDialectDetectorFactoryBean) {
-                        dataSource = ref(dataSourceName)
+                        dataSource = ref("dataSource$suffix")
                         vendorNameDialectMappings = vendorToDialect
                     }
                 }
@@ -168,17 +170,21 @@
                 }
 
 
+                if (Environment.current.isReloadEnabled()) {
+                    "${SessionFactoryHolder.BEAN_ID}$suffix"(SessionFactoryHolder)
+                }
+
                 // the main SessionFactory bean
                 if(!beanDefinitionRegistry.containsBeanDefinition(sessionFactoryName)) {
                     "$sessionFactoryName"(ConfigurableLocalSessionFactoryBean) { bean ->
                         bean.autowire = "byType"
-                        dataSource = ref(dataSourceName)
+                        dataSource = ref("dataSource$suffix")
                         delegate.hibernateProperties = ref("hibernateProperties$suffix")
                         grailsApplication = ref(GrailsApplication.APPLICATION_ID)
                         entityInterceptor = ref("entityInterceptor$suffix")
 
                         List hibConfigLocations = []
-                        def cl = classLoader ?: Thread.currentThread().contextClassLoader
+                        def cl = Thread.currentThread().contextClassLoader
                         if (cl.getResource(prefix + 'hibernate.cfg.xml')) {
                             hibConfigLocations << 'classpath:' + prefix + 'hibernate.cfg.xml'
                         }
@@ -208,7 +214,7 @@
                     "transactionManager$suffix"(GrailsHibernateTransactionManager) { bean ->
                         bean.autowire = "byName"
                         sessionFactory = ref(sessionFactoryName)
-                        dataSource = ref(dataSourceName)
+                        dataSource = ref("dataSource$suffix")
                     }
                 }
 
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/grails/plugin/hibernate4/HibernatePluginSupport.groovy b/grails-datastore-gorm-hibernate4/src/main/groovy/grails/plugin/hibernate4/HibernatePluginSupport.groovy
index b088c90..375537b 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/grails/plugin/hibernate4/HibernatePluginSupport.groovy
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/grails/plugin/hibernate4/HibernatePluginSupport.groovy
@@ -15,12 +15,12 @@
  */
 package grails.plugin.hibernate4
 
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
-import org.codehaus.groovy.grails.commons.spring.DefaultRuntimeSpringConfiguration
-import org.codehaus.groovy.grails.commons.spring.GrailsRuntimeConfigurator
-import org.codehaus.groovy.grails.commons.spring.RuntimeSpringConfiguration
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
+import grails.util.Environment
+import grails.validation.ConstrainedProperty
+import grails.validation.ConstraintsEvaluator
 import org.codehaus.groovy.grails.orm.hibernate.*
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
@@ -31,9 +31,10 @@
 import org.codehaus.groovy.grails.orm.hibernate.validation.HibernateDomainClassValidator
 import org.codehaus.groovy.grails.orm.hibernate.validation.PersistentConstraintFactory
 import org.codehaus.groovy.grails.orm.hibernate.validation.UniqueConstraint
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
-import org.codehaus.groovy.grails.validation.ConstraintsEvaluator
 import org.grails.datastore.mapping.model.MappingContext
+import org.grails.spring.DefaultRuntimeSpringConfiguration
+import org.grails.spring.RuntimeSpringConfiguration
+import org.grails.web.servlet.context.support.GrailsRuntimeConfigurator
 import org.hibernate.EmptyInterceptor
 import org.hibernate.cfg.ImprovedNamingStrategy
 import org.slf4j.Logger
@@ -261,7 +262,7 @@
 
                 hibernateProperties = ref("hibernateProperties$suffix")
 
-                grailsApplication = ref("grailsApplication", true)
+                grailsApplication = ref("grailsApplication")
 
                 entityInterceptor = ref("entityInterceptor$suffix")
 
@@ -394,7 +395,7 @@
                 def hibConfig = application.config["hibernate$suffix"]
                 def sessionFactoryReload = hibConfig?.containsKey('reload') ? hibConfig.reload : true
 
-                if (sessionFactoryReload) {
+                if (sessionFactoryReload && Environment.current.isReloadEnabled()) {
                     "${SessionFactoryHolder.BEAN_ID}$suffix"(SessionFactoryHolder) {
                         sessionFactory = bean(ConfigurableLocalSessionFactoryBean) { bean ->
                             bean.parent = ref("abstractSessionFactoryBeanConfig$suffix")
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java
index cc95352..a9dcedd 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/ConfigurableLocalSessionFactoryBean.java
@@ -15,6 +15,8 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClassProperty;
 import groovy.lang.GroovySystem;
 import groovy.lang.MetaClassRegistry;
 
@@ -28,8 +30,6 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration;
 import org.codehaus.groovy.grails.orm.hibernate.transaction.GrailsJdbcTransactionFactory;
 import org.hibernate.HibernateException;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java
index f9b211b..135a263 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/EventTriggeringInterceptor.java
@@ -15,6 +15,8 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.config.Config;
+import grails.core.GrailsDomainClass;
 import groovy.lang.GroovySystem;
 import groovy.util.ConfigObject;
 
@@ -22,14 +24,13 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import org.codehaus.groovy.grails.commons.AnnotationDomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
 import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventListener;
 import org.codehaus.groovy.grails.orm.hibernate.support.SoftKey;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.grails.core.artefact.AnnotationDomainClassArtefactHandler;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.grails.datastore.gorm.timestamp.DefaultTimestampProvider;
 import org.grails.datastore.gorm.timestamp.TimestampProvider;
 import org.grails.datastore.mapping.engine.event.AbstractPersistenceEvent;
@@ -63,10 +64,10 @@
     
     private TimestampProvider timestampProvider = new DefaultTimestampProvider();
 
-    public EventTriggeringInterceptor(HibernateDatastore datastore, ConfigObject co) {
+    public EventTriggeringInterceptor(HibernateDatastore datastore, Config co) {
         super(datastore);
 
-        Object failOnErrorConfig = co.flatten().get("grails.gorm.failOnError");
+        Object failOnErrorConfig = co.getProperty("grails.gorm.failOnError", Object.class);
         if (failOnErrorConfig instanceof List) {
             failOnError = true;
             failOnErrorPackages = (List<?>)failOnErrorConfig;
@@ -248,5 +249,5 @@
 
     public void setTimestampProvider(TimestampProvider timestampProvider) {
         this.timestampProvider = timestampProvider;
-    }    
+    }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java
index c6bfb47..c0bbb3a 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateDomainClass.java
@@ -17,7 +17,7 @@
 
 import java.util.Collection;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
+import grails.core.GrailsApplication;
 import org.hibernate.MappingException;
 import org.hibernate.SessionFactory;
 import org.hibernate.engine.spi.SessionFactoryImplementor;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java
index f35b0f0..1f93f7b 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/GrailsHibernateTemplate.java
@@ -15,10 +15,13 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.core.GrailsApplication;
+import groovy.lang.Closure;
+import groovy.util.ProxyGenerator;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.hibernate.*;
 import org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl;
 import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
@@ -104,16 +107,25 @@
         this.flushMode = defaultFlushMode;
     }
 
+
+    @Override
+    public <T> T execute(Closure<T> callable) {
+        HibernateCallback<T> hibernateCallback = DefaultGroovyMethods.asType(callable, HibernateCallback.class);
+        return execute(hibernateCallback);
+    }
+
     public SessionFactory getSessionFactory() {
         return sessionFactory;
     }
 
+    @Override
     public void applySettings(Query query) {
         if (exposeNativeSession) {
             prepareQuery(query);
         }
     }
 
+    @Override
     public void applySettings(Criteria criteria) {
         if (exposeNativeSession) {
             prepareCriteria(criteria);
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java
index bbe52d8..1596b74 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateDatastore.java
@@ -14,12 +14,13 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate;
 
+import grails.config.Config;
+import grails.core.GrailsApplication;
+import grails.core.support.GrailsApplicationAware;
 import groovy.util.ConfigObject;
 
 import java.util.Map;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware;
 import org.grails.datastore.mapping.core.Session;
 import org.grails.datastore.mapping.model.MappingContext;
 import org.hibernate.SessionFactory;
@@ -38,15 +39,15 @@
     private GrailsApplication grailsApplication;
     private int defaultFlushMode;
 
-    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config) {
+    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config) {
         super(mappingContext, sessionFactory, config);
     }
-    
-    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config, ApplicationContext applicationContext) {
+
+    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config, ApplicationContext applicationContext) {
         this(mappingContext, sessionFactory, config, applicationContext, GrailsHibernateTemplate.FLUSH_AUTO);
     }
 
-    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, ConfigObject config, ApplicationContext applicationContext, int defaultFlushMode) {
+    public HibernateDatastore(MappingContext mappingContext, SessionFactory sessionFactory, Config config, ApplicationContext applicationContext, int defaultFlushMode) {
         super(mappingContext, sessionFactory, config, applicationContext);
         this.defaultFlushMode = defaultFlushMode;
     }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy
index a79f98d..7fd30d6 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormEnhancer.groovy
@@ -14,23 +14,12 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
 import groovy.transform.CompileStatic
 
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.CountByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllByBooleanPropertyPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByBooleanPropertyPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindOrCreateByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindOrSaveByPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ListOrderByPersistentMethod
 import org.grails.datastore.gorm.GormInstanceApi
 import org.grails.datastore.gorm.GormStaticApi
 import org.grails.datastore.gorm.GormValidationApi
-import org.grails.datastore.gorm.finders.FinderMethod
-import org.grails.datastore.mapping.core.Datastore
-import org.grails.datastore.mapping.model.PersistentEntity
 import org.springframework.transaction.PlatformTransactionManager
 
 /**
@@ -47,19 +36,6 @@
         super(datastore, transactionManager, grailsApplication)
     }
 
-    protected List<FinderMethod> createDynamicFinders() {
-        HibernateDatastore hibernateDatastore = (HibernateDatastore)datastore
-        def sessionFactory = hibernateDatastore.sessionFactory
-        [new FindAllByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindAllByBooleanPropertyPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindOrCreateByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindOrSaveByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new FindByBooleanPropertyPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new CountByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader),
-         new ListOrderByPersistentMethod(hibernateDatastore, grailsApplication, sessionFactory, classLoader)]
-    }
-
     protected <D> GormValidationApi<D> getValidationApi(Class<D> cls) {
         new HibernateGormValidationApi<D>(cls, (HibernateDatastore)datastore, classLoader)
     }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy
index 70bb19d..ba8a491 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormInstanceApi.groovy
@@ -15,18 +15,13 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import groovy.transform.CompileStatic
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.SavePersistentMethod
-import org.hibernate.LockMode
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.hibernate.engine.spi.EntityEntry
 import org.hibernate.engine.spi.SessionImplementor
-import org.hibernate.proxy.HibernateProxy
-import org.springframework.dao.DataAccessException
 
 /**
  * The implementation of the GORM instance API contract for Hibernate.
@@ -37,27 +32,23 @@
 @CompileStatic
 class HibernateGormInstanceApi<D> extends AbstractHibernateGormInstanceApi<D> {
 
-    protected SavePersistentMethod saveMethod
-    protected MergePersistentMethod mergeMethod
     protected GrailsHibernateTemplate hibernateTemplate
     protected InstanceApiHelper instanceApiHelper
 
     HibernateGormInstanceApi(Class<D> persistentClass, HibernateDatastore datastore, ClassLoader classLoader) {
-        super(persistentClass, datastore, classLoader)
+        super(persistentClass, datastore, classLoader, null)
 
         def grailsApplication = datastore.getGrailsApplication()
         if (grailsApplication) {
             GrailsDomainClass domainClass = (GrailsDomainClass)grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, persistentClass.name)
             config = (Map)grailsApplication.getFlatConfig().get('grails.gorm')
-            saveMethod = new SavePersistentMethod(sessionFactory, classLoader, grailsApplication, domainClass, datastore)
-            mergeMethod = new MergePersistentMethod(sessionFactory, classLoader, grailsApplication, domainClass, datastore)
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, grailsApplication, datastore.getDefaultFlushMode())
-            cacheQueriesByDefault = GrailsHibernateUtil.isCacheQueriesByDefault(grailsApplication)
         }
         else {
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory)
             hibernateTemplate.setFlushMode(datastore.getDefaultFlushMode())
         }
+        super.hibernateTemplate = hibernateTemplate
         instanceApiHelper = new InstanceApiHelper(hibernateTemplate)
     }
 
@@ -140,111 +131,6 @@
         return fieldIndex == -1 ? null : entry.loadedState[fieldIndex]
     }
 
-    @Override
-    D lock(D instance) {
-        hibernateTemplate.lock(instance, LockMode.PESSIMISTIC_WRITE)
-    }
-
-    @Override
-    D refresh(D instance) {
-        hibernateTemplate.refresh(instance)
-        return instance
-    }
-
-    @Override
-    D save(D instance) {
-        if (saveMethod) {
-            return (D)saveMethod.invoke(instance, "save", EMPTY_ARRAY)
-        }
-        else {
-            return super.save(instance)
-        }
-    }
-
-    D save(D instance, boolean validate) {
-        if (saveMethod) {
-            return (D)saveMethod.invoke(instance, "save", [validate] as Object[])
-        }
-        else {
-            return super.save(instance, validate)
-        }
-    }
-
-    @Override
-    D merge(D instance) {
-        if (mergeMethod) {
-            return (D)mergeMethod.invoke(instance, "merge", EMPTY_ARRAY)
-        }
-        else {
-            return super.merge(instance)
-        }
-    }
-
-    @Override
-    D merge(D instance, Map params) {
-        if (mergeMethod) {
-            return (D)mergeMethod.invoke(instance, "merge", [params] as Object[])
-        }
-        else {
-            return super.merge(instance, params)
-        }
-    }
-
-    @Override
-    D save(D instance, Map params) {
-        if (saveMethod) {
-            return (D)saveMethod.invoke(instance, "save", [params] as Object[])
-        }
-        else {
-            return super.save(instance, params)
-        }
-    }
-
-    @Override
-    D attach(D instance) {
-        hibernateTemplate.lock(instance, LockMode.NONE)
-        return instance
-    }
-
-    @Override
-    void discard(D instance) {
-        hibernateTemplate.evict instance
-    }
-
-    @Override
-    void delete(D instance) {
-        boolean flush = shouldFlush()
-        try {
-            instanceApiHelper.delete instance, flush
-        }
-        catch (DataAccessException e) {
-            handleDataAccessException(hibernateTemplate, e)
-        }
-    }
-
-    @Override
-    void delete(D instance, Map params) {
-        boolean flush = shouldFlush(params)
-        try {
-            instanceApiHelper.delete instance, flush
-        }
-        catch (DataAccessException e) {
-            handleDataAccessException(hibernateTemplate, e)
-        }
-    }
-
-    @Override
-    boolean instanceOf(D instance, Class cls) {
-        if (instance instanceof HibernateProxy) {
-            return GrailsHibernateUtil.unwrapProxy(instance) in cls
-        }
-        return instance in cls
-    }
-
-    @Override
-    boolean isAttached(D instance) {
-        hibernateTemplate.contains instance
-    }
 
     protected EntityEntry findEntityEntry(D instance, SessionImplementor session, boolean forDirtyCheck = true) {
         def entry = session.persistenceContext.getEntry(instance)
@@ -259,22 +145,8 @@
         entry
     }
 
-    /**
-     * Session should no longer be flushed after a data access exception occurs (such a constriant violation)
-     */
-    protected void handleDataAccessException(GrailsHibernateTemplate template, DataAccessException e) {
-        try {
-            instanceApiHelper.setFlushModeManual()
-        }
-        finally {
-            throw e
-        }
-    }
-
-    boolean shouldFlush(Map map = [:]) {
-        if (map?.containsKey('flush')) {
-            return Boolean.TRUE == map.flush
-        }
-        return config?.autoFlush instanceof Boolean ? config.autoFlush : false
+    @Override
+    void setObjectToReadWrite(Object target) {
+        GrailsHibernateUtil.setObjectToReadWrite(target, sessionFactory)
     }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy
index 8c48df7..02c8ef1 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormStaticApi.groovy
@@ -15,33 +15,23 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
 import grails.orm.HibernateCriteriaBuilder
+import grails.orm.PagedResultList
+import groovy.transform.CompileDynamic
 import groovy.transform.CompileStatic
 import groovy.transform.TypeCheckingMode
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.orm.hibernate.cfg.CompositeIdentity
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
-import org.codehaus.groovy.grails.orm.hibernate.cfg.HibernateUtils
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ExecuteQueryPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ExecuteUpdatePersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ListPersistentMethod
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.MergePersistentMethod
-import org.grails.datastore.gorm.GormStaticApi
+import org.codehaus.groovy.grails.orm.hibernate.query.GrailsHibernateQueryUtils
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.datastore.gorm.finders.DynamicFinder
 import org.grails.datastore.gorm.finders.FinderMethod
 import org.grails.datastore.mapping.query.api.BuildableCriteria as GrailsCriteria
 import org.hibernate.Criteria
 import org.hibernate.LockMode
 import org.hibernate.Session
 import org.hibernate.SessionFactory
-import org.hibernate.criterion.CriteriaSpecification
-import org.hibernate.criterion.Projections
-import org.hibernate.criterion.Restrictions
 import org.springframework.core.convert.ConversionService
 import org.springframework.orm.hibernate4.SessionFactoryUtils
 import org.springframework.orm.hibernate4.SessionHolder
@@ -55,159 +45,66 @@
  * @since 1.0
  */
 @CompileStatic
-class HibernateGormStaticApi<D> extends GormStaticApi<D> {
-    protected static final EMPTY_ARRAY = [] as Object[]
-
+class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> {
     protected GrailsHibernateTemplate hibernateTemplate
     protected SessionFactory sessionFactory
     protected ConversionService conversionService
     protected Class identityType
-    protected ListPersistentMethod listMethod
-    protected FindAllPersistentMethod findAllMethod
-    protected FindPersistentMethod findMethod
-    protected ExecuteQueryPersistentMethod executeQueryMethod
-    protected ExecuteUpdatePersistentMethod executeUpdateMethod
-    protected MergePersistentMethod mergeMethod
     protected ClassLoader classLoader
     protected GrailsApplication grailsApplication
-    protected GrailsDomainBinder grailsDomainBinder = new GrailsDomainBinder()
-    protected int defaultFlushMode
+    private HibernateGormInstanceApi<D> instanceApi
+    private int defaultFlushMode
 
     HibernateGormStaticApi(Class<D> persistentClass, HibernateDatastore datastore, List<FinderMethod> finders,
                 ClassLoader classLoader, PlatformTransactionManager transactionManager) {
-        super(persistentClass, datastore, finders, transactionManager)
+        super(persistentClass, datastore, finders, transactionManager, null)
         this.classLoader = classLoader
         sessionFactory = datastore.getSessionFactory()
         conversionService = datastore.mappingContext.conversionService
 
         identityType = persistentEntity.identity?.type
 
-        def mappingContext = datastore.mappingContext
         grailsApplication = datastore.grailsApplication
         if (grailsApplication) {
             GrailsDomainClass domainClass = (GrailsDomainClass)grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, persistentClass.name)
             identityType = domainClass.identifier?.type
 
-            mergeMethod = new MergePersistentMethod(sessionFactory, classLoader, grailsApplication, domainClass, datastore)
-            listMethod = new ListPersistentMethod(grailsApplication, sessionFactory, classLoader, mappingContext.conversionService, datastore.getDefaultFlushMode())
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, grailsApplication, datastore.getDefaultFlushMode())
         } else {
             hibernateTemplate = new GrailsHibernateTemplate(sessionFactory)
             hibernateTemplate.setFlushMode(datastore.getDefaultFlushMode())
         }
-        
         this.defaultFlushMode = datastore.getDefaultFlushMode()
-
-        executeQueryMethod = new ExecuteQueryPersistentMethod(sessionFactory, classLoader, grailsApplication, conversionService, datastore.getDefaultFlushMode())
-        executeUpdateMethod = new ExecuteUpdatePersistentMethod(sessionFactory, classLoader, grailsApplication, datastore.getDefaultFlushMode())
-        findMethod = new FindPersistentMethod(sessionFactory, classLoader, grailsApplication, conversionService, datastore.getDefaultFlushMode())
-        findAllMethod = new FindAllPersistentMethod(sessionFactory, classLoader, grailsApplication, conversionService, datastore.getDefaultFlushMode())
+        super.hibernateTemplate = hibernateTemplate
+        
+        instanceApi = new HibernateGormInstanceApi<>(persistentClass, datastore, classLoader)
     }
 
-//    /**
-//     * Property missing handling used to relay property access onto target entity for named queries etc.
-//     *
-//     * @param property The name of the property
-//     */
-//    @CompileStatic(TypeCheckingMode.SKIP)
-//    def propertyMissing(String property) {
-//        if(persistentClass.hasProperty(property)) {
-//            return this.persistentClass."$property"
-//        }
-//        else {
-//            throw new MissingPropertyException(property, HibernateGormStaticApi)
-//        }
-//    }
-
 
     @Override
-    D get(Serializable id) {
-        doGetInstance(id)
-    }
+    List<D> list(Map params = Collections.emptyMap()) {
+        hibernateTemplate.execute { Session session ->
+            Criteria c = session.createCriteria(persistentEntity.javaClass)
+            hibernateTemplate.applySettings c
 
-    private D doGetInstance(Serializable id) {
-        if (id || (id instanceof Number)) {
-            id = convertIdentifier(id)
-            D result = (D)hibernateTemplate.get((Class)persistentClass, id)
-            return (D)GrailsHibernateUtil.unwrapIfProxy(result)
-        } else {
-            return null
-        }
-    }
+            params = params ? new HashMap(params) : Collections.emptyMap()
+            setResultTransformer(c)
+            if(params.containsKey(DynamicFinder.ARGUMENT_MAX)) {
 
-    Serializable convertIdentifier(Object id) {
-        (Serializable)HibernateUtils.convertValueToType(id, identityType, conversionService)
-    }
-
-    @Override
-    D read(Serializable id) {
-        if (id == null) {
-            return null
-        }
-
-        hibernateTemplate.execute(  { Session session ->
-           D o = doGetInstance((Serializable)id)
-           if (o && session.contains(o)) {
-               session.setReadOnly(o, true)
-           }
-           return o
-        } as GrailsHibernateTemplate.HibernateCallback )
-    }
-
-    @Override
-    D load(Serializable id) {
-        id = convertIdentifier(id)
-        if (id != null) {
-            return (D) hibernateTemplate.load((Class)persistentClass, id)
-        }
-    }
-
-    @Override
-    List<D> getAll() {
-        (List<D>)hibernateTemplate.execute(new GrailsHibernateTemplate.HibernateCallback() {
-            def doInHibernate(Session session) {
-                Criteria criteria = session.createCriteria(persistentClass)
-                hibernateTemplate.applySettings criteria
-                criteria.list()
+                c.setMaxResults(Integer.MAX_VALUE)
+                GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, c, params, datastore.mappingContext.conversionService, true)
+                return new PagedResultList(hibernateTemplate, c)
             }
-        })
-    }
-
-    List<D> getAll(List ids) {
-        getAllInternal(ids)
-    }
-
-    List<D> getAll(Long... ids) {
-        getAllInternal(ids as List)
-    }
-
-    @Override
-    List<D> getAll(Serializable... ids) {
-        getAllInternal(ids as List)
-    }
-
-    private List getAllInternal(List ids) {
-        if (!ids) return []
-
-        (List)hibernateTemplate.execute(new GrailsHibernateTemplate.HibernateCallback() {
-            def doInHibernate(Session session) {
-                ids = ids.collect { HibernateUtils.convertValueToType((Serializable)it, identityType, conversionService) }
-                def criteria = session.createCriteria(persistentClass)
-                hibernateTemplate.applySettings(criteria)
-                def identityName = persistentEntity.identity.name
-                criteria.add(Restrictions.'in'(identityName, ids))
-                def results = criteria.list()
-                def idsMap = [:]
-                for (object in results) {
-                    idsMap[object[identityName]] = object
-                }
-                results.clear()
-                for (id in ids) {
-                    results << idsMap[id]
-                }
-                results
+            else {
+                GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, c, params, datastore.mappingContext.conversionService, true)
+                return c.list()
             }
-        })
+        }
+    }
+
+    @CompileDynamic
+    protected void setResultTransformer(Criteria c) {
+        c.resultTransformer = Criteria.DISTINCT_ROOT_ENTITY
     }
 
     @Override
@@ -215,7 +112,6 @@
         def builder = new HibernateCriteriaBuilder(persistentClass, sessionFactory)
         builder.grailsApplication = grailsApplication
         builder.conversionService = conversionService
-        builder.defaultFlushMode = defaultFlushMode
         builder
     }
 
@@ -225,258 +121,55 @@
     }
 
     @Override
-    D merge(o) {
-        (D)mergeMethod.invoke(o, "merge", [] as Object[])
+    D merge( D o ) {
+        instanceApi.merge(o)
     }
 
     @Override
-    Integer count() {
-        (Integer)hibernateTemplate.execute(new GrailsHibernateTemplate.HibernateCallback() {
-            def doInHibernate(Session session) {
-                def criteria = session.createCriteria(persistentClass)
-                hibernateTemplate.applySettings(criteria)
-                criteria.setProjection(Projections.rowCount())
-                def num = criteria.uniqueResult()
-                num == null ? 0 : num
+    Integer executeUpdate(String query, Map params, Map args) {
+        def template = hibernateTemplate
+        SessionFactory sessionFactory = this.sessionFactory
+        return (Integer) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+            def sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource( sessionFactory )
+            if (sessionHolder && sessionHolder.hasTimeout()) {
+                q.timeout = sessionHolder.timeToLiveInSeconds
             }
-        })
+
+            populateQueryArguments(q, params)
+            populateQueryArguments(q, args)
+            populateQueryWithNamedArguments(q, params)
+
+            return q.executeUpdate()
+        }
     }
 
     @Override
-    boolean exists(Serializable id) {
-        id = convertIdentifier(id)
-        hibernateTemplate.execute new GrailsHibernateTemplate.HibernateCallback() {
-            def doInHibernate(Session session) {
-                Criteria criteria = session.createCriteria(persistentEntity.javaClass)
-                hibernateTemplate.applySettings(criteria)
-                criteria.add(Restrictions.idEq(id))
-                    .setProjection(Projections.rowCount())
-                    .uniqueResult()
+    Integer executeUpdate(String query, Collection params, Map args) {
+        def template = hibernateTemplate
+        SessionFactory sessionFactory = this.sessionFactory
+
+        return (Integer) template.execute { Session session ->
+            def q = session.createQuery(query)
+            template.applySettings(q)
+            def sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource( sessionFactory )
+            if (sessionHolder && sessionHolder.hasTimeout()) {
+                q.timeout = sessionHolder.timeToLiveInSeconds
             }
-        }
-    }
 
-    @Override
-    List<D> list(Map params) {
-        (List<D>)listMethod.invoke(persistentClass, "list", [params] as Object[])
-    }
 
-    @Override
-    List<D> list() {
-        (List<D>)listMethod.invoke(persistentClass, "list", EMPTY_ARRAY)
-    }
-
-    @Override
-    List<D> findAll(example, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [example, args] as Object[])
-    }
-
-    @Override
-    D find(example, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [example, args] as Object[])
-    }
-
-    D first(Map m) {
-        def entityMapping = grailsDomainBinder.getMapping(persistentEntity.javaClass)
-        if (entityMapping?.identity instanceof CompositeIdentity) {
-            throw new UnsupportedOperationException('The first() method is not supported for domain classes that have composite keys.')
-        }
-        super.first(m)
-    }
-
-    D last(Map m) {
-        def entityMapping = grailsDomainBinder.getMapping(persistentEntity.javaClass)
-        if (entityMapping?.identity instanceof CompositeIdentity) {
-            throw new UnsupportedOperationException('The last() method is not supported for domain classes that have composite keys.')
-        }
-        super.last(m)
-    }
-
-    /**
-     * Finds a single result for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [foo:'bar], [max:10]) instead
-     */
-    @Deprecated
-    D find(String query, Map args, Integer max) {
-        (D)findMethod.invoke(persistentClass, "find", [query, args, max] as Object[])
-    }
-
-    /**
-     * Finds a single result for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @param offset The offset
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [foo:'bar], [max:10, offset:5]) instead
-     */
-    @Deprecated
-    D find(String query, Map args, Integer max, Integer offset) {
-        (D)findMethod.invoke(persistentClass, "find", [query, args, max, offset] as Object[])
-    }
-
-    /**
-     * Finds a single result for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [max:10]) instead
-     */
-    @Deprecated
-    D find(String query, Integer max) {
-        (D)findMethod.invoke(persistentClass, "find", [query, max] as Object[])
-    }
-
-    /**
-     * Finds a single result for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @param offset The offset to use
-     * @return A single result or null
-     *
-     * @deprecated Use Book.find('..', [max:10, offset:5]) instead
-     */
-    @Deprecated
-    D find(String query, Integer max, Integer offset) {
-        (D)findMethod.invoke(persistentClass, "find", [query, max, offset] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [foo:'bar], [max:10]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Map args, Integer max) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, args, max] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and arguments and a maximum results to return value
-     *
-     * @param query The query
-     * @param args The arguments
-     * @param max The maximum to return
-     * @param offset The offset
-     *
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [foo:'bar], [max:10, offset:5]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Map args, Integer max, Integer offset) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, args, max, offset] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [max:10]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Integer max) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, max] as Object[])
-    }
-
-    /**
-     * Finds a list of results for the given query and a maximum results to return value
-     *
-     * @param query The query
-     * @param max The maximum to return
-     * @return A list of results
-     *
-     * @deprecated Use findAll('..', [max:10, offset:5]) instead
-     */
-    @Deprecated
-    List<D> findAll(String query, Integer max, Integer offset) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, max, offset] as Object[])
-    }
-
-    @Override
-    List<D> findAllWhere(Map queryMap, Map args) {
-        if (!queryMap) return null
-
-        (List<D>)hibernateTemplate.execute( { Session session ->
-                Map<String, Object> processedQueryMap = [:]
-                queryMap.each{ key, value -> processedQueryMap[key.toString()] = value }
-                Map queryArgs = filterQueryArgumentMap(processedQueryMap)
-
-                List<String> nullNames = removeNullNames(queryArgs)
-                Criteria criteria = session.createCriteria(persistentClass)
-                hibernateTemplate.applySettings(criteria)
-                criteria.add(Restrictions.allEq(queryArgs))
-                for (name in nullNames) {
-                    criteria.add Restrictions.isNull(name)
+            params.eachWithIndex { val, int i ->
+                if (val instanceof CharSequence) {
+                    q.setParameter i, val.toString()
                 }
-                criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
-                criteria.list()
-        } as GrailsHibernateTemplate.HibernateCallback)
-    }
-
-    @Override
-    D findWhere(Map queryMap, Map args) {
-        if (!queryMap) return null
-
-        (D)hibernateTemplate.execute( { Session session ->
-                Map<String, Object> processedQueryMap = [:]
-                queryMap.each{ key, value -> processedQueryMap[key.toString()] = value }
-                Map queryArgs = filterQueryArgumentMap(processedQueryMap)
-                List<String> nullNames = removeNullNames(queryArgs)
-                Criteria criteria = session.createCriteria(persistentClass)
-                hibernateTemplate.applySettings(criteria)
-                criteria.add(Restrictions.allEq(queryArgs))
-                for (name in nullNames) {
-                    criteria.add Restrictions.isNull(name)
+                else {
+                    q.setParameter i, val
                 }
-                criteria.setMaxResults(1)
-                GrailsHibernateUtil.unwrapIfProxy(criteria.uniqueResult())
-        } as GrailsHibernateTemplate.HibernateCallback)
-    }
-
-    private Map filterQueryArgumentMap(Map query) {
-        def queryArgs = [:]
-        for (entry in query.entrySet()) {
-            if (entry.value instanceof CharSequence) {
-                queryArgs[entry.key] = entry.value.toString()
             }
-            else {
-                queryArgs[entry.key] = entry.value
-            }
+            populateQueryArguments(q, args)
+            return q.executeUpdate()
         }
-        return queryArgs
-    }
-
-    private List<String> removeNullNames(Map query) {
-        List<String> nullNames = []
-        Set<String> allNames = new HashSet(query.keySet())
-        for (String name in allNames) {
-            def value = query[name]
-            if (value == null) {
-                query.remove name
-                nullNames << name
-            }
-        }
-        nullNames
     }
 
     @Override
@@ -535,116 +228,5 @@
         }
     }
 
-    @Override
-    List<D> executeQuery(String query) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query] as Object[])
-    }
 
-    List<D> executeQuery(String query, arg) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, arg] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Map args) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, args] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Map params, Map args) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, params, args] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Collection params) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, params] as Object[])
-    }
-
-    @Override
-    List<D> executeQuery(String query, Collection params, Map args) {
-        (List<D>)executeQueryMethod.invoke(persistentClass, "executeQuery", [query, params, args] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Map args) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, args] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Map params, Map args) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, params, args] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Collection params) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, params] as Object[])
-    }
-
-    @Override
-    Integer executeUpdate(String query, Collection params, Map args) {
-        (Integer)executeUpdateMethod.invoke(persistentClass, "executeUpdate", [query, params, args] as Object[])
-    }
-
-    @Override
-    D find(String query) {
-        (D)findMethod.invoke(persistentClass, "find", [query] as Object[])
-    }
-
-    D find(String query, Object[] params) {
-        (D)findMethod.invoke(persistentClass, "find", [query, params] as Object[])
-    }
-
-    @Override
-    D find(String query, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [query, args] as Object[])
-    }
-
-    @Override
-    D find(String query, Map params, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [query, params, args] as Object[])
-    }
-
-    @Override
-    Object find(String query, Collection params) {
-        findMethod.invoke(persistentClass, "find", [query, params] as Object[])
-    }
-
-    @Override
-    D find(String query, Collection params, Map args) {
-        (D)findMethod.invoke(persistentClass, "find", [query, params, args] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, args] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Map params, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, params, args] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Collection params) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, params] as Object[])
-    }
-
-    @Override
-    List<D> findAll(String query, Collection params, Map args) {
-        (List<D>)findAllMethod.invoke(persistentClass, "findAll", [query, params, args] as Object[])
-    }
-
-    @Override
-    D create() {
-        return (D)super.create()
-    }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy
index 4fcb082..6881ddf 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateGormValidationApi.groovy
@@ -17,22 +17,10 @@
 
 import groovy.transform.CompileStatic
 
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ValidatePersistentMethod
-
 @CompileStatic
 class HibernateGormValidationApi<D> extends AbstractHibernateGormValidationApi<D> {
 
-    ValidatePersistentMethod validateMethod
-
     HibernateGormValidationApi(Class<D> persistentClass, HibernateDatastore datastore, ClassLoader classLoader) {
         super(persistentClass, datastore, classLoader)
-
-        def mappingContext = datastore.mappingContext
-        def grailsApplication = datastore.grailsApplication
-        if (grailsApplication) {
-            def validator = mappingContext.getEntityValidator(mappingContext.getPersistentEntity(persistentClass.name))
-            validateMethod = new ValidatePersistentMethod(datastore.getSessionFactory(),
-                classLoader, grailsApplication, validator, datastore)
-        }
     }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java
index ead80b9..22228b4 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateSession.java
@@ -21,10 +21,10 @@
 
 import javax.persistence.FlushModeType;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
+import grails.core.GrailsApplication;
+import grails.core.support.proxy.ProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.HibernateProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.query.HibernateQuery;
-import org.codehaus.groovy.grails.support.proxy.ProxyHandler;
 import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.query.Query;
 import org.grails.datastore.mapping.query.api.QueryableCriteria;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java
index c36c272..1da399a 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/DefaultGrailsDomainConfiguration.java
@@ -14,20 +14,26 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
+import grails.core.GrailsApplication;
+import grails.core.GrailsClass;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import groovy.lang.Closure;
 import groovy.util.Eval;
 
 import java.util.HashSet;
+import java.util.Properties;
 import java.util.Set;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwarePojoEntityTuplizer;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.hibernate.EntityMode;
+import org.hibernate.HibernateException;
 import org.hibernate.MappingException;
 import org.hibernate.cfg.Configuration;
 import org.hibernate.cfg.Mappings;
+import org.hibernate.cfg.Settings;
+import org.hibernate.service.ServiceRegistry;
 
 /**
  * Creates runtime configuration mapping for the Grails domain classes
@@ -81,6 +87,19 @@
         dataSourceName = name;
     }
 
+    @Override
+    public Settings buildSettings(ServiceRegistry serviceRegistry) {
+        Settings settings = super.buildSettings(serviceRegistry);
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
+
+    @Override
+    public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
+        Settings settings = super.buildSettings(props, serviceRegistry);
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
     /**
      * Overrides the default behaviour to including binding of Grails domain classes.
      */
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java
index f25d6fb..e387a6c 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsAnnotationConfiguration.java
@@ -15,16 +15,16 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
+import grails.core.*;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.*;
 import org.codehaus.groovy.grails.orm.hibernate.EventListenerIntegrator;
 import org.codehaus.groovy.grails.orm.hibernate.GrailsSessionContext;
 import org.codehaus.groovy.grails.orm.hibernate.HibernateEventListeners;
-import org.hibernate.HibernateException;
-import org.hibernate.MappingException;
-import org.hibernate.SessionFactory;
-import org.hibernate.SessionFactoryObserver;
+import org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwarePojoEntityTuplizer;
+import org.grails.core.artefact.AnnotationDomainClassArtefactHandler;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.hibernate.*;
 import org.hibernate.boot.registry.BootstrapServiceRegistry;
 import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
 import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
@@ -56,6 +56,7 @@
 import javax.persistence.Entity;
 import javax.persistence.MappedSuperclass;
 import java.io.IOException;
+import java.lang.InstantiationException;
 import java.util.*;
 
 /**
@@ -100,6 +101,9 @@
         if (shouldMapWithGorm(domainClass)) {
             domainClasses.add(domainClass);
         }
+        else {
+            addAnnotatedClass(domainClass.getClazz());
+        }
 
         return this;
     }
@@ -332,6 +336,20 @@
     }
 
     @Override
+    public Settings buildSettings(ServiceRegistry serviceRegistry) {
+        Settings settings = super.buildSettings(serviceRegistry);
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
+
+    @Override
+    public Settings buildSettings(Properties props, ServiceRegistry serviceRegistry) throws HibernateException {
+        Settings settings = super.buildSettings(props, serviceRegistry);
+        settings.getEntityTuplizerFactory().registerDefaultTuplizerClass(EntityMode.POJO, GroovyAwarePojoEntityTuplizer.class);
+        return settings;
+    }
+
+    @Override
     public SessionFactory buildSessionFactory() throws HibernateException {
 
         // set the class loader to load Groovy classes
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java
index 0e14799..75f6d15 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinder.java
@@ -17,13 +17,13 @@
 import java.util.Arrays;
 import java.util.List;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.validation.ConstrainedProperty;
+import grails.validation.Constraint;
 import org.codehaus.groovy.grails.orm.hibernate.persister.entity.GroovyAwareJoinedSubclassEntityPersister;
 import org.codehaus.groovy.grails.orm.hibernate.persister.entity.GroovyAwareSingleTableEntityPersister;
 import org.codehaus.groovy.grails.orm.hibernate.validation.UniqueConstraint;
-import org.codehaus.groovy.grails.validation.ConstrainedProperty;
-import org.codehaus.groovy.grails.validation.Constraint;
 import org.hibernate.mapping.Column;
 import org.hibernate.mapping.OneToOne;
 import org.hibernate.mapping.Table;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java
index 318d910..0bc0d5d 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsHibernateUtil.java
@@ -15,19 +15,25 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg;
 
+import grails.core.GrailsApplication;
+import grails.core.GrailsClass;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import grails.util.CollectionUtils;
+import grails.util.GrailsClassUtils;
 import grails.util.Holders;
 import groovy.lang.GroovyObject;
 import groovy.lang.GroovySystem;
 import groovy.lang.MetaClass;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.*;
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateDomainClass;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.GroovyAwareJavassistProxyFactory;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.HibernateProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.query.HibernateQueryConstants;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
+import org.grails.core.DefaultGrailsDomainClass;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.hibernate.*;
 import org.hibernate.criterion.Order;
 import org.hibernate.engine.spi.EntityEntry;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy
index f22d04e..902440a 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/HibernateUtils.groovy
@@ -16,15 +16,15 @@
 package org.codehaus.groovy.grails.orm.hibernate.cfg
 
 import grails.artefact.Enhanced
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
+import grails.util.GrailsClassUtils
+import grails.util.GrailsMetaClassUtils
 import grails.util.GrailsNameUtils
 import groovy.transform.CompileStatic
 import groovy.transform.TypeCheckingMode
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsClassUtils
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate
 import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormEnhancer
@@ -32,8 +32,9 @@
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormStaticApi
 import org.codehaus.groovy.grails.orm.hibernate.HibernateGormValidationApi
 import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor
+import org.codehaus.groovy.grails.orm.hibernate.support.HibernateRuntimeUtils
 import org.codehaus.groovy.runtime.InvokerHelper
-import org.codehaus.groovy.runtime.StringGroovyMethods
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.grails.datastore.mapping.core.Datastore
 import org.grails.datastore.mapping.model.MappingContext
 import org.grails.datastore.mapping.model.PersistentEntity
@@ -186,13 +187,14 @@
     // http://jira.codehaus.org/browse/GROOVY-6138 prevents using CompileStatic for this method
     @CompileStatic(TypeCheckingMode.SKIP)
     static void enhanceProxyClass(Class proxyClass) {
-        MetaMethod grailsEnhancedMetaMethod = proxyClass.metaClass.getStaticMetaMethod("grailsEnhanced", (Class[])null)
+
+        MetaClass mc = GrailsMetaClassUtils.getExpandoMetaClass(proxyClass)
+        MetaMethod grailsEnhancedMetaMethod = mc.getStaticMetaMethod("grailsEnhanced", (Class[])null)
         if (grailsEnhancedMetaMethod != null && grailsEnhancedMetaMethod.invoke(proxyClass, null) == proxyClass) {
             return
         }
 
-        MetaClass mc = (MetaClass)InvokerHelper.getMetaClass(proxyClass)
-        MetaClass superMc = InvokerHelper.getMetaClass(proxyClass.getSuperclass())
+        MetaClass superMc = GrailsMetaClassUtils.getExpandoMetaClass(proxyClass.getSuperclass())
 
         // hasProperty
         registerMetaMethod(mc, 'hasProperty', { String name ->
@@ -332,38 +334,6 @@
     }
 
     static Object convertValueToType(Object passedValue, Class targetType, ConversionService conversionService) {
-        // workaround for GROOVY-6127, do not assign directly in parameters before it's fixed
-        Object value = passedValue
-        if(targetType != null && value != null && !(value in targetType)) {
-            if (value instanceof CharSequence) {
-                value = value.toString()
-                if(value in targetType) {
-                    return value
-                }
-            }
-            try {
-                if (value instanceof Number && (targetType==Long || targetType==Integer)) {
-                    if(targetType == Long) {
-                        value = ((Number)value).toLong()
-                    } else {
-                        value = ((Number)value).toInteger()
-                    }
-                } else if (value instanceof String && targetType in Number) {
-                    String strValue = value.trim()
-                    if(targetType == Long) {
-                        value = Long.parseLong(strValue)
-                    } else if (targetType == Integer) {
-                        value = Integer.parseInt(strValue)
-                    } else {
-                        value = StringGroovyMethods.asType(strValue, targetType)
-                    }
-                } else {
-                    value = conversionService.convert(value, targetType)
-                }
-            } catch (e) {
-                // ignore
-            }
-        }
-        return value
+        HibernateRuntimeUtils.convertValueToType(passedValue, targetType, conversionService)
     }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractClausedStaticPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractClausedStaticPersistentMethod.java
deleted file mode 100644
index ede2b7a..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractClausedStaticPersistentMethod.java
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.orm.RlikeExpression;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-import groovy.lang.Range;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.*;
-import org.hibernate.Criteria;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.CriteriaQuery;
-import org.hibernate.criterion.Criterion;
-import org.hibernate.criterion.Restrictions;
-import org.hibernate.engine.spi.TypedValue;
-import org.springframework.beans.TypeMismatchException;
-import org.springframework.core.convert.ConversionService;
-import org.springframework.util.Assert;
-
-import java.util.*;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * @author Graeme Rocher
- * @since 31-Aug-2005
- */
-public abstract class AbstractClausedStaticPersistentMethod extends AbstractStaticPersistentMethod {
-
-    protected static final Log LOG = LogFactory.getLog(AbstractClausedStaticPersistentMethod.class);
-
-    /**
-     * @author Graeme Rocher
-     */
-    protected abstract static class GrailsMethodExpression {
-        protected static final String LESS_THAN = "LessThan";
-        protected static final String LESS_THAN_OR_EQUAL = "LessThanEquals";
-        protected static final String GREATER_THAN = "GreaterThan";
-        protected static final String GREATER_THAN_OR_EQUAL = "GreaterThanEquals";
-        protected static final String LIKE = "Like";
-        protected static final String ILIKE = "Ilike";
-        protected static final String RLIKE = "Rlike";
-        protected static final String BETWEEN = "Between";
-        protected static final String IN_LIST= "InList";
-        protected static final String IS_NOT_NULL = "IsNotNull";
-        protected static final String IS_NULL = "IsNull";
-        protected static final String NOT = "Not";
-        protected static final String EQUAL = "Equal";
-        protected static final String NOT_EQUAL = "NotEqual";
-        protected static final String IN_RANGE = "InRange";
-
-        protected String propertyName;
-        protected Object[] arguments;
-        protected int argumentsRequired;
-        protected boolean negation;
-        protected String type;
-        protected Class<?> targetClass;
-        private GrailsApplication application;
-        protected final ConversionService conversionService;
-
-        /**
-         * Used as an indication that an expression will return no results, so stop processing and return nothing.
-         */
-        static final Criterion FORCE_NO_RESULTS = new Criterion() {
-            private static final long serialVersionUID = 1L;
-            public TypedValue[] getTypedValues(Criteria c, CriteriaQuery q) { return null; }
-            public String toSqlString(Criteria c, CriteriaQuery q) { return null; }
-        };
-
-        GrailsMethodExpression(GrailsApplication application, Class<?> targetClass,
-                String propertyName, String type, int argumentsRequired, boolean negation, ConversionService conversionService) {
-            this.application = application;
-            this.targetClass = targetClass;
-            this.propertyName = propertyName;
-            this.type = type;
-            this.argumentsRequired = argumentsRequired;
-            this.negation = negation;
-            this.conversionService = conversionService;
-        }
-
-        GrailsMethodExpression(GrailsApplication application, Class<?> targetClass,
-                String queryParameter, String type, int argumentsRequired, ConversionService conversionService) {
-            this(application, targetClass, calcPropertyName(queryParameter, type), type,
-                 argumentsRequired, isNegation(queryParameter, type), conversionService);
-        }
-
-        public String getPropertyName() {
-            return propertyName;
-        }
-
-        public Object[] getArguments() {
-            Object[] copy = new Object[arguments.length];
-            System.arraycopy(arguments, 0, copy, 0, arguments.length);
-            return copy;
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder buf = new StringBuilder("[GrailsMethodExpression] ");
-            buf.append(propertyName)
-               .append(" ")
-               .append(type)
-               .append(" ");
-
-            for (int i = 0; i < arguments.length; i++) {
-                buf.append(arguments[i]);
-                if (i != arguments.length) {
-                    buf.append(" and ");
-                }
-            }
-            return buf.toString();
-        }
-
-        @SuppressWarnings("unchecked")
-        protected void setArguments(Object[] args) throws IllegalArgumentException {
-            if (args.length != argumentsRequired) {
-                throw new IllegalArgumentException("Method expression '" + type + "' requires " +
-                        argumentsRequired + " arguments");
-            }
-
-            GrailsDomainClass dc = (GrailsDomainClass)application.getArtefact(
-                    DomainClassArtefactHandler.TYPE, targetClass.getName());
-            GrailsDomainClassProperty prop = dc.getPropertyByName(propertyName);
-
-            if (prop == null) {
-                throw new IllegalArgumentException("Property " + propertyName +
-                        " doesn't exist for method expression '"+ type + "'");
-            }
-
-            for (int i = 0; i < args.length; i++) {
-                Object currentArg = args[i];
-                if (currentArg == null) continue;
-                // convert GStrings to strings
-                if (prop.getType() == String.class && (currentArg instanceof CharSequence)) {
-                    args[i] = currentArg.toString();
-                }
-                else if (!prop.getType().isAssignableFrom(currentArg.getClass()) && !(GrailsClassUtils.isMatchBetweenPrimativeAndWrapperTypes(prop.getType(), currentArg.getClass()))) {
-                    try {
-                        if (type.equals(IN_LIST)) {
-                            if(currentArg instanceof Collection) {
-                                currentArg = convertArgumentList(prop, (Collection)currentArg);
-                            }
-                            args[i] = conversionService.convert(currentArg, Collection.class);
-                        }
-                        else {
-                            args[i] = conversionService.convert(currentArg, prop.getType());
-                        }
-                    }
-                    catch (TypeMismatchException tme) {
-                        // if we cannot perform direct conversion and argument is subclass of Number
-                        // we can try to convert it through its String representation
-                        if (Number.class.isAssignableFrom(currentArg.getClass())) {
-                            try {
-                                args[i] = conversionService.convert(currentArg.toString(), prop.getType());
-                            }
-                            catch(TypeMismatchException tme1) {
-                                throw new IllegalArgumentException("Cannot convert value " + currentArg + " of property '"+propertyName+"' to required type " + prop.getType() + ": " + tme1.getMessage());
-                            }
-                        }
-                        else {
-                            throw new IllegalArgumentException("Cannot convert value " + currentArg + " of property '"+propertyName+"' to required type " + prop.getType());
-                        }
-                    }
-                }
-                else if(type.equals(IN_LIST) && (currentArg instanceof Collection)) {
-                    currentArg = convertArgumentList(prop, (Collection) currentArg);
-                }
-            }
-
-            arguments = args;
-        }
-
-        protected List convertArgumentList(GrailsDomainClassProperty prop, Collection argList) {
-            List convertedList = new ArrayList(argList.size());
-            for (Object item : argList) {
-                if(item instanceof CharSequence) {
-                    item = item.toString();
-                }
-                convertedList.add(conversionService.convert(item, prop.getType()));
-            }
-            return convertedList;
-        }
-
-        abstract Criterion createCriterion();
-
-        protected Criterion getCriterion() {
-            Assert.notNull(arguments, "Parameters array must be set before retrieving Criterion");
-            return negation ? Restrictions.not(createCriterion()) : createCriterion();
-        }
-
-        protected static GrailsMethodExpression create(final GrailsApplication application,
-                Class<?> clazz, String queryParameter, ConversionService conversionService) {
-
-            if (queryParameter.endsWith(LESS_THAN_OR_EQUAL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, LESS_THAN_OR_EQUAL, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.le(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(LESS_THAN)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, LESS_THAN, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.lt(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(GREATER_THAN_OR_EQUAL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, GREATER_THAN_OR_EQUAL, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.ge(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(GREATER_THAN)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, GREATER_THAN, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.gt(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(LIKE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, LIKE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.like(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(ILIKE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, ILIKE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return Restrictions.ilike(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(RLIKE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, RLIKE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                        return new RlikeExpression(propertyName, arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IS_NOT_NULL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IS_NOT_NULL, 0, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.isNotNull(propertyName);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IS_NULL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IS_NULL, 0, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.isNull(propertyName);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(BETWEEN)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, BETWEEN, 2, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.between(propertyName,arguments[0], arguments[1]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IN_LIST)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IN_LIST, 1, conversionService) {
-                    @SuppressWarnings("rawtypes")
-                    @Override
-                    Criterion createCriterion() {
-                        Collection collection = (Collection)arguments[0];
-                        if (collection == null || collection.isEmpty()) {
-                            return FORCE_NO_RESULTS;
-                        }
-                        return Restrictions.in(propertyName, collection);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(NOT_EQUAL)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, NOT_EQUAL, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        if (arguments[0] == null) return Restrictions.isNotNull(propertyName);
-                        return Restrictions.ne(propertyName,arguments[0]);
-                    }
-                };
-            }
-
-            if (queryParameter.endsWith(IN_RANGE)) {
-                return new GrailsMethodExpression(application, clazz, queryParameter, IN_RANGE, 1, conversionService) {
-                    @Override
-                    Criterion createCriterion() {
-                        return Restrictions.between(propertyName, arguments[0], arguments[1]);
-                    }
-                    @Override
-                    protected void setArguments(Object[] args) throws IllegalArgumentException {
-                        if (args != null && args.length > 0 && args[0] instanceof Range) {
-                            Range<?> range = (Range<?>) args[0];
-                            args = new Object[] { range.getFrom(), range.getTo() };
-                            argumentsRequired = 2;
-                        }
-                        super.setArguments(args);
-                    }
-                };
-            }
-
-            return new GrailsMethodExpression(application, clazz,
-                    calcPropertyName(queryParameter, null),
-                    EQUAL, 1, isNegation(queryParameter, EQUAL), conversionService) {
-                @Override
-                Criterion createCriterion() {
-                    if (arguments[0] == null) return Restrictions.isNull(propertyName);
-                    return Restrictions.eq(propertyName,arguments[0]);
-                }
-            };
-        }
-
-        private static boolean isNegation(String queryParameter, String clause) {
-            String propName;
-            if (clause != null && !clause.equals(EQUAL)) {
-                int i = queryParameter.indexOf(clause);
-                propName = queryParameter.substring(0,i);
-            }
-            else {
-                propName = queryParameter;
-            }
-            return propName.endsWith(NOT);
-        }
-
-        private static String calcPropertyName(String queryParameter, String clause) {
-            String propName;
-            if (clause != null && !clause.equals(EQUAL)) {
-                int i = queryParameter.indexOf(clause);
-                propName = queryParameter.substring(0,i);
-            }
-            else {
-                propName = queryParameter;
-            }
-            if (propName.endsWith(NOT)) {
-                int i = propName.lastIndexOf(NOT);
-                propName = propName.substring(0, i);
-            }
-            return propName.substring(0,1).toLowerCase(Locale.ENGLISH) + propName.substring(1);
-        }
-    }
-
-    private final String[] operators;
-    private final Pattern[] operatorPatterns;
-    protected final ConversionService conversionService;
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     * @param pattern
-     * @param operators
-     */
-    public AbstractClausedStaticPersistentMethod(GrailsApplication application, SessionFactory sessionFactory, ClassLoader classLoader, Pattern pattern, String[] operators, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, pattern, application, defaultFlushMode);
-        this.operators = operators;
-        operatorPatterns = new Pattern[operators.length];
-        for (int i = 0; i < operators.length; i++) {
-            operatorPatterns[i] = Pattern.compile("(\\w+)("+operators[i]+")(\\p{Upper})(\\w+)");
-        }
-        this.conversionService = conversionService;
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractStaticPersistentMethod#doInvokeInternal(java.lang.Class, java.lang.String, java.lang.Object[])
-     */
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName,
-                                      Closure additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz, methodName, null, additionalCriteria, arguments);
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz, methodName, additionalCriteria,null, arguments);
-    }
-
-    protected Object doInvokeInternal(Class<?> clazz, String methodName, DetachedCriteria<?> detachedCriteria, Closure<?> additionalCriteria, Object[] arguments) {
-        List<GrailsMethodExpression> expressions = new ArrayList<GrailsMethodExpression>();
-        if (arguments == null) arguments = new Object[0];
-        Matcher match = super.getPattern().matcher(methodName);
-        // find match
-        match.find();
-
-        String[] queryParameters;
-        int totalRequiredArguments = 0;
-        // get the sequence clauses
-        final String querySequence;
-        int groupCount = match.groupCount();
-        if (groupCount == 6) {
-            String booleanProperty = match.group(3);
-            if (booleanProperty == null) {
-                booleanProperty = match.group(6);
-                querySequence = null;
-            }
-            else {
-                querySequence = match.group(5);
-            }
-            Boolean arg = Boolean.TRUE;
-            if (booleanProperty.matches("Not[A-Z].*")) {
-                booleanProperty = booleanProperty.substring(3);
-                arg = Boolean.FALSE;
-            }
-            GrailsMethodExpression booleanExpression = GrailsMethodExpression.create(
-                    application, clazz, booleanProperty, conversionService);
-            booleanExpression.setArguments(new Object[]{arg});
-            expressions.add(booleanExpression);
-        }
-        else {
-            querySequence = match.group(2);
-        }
-        // if it contains operator and split
-        boolean containsOperator = false;
-        String operatorInUse = null;
-
-        if (querySequence != null) {
-            for (int i = 0; i < operators.length; i++) {
-                Matcher currentMatcher = operatorPatterns[i].matcher(querySequence);
-                if (currentMatcher.find()) {
-                    containsOperator = true;
-                    operatorInUse = operators[i];
-
-                    queryParameters = querySequence.split(operatorInUse);
-
-                    // loop through query parameters and create expressions
-                    // calculating the number of arguments required for the expression
-                    int argumentCursor = 0;
-                    for (String queryParameter : queryParameters) {
-                        GrailsMethodExpression currentExpression = GrailsMethodExpression.create(
-                                application, clazz, queryParameter, conversionService);
-                        totalRequiredArguments += currentExpression.argumentsRequired;
-                        // populate the arguments into the GrailsExpression from the argument list
-                        Object[] currentArguments = new Object[currentExpression.argumentsRequired];
-                        if ((argumentCursor + currentExpression.argumentsRequired) > arguments.length) {
-                            throw new MissingMethodException(methodName, clazz, arguments);
-                        }
-
-                        for (int k = 0; k < currentExpression.argumentsRequired; k++, argumentCursor++) {
-                            currentArguments[k] = arguments[argumentCursor];
-                        }
-                        try {
-                            currentExpression.setArguments(currentArguments);
-                        }
-                        catch (IllegalArgumentException iae) {
-                            LOG.debug(iae.getMessage(), iae);
-                            throw new MissingMethodException(methodName, clazz, arguments);
-                        }
-                        // add to list of expressions
-                        expressions.add(currentExpression);
-                    }
-                    break;
-                }
-            }
-        }
-
-        // otherwise there is only one expression
-        if (!containsOperator && querySequence != null) {
-            GrailsMethodExpression solo = GrailsMethodExpression.create(application, clazz, querySequence, conversionService);
-
-            if (solo.argumentsRequired > arguments.length) {
-                throw new MissingMethodException(methodName, clazz, arguments);
-            }
-
-            totalRequiredArguments += solo.argumentsRequired;
-            Object[] soloArgs = new Object[solo.argumentsRequired];
-
-            System.arraycopy(arguments, 0, soloArgs, 0, solo.argumentsRequired);
-            try {
-                solo.setArguments(soloArgs);
-            }
-            catch (IllegalArgumentException iae) {
-                LOG.debug(iae.getMessage(), iae);
-                throw new MissingMethodException(methodName,clazz,arguments);
-            }
-            expressions.add(solo);
-        }
-
-        // if the total of all the arguments necessary does not equal the number of arguments throw exception
-        if (totalRequiredArguments > arguments.length) {
-            throw new MissingMethodException(methodName,clazz,arguments);
-        }
-
-        // calculate the remaining arguments
-        Object[] remainingArguments = new Object[arguments.length - totalRequiredArguments];
-        if (remainingArguments.length > 0) {
-            for (int i = 0, j = totalRequiredArguments; i < remainingArguments.length; i++,j++) {
-                remainingArguments[i] = arguments[j];
-            }
-        }
-
-        if (LOG.isTraceEnabled()) {
-            LOG.trace("Calculated expressions: " + expressions);
-        }
-
-        return doInvokeInternalWithExpressions(clazz, methodName, remainingArguments, expressions, operatorInUse, detachedCriteria, additionalCriteria);
-    }
-
-    @SuppressWarnings("rawtypes")
-    protected abstract Object doInvokeInternalWithExpressions(Class clazz, String methodName, Object[] arguments, List expressions, String operatorInUse, DetachedCriteria detachedCriteria, Closure additionalCriteria);
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractDynamicPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractDynamicPersistentMethod.java
deleted file mode 100644
index 140c537..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractDynamicPersistentMethod.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.validation.ValidationErrors;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.metaclass.AbstractDynamicMethodInvocation;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.SessionFactory;
-import org.springframework.util.Assert;
-import org.springframework.validation.Errors;
-import org.springframework.validation.FieldError;
-
-/**
- * @author Steven Devijver
- */
-public abstract class AbstractDynamicPersistentMethod extends AbstractDynamicMethodInvocation {
-
-    public static final String ERRORS_PROPERTY = "errors";
-
-    private ClassLoader classLoader;
-    private GrailsHibernateTemplate hibernateTemplate;
-    private SessionFactory sessionFactory;
-    GrailsApplication application;
-    int defaultFlushMode;
-
-    public AbstractDynamicPersistentMethod(Pattern pattern, SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, int defaultFlushMode) {
-        super(pattern);
-        Assert.notNull(sessionFactory, "Session factory is required!");
-        this.classLoader = classLoader;
-        Assert.notNull(application, "Constructor argument 'application' cannot be null");
-        this.application = application;
-        this.sessionFactory = sessionFactory;
-        hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, application, defaultFlushMode);
-    }
-
-    protected SessionFactory getSessionFactory() {
-        return sessionFactory;
-    }
-
-    protected GrailsHibernateTemplate getHibernateTemplate() {
-        return hibernateTemplate;
-    }
-
-    @Override
-    public Object invoke(Object target, String methodName, Object[] arguments) {
-        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try {
-            Thread.currentThread().setContextClassLoader(classLoader);
-            return doInvokeInternal(target, arguments);
-        }
-        finally {
-            Thread.currentThread().setContextClassLoader(originalClassLoader);
-        }
-    }
-
-    protected abstract Object doInvokeInternal(Object target, Object[] arguments);
-
-    /**
-     * This method will set the target object to read-only if it is contained with the Hibernate session,
-     * Preventing Hibernate dirty-checking from persisting the instance
-     *
-     * @param target The target object
-     */
-    protected void setObjectToReadOnly(final Object target) {
-        GrailsHibernateUtil.setObjectToReadyOnly(target, sessionFactory);
-    }
-
-    protected void setObjectToReadWrite(final Object target) {
-        GrailsHibernateUtil.setObjectToReadWrite(target, sessionFactory);
-    }
-
-    /**
-     * Initializes the Errors property on target.  The target will be assigned a new
-     * Errors property.  If the target contains any binding errors, those binding
-     * errors will be copied in to the new Errors property.
-     *
-     * @param target object to initialize
-     * @return the new Errors object
-     */
-    protected Errors setupErrorsProperty(Object target) {
-        MetaClass mc = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass());
-
-        ValidationErrors errors = new ValidationErrors(target);
-
-        Errors originalErrors = (Errors) mc.getProperty(target, ERRORS_PROPERTY);
-        for (Object o : originalErrors.getFieldErrors()) {
-            FieldError fe = (FieldError)o;
-            if (fe.isBindingFailure()) {
-                errors.addError(new FieldError(fe.getObjectName(),
-                                               fe.getField(),
-                                               fe.getRejectedValue(),
-                                               fe.isBindingFailure(),
-                                               fe.getCodes(),
-                                               fe.getArguments(),
-                                               fe.getDefaultMessage()));
-            }
-        }
-
-        mc.setProperty(target, ERRORS_PROPERTY, errors);
-        return errors;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethod.java
deleted file mode 100644
index 3721f23..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethod.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.NonUniqueResultException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Disjunction;
-import org.hibernate.criterion.Restrictions;
-import org.hibernate.internal.CriteriaImpl;
-
-public abstract class AbstractFindByPersistentMethod extends AbstractClausedStaticPersistentMethod {
-    public static final String OPERATOR_OR = "Or";
-    public static final String OPERATOR_AND = "And";
-    public static final String[] OPERATORS = { OPERATOR_AND, OPERATOR_OR };
-    private HibernateDatastore datastore;
-    private static final Map<String, Boolean> useLimitCache = new ConcurrentHashMap<String, Boolean>();
-
-    public AbstractFindByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,
-                                          SessionFactory sessionFactory, ClassLoader classLoader,
-                                          Pattern pattern, String[] operators) {
-        super(application, sessionFactory, classLoader, pattern, operators, datastore.getMappingContext().getConversionService(), datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternalWithExpressions(final Class clazz, String methodName, final Object[] arguments, final List expressions, String operatorInUse, final DetachedCriteria detachedCriteria, final Closure additionalCriteria) {
-        final String operator = OPERATOR_OR.equals(operatorInUse) ? OPERATOR_OR : OPERATOR_AND;
-        return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Criteria crit = buildCriteria(session, detachedCriteria, additionalCriteria, clazz, arguments, operator, expressions);
-
-                boolean useLimit = establishWhetherToUseLimit(clazz);
-                return getResult(crit, useLimit);
-            }
-        });
-    }
-
-    private boolean establishWhetherToUseLimit(Class<?> clazz) {
-        boolean useLimit = true;
-        GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE, clazz.getName());
-        if (domainClass != null) {
-            Boolean aBoolean = useLimitCache.get(domainClass.getName());
-            if (aBoolean != null) {
-                useLimit = aBoolean;
-            }
-            else {
-
-                for (GrailsDomainClassProperty property : domainClass.getPersistentProperties()) {
-                    if ((property.isOneToMany()||property.isManyToMany()) && property.getFetchMode() == GrailsDomainClassProperty.FETCH_EAGER) {
-                        useLimit = false;
-                        useLimitCache.put(domainClass.getName(), useLimit);
-                        break;
-                    }
-                }
-            }
-        }
-        return useLimit;
-    }
-
-    protected Object getResult(Criteria crit) {
-        CriteriaImpl impl = (CriteriaImpl) crit;
-        String entityOrClassName = impl.getEntityOrClassName();
-        GrailsClass domainClass = application.getArtefact(DomainClassArtefactHandler.TYPE, entityOrClassName);
-        boolean useLimit = establishWhetherToUseLimit(domainClass.getClazz());
-
-        return getResult(crit, useLimit);
-    }
-
-    protected Object getResult(Criteria crit, boolean useLimit) {
-        if (useLimit) {
-            final List<?> list = crit.list();
-            if (!list.isEmpty()) {
-                return GrailsHibernateUtil.unwrapIfProxy(list.get(0));
-            }
-        }
-        else {
-            try {
-                return crit.uniqueResult();
-            } catch (NonUniqueResultException e) {
-                return null;
-            }
-        }
-        return null;
-    }
-
-    protected Criteria buildCriteria(Session session, DetachedCriteria<?> detachedCriteria,
-            Closure<?> additionalCriteria, Class<?> clazz, Object[] arguments,
-            String operator, List<?> expressions) {
-        Criteria crit = getCriteria(datastore, application, session, detachedCriteria, additionalCriteria, clazz);
-
-        boolean useLimit = establishWhetherToUseLimit(clazz);
-
-        if (arguments.length > 0) {
-            if (arguments[0] instanceof Map<?, ?>) {
-                Map<?, ?> argMap = (Map<?, ?>)arguments[0];
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit, argMap, conversionService);
-                if (!argMap.containsKey(GrailsHibernateUtil.ARGUMENT_FETCH)) {
-                    if (useLimit) {
-                        crit.setMaxResults(1);
-                    }
-                }
-            }
-            else {
-                if (useLimit) {
-                    crit.setMaxResults(1);
-                }
-            }
-        }
-        else {
-            if (useLimit) {
-                crit.setMaxResults(1);
-            }
-        }
-
-        if (operator.equals(OPERATOR_OR)) {
-            if (firstExpressionIsRequiredBoolean()) {
-                GrailsMethodExpression expression = (GrailsMethodExpression) expressions.remove(0);
-                crit.add(expression.getCriterion());
-            }
-            Disjunction dis = Restrictions.disjunction();
-            for (Object expression : expressions) {
-                GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                dis.add(current.getCriterion());
-            }
-            crit.add(dis);
-        }
-        else {
-            for (Object expression : expressions) {
-                GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                crit.add(current.getCriterion());
-            }
-        }
-        return crit;
-    }
-
-    /**
-     * Indicates if the first expression in the query is a required boolean property and as such should
-     * be ANDed to the other expressions, not ORed.
-     *
-     * @return true if the first expression is a required boolean property, false otherwise
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByBooleanPropertyPersistentMethod
-     */
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return false;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractSavePersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractSavePersistentMethod.java
deleted file mode 100644
index d342d16..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractSavePersistentMethod.java
+++ /dev/null
@@ -1,377 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.validation.DeferredBindingActions;
-import grails.validation.ValidationException;
-import groovy.lang.GroovyObject;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-
-import java.io.Serializable;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass;
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.validation.AbstractPersistentConstraint;
-import org.codehaus.groovy.grails.validation.CascadingValidator;
-import org.grails.datastore.mapping.engine.event.ValidationEvent;
-import org.hibernate.SessionFactory;
-import org.springframework.beans.BeanWrapper;
-import org.springframework.beans.BeanWrapperImpl;
-import org.springframework.beans.InvalidPropertyException;
-import org.springframework.validation.Errors;
-import org.springframework.validation.Validator;
-
-/**
- * Abstract class for different implementations that perform saving to implement.
- *
- * @author Graeme Rocher
- * @since 0.3
- */
-public abstract class AbstractSavePersistentMethod extends AbstractDynamicPersistentMethod {
-
-    private HibernateDatastore datastore;
-    private static final String ARGUMENT_VALIDATE = "validate";
-    private static final String ARGUMENT_DEEP_VALIDATE = "deepValidate";
-    private static final String ARGUMENT_FLUSH = "flush";
-    private static final String ARGUMENT_INSERT = "insert";
-    private static final String ARGUMENT_FAIL_ON_ERROR = "failOnError";
-    private static final String FAIL_ON_ERROR_CONFIG_PROPERTY = "grails.gorm.failOnError";
-    private static final String AUTO_FLUSH_CONFIG_PROPERTY = "grails.gorm.autoFlush";
-
-    /**
-     * When a domain instance is saved without validation, we put it
-     * into this thread local variable. Any code that needs to know
-     * whether the domain instance should be validated can just check
-     * the value. Note that this only works because the session is
-     * flushed when a domain instance is saved without validation.
-     */
-    private static ThreadLocal<Set<Integer>> disableAutoValidationFor = new ThreadLocal<Set<Integer>>();
-
-    static {
-        ShutdownOperations.addOperation(new Runnable() {
-            public void run() {
-                disableAutoValidationFor.remove();
-            }
-        });
-    }
-
-    private static Set<Integer> getDisableAutoValidationFor() {
-        Set<Integer> identifiers = disableAutoValidationFor.get();
-        if (identifiers == null)
-            disableAutoValidationFor.set(identifiers = new HashSet<Integer>());
-        return identifiers;
-    }
-
-    public static boolean isAutoValidationDisabled(Object obj) {
-        Set<Integer> identifiers = getDisableAutoValidationFor();
-        return obj != null && identifiers.contains(System.identityHashCode(obj));
-    }
-
-    public static void clearDisabledValidations(Object obj) {
-        getDisableAutoValidationFor().remove(System.identityHashCode(obj));
-    }
-
-    public static void clearDisabledValidations() {
-        getDisableAutoValidationFor().clear();
-    }
-
-    public AbstractSavePersistentMethod(Pattern pattern, SessionFactory sessionFactory,
-              ClassLoader classLoader, GrailsApplication application,
-              GrailsDomainClass domainClass, HibernateDatastore datastore) {
-        super(pattern, sessionFactory, classLoader, application, datastore.getDefaultFlushMode());
-
-        this.datastore = datastore;
-    }
-
-    public AbstractSavePersistentMethod(Pattern pattern, SessionFactory sessionFactory,
-             ClassLoader classLoader, GrailsApplication application, HibernateDatastore datastore) {
-       this(pattern, sessionFactory, classLoader, application, null, datastore);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private boolean shouldFail(GrailsApplication grailsApplication, GrailsDomainClass domainClass) {
-        boolean shouldFail = false;
-        final Map config = grailsApplication.getFlatConfig();
-        if (config.containsKey(FAIL_ON_ERROR_CONFIG_PROPERTY)) {
-            Object configProperty = config.get(FAIL_ON_ERROR_CONFIG_PROPERTY);
-            if (configProperty instanceof Boolean) {
-                shouldFail = Boolean.TRUE == configProperty;
-            }
-            else if (configProperty instanceof List) {
-                if (domainClass != null) {
-                    final Class theClass = domainClass.getClazz();
-                    List packageList = (List) configProperty;
-                    shouldFail = GrailsClassUtils.isClassBelowPackage(theClass, packageList);
-                }
-            }
-        }
-        return shouldFail;
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod#doInvokeInternal(java.lang.Object, java.lang.Object[])
-     */
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(final Object target, Object[] arguments) {
-        GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,
-                target.getClass().getName());
-
-        DeferredBindingActions.runActions();
-        boolean shouldFlush = shouldFlush(arguments);
-        boolean shouldValidate = shouldValidate(arguments, domainClass);
-        if (shouldValidate) {
-            Validator validator = domainClass.getValidator();
-
-            if (domainClass instanceof DefaultGrailsDomainClass) {
-                GrailsHibernateUtil.autoAssociateBidirectionalOneToOnes((DefaultGrailsDomainClass) domainClass, target);
-            }
-            Errors errors = setupErrorsProperty(target);
-
-            if (validator != null) {
-                datastore.getApplicationContext().publishEvent(new ValidationEvent(datastore, target));
-
-                boolean deepValidate = true;
-                Map argsMap = null;
-                if (arguments.length > 0 && arguments[0] instanceof Map) {
-                    argsMap = (Map) arguments[0];
-                }
-                if (argsMap != null && argsMap.containsKey(ARGUMENT_DEEP_VALIDATE)) {
-                    deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, argsMap);
-                }
-
-                AbstractPersistentConstraint.sessionFactory.set(datastore.getSessionFactory());
-                try {
-                    if (deepValidate && (validator instanceof CascadingValidator)) {
-                        ((CascadingValidator)validator).validate(target, errors, deepValidate);
-                    }
-                    else {
-                        validator.validate(target,errors);
-                    }
-                }
-                finally {
-                    AbstractPersistentConstraint.sessionFactory.remove();
-                }
-
-                if (errors.hasErrors()) {
-                    handleValidationError(domainClass,target,errors);
-                    boolean shouldFail = shouldFail(application, domainClass);
-                    if (argsMap != null && argsMap.containsKey(ARGUMENT_FAIL_ON_ERROR)) {
-                        shouldFail = GrailsClassUtils.getBooleanFromMap(ARGUMENT_FAIL_ON_ERROR, argsMap);
-                    }
-                    if (shouldFail) {
-                        throw new ValidationException("Validation Error(s) occurred during save()", errors);
-                    }
-                    return null;
-                }
-
-                setObjectToReadWrite(target);
-            }
-        }
-
-        // this piece of code will retrieve a persistent instant
-        // of a domain class property is only the id is set thus
-        // relieving this burden off the developer
-        if (domainClass != null) {
-            autoRetrieveAssocations(domainClass, target);
-        }
-
-        if (!shouldValidate) {
-            Set<Integer> identifiers = getDisableAutoValidationFor();
-            identifiers.add(System.identityHashCode(target));
-        }
-
-        if (shouldInsert(arguments)) {
-            return performInsert(target, shouldFlush);
-        }
-
-        return performSave(target, shouldFlush);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private boolean shouldInsert(Object[] arguments) {
-        return arguments.length > 0 && arguments[0] instanceof Map &&
-            GrailsClassUtils.getBooleanFromMap(ARGUMENT_INSERT, (Map) arguments[0]);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private boolean shouldFlush(Object[] arguments) {
-        final boolean shouldFlush;
-        if (arguments.length > 0 && arguments[0] instanceof Boolean) {
-            shouldFlush = (Boolean)arguments[0];
-        }
-        else if (arguments.length > 0 && arguments[0] instanceof Map && ((Map) arguments[0]).containsKey(ARGUMENT_FLUSH)) {
-            shouldFlush = GrailsClassUtils.getBooleanFromMap(ARGUMENT_FLUSH, ((Map) arguments[0]));
-        }
-        else {
-            final Map config = application.getFlatConfig();
-            shouldFlush = Boolean.TRUE == config.get(AUTO_FLUSH_CONFIG_PROPERTY);
-        }
-        return shouldFlush;
-    }
-
-    /**
-     * Performs automatic association retrieval
-     * @param domainClass The domain class to retrieve associations for
-     * @param target The target object
-     */
-    @SuppressWarnings("unchecked")
-    private void autoRetrieveAssocations(GrailsDomainClass domainClass, Object target) {
-        BeanWrapper bean = new BeanWrapperImpl(target);
-        GrailsHibernateTemplate t = getHibernateTemplate();
-        GrailsDomainClassProperty[] props = domainClass.getPersistentProperties();
-        for (int i = 0; i < props.length; i++) {
-            GrailsDomainClassProperty prop = props[i];
-            if (!prop.isManyToOne() && !prop.isOneToOne()) {
-                continue;
-            }
-
-            Object propValue = bean.getPropertyValue(prop.getName());
-            if (propValue == null || t.contains(propValue)) {
-                continue;
-            }
-
-            GrailsDomainClass otherSide = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,
-                    prop.getType().getName());
-            if (otherSide == null) {
-                continue;
-            }
-
-            BeanWrapper propBean = new BeanWrapperImpl(propValue);
-            try {
-                Serializable id = (Serializable)propBean.getPropertyValue(otherSide.getIdentifier().getName());
-                if (id != null) {
-                    final Object propVal = t.get(prop.getType(), id);
-                    if (propVal != null) {
-                        bean.setPropertyValue(prop.getName(), propVal);
-                    }
-                }
-            }
-            catch (InvalidPropertyException ipe) {
-                // property is not accessable
-            }
-        }
-    }
-
-    /**
-     * Sets the flush mode to manual. which ensures that the database changes are not persisted to the database
-     * if a validation error occurs. If save() is called again and validation passes the code will check if there
-     * is a manual flush mode and flush manually if necessary
-     *
-     * @param domainClass The domain class
-     * @param target The target object that failed validation
-     * @param errors The Errors instance  @return This method will return null signaling a validation failure
-     */
-    protected Object handleValidationError(GrailsDomainClass domainClass, final Object target, Errors errors) {
-        // if a validation error occurs set the object to read-only to prevent a flush
-        setObjectToReadOnly(target);
-        if (domainClass instanceof DefaultGrailsDomainClass) {
-            DefaultGrailsDomainClass dgdc = (DefaultGrailsDomainClass) domainClass;
-            List<GrailsDomainClassProperty> associations = dgdc.getAssociations();
-            for (GrailsDomainClassProperty association : associations) {
-                if (association.isOneToOne() || association.isManyToOne()) {
-                    BeanWrapper bean = new BeanWrapperImpl(target);
-                    Object propertyValue = bean.getPropertyValue(association.getName());
-                    if (propertyValue != null) {
-                        setObjectToReadOnly(propertyValue);
-                    }
-                }
-            }
-        }
-        setErrorsOnInstance(target, errors);
-        return null;
-    }
-
-    /**
-     * Associates the Errors object on the instance
-     *
-     * @param target The target instance
-     * @param errors The Errors object
-     */
-    protected void setErrorsOnInstance(Object target, Errors errors) {
-        if (target instanceof GroovyObject) {
-            ((GroovyObject)target).setProperty(ERRORS_PROPERTY,errors);
-        }
-        else {
-            MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass());
-            metaClass.setProperty(target.getClass() ,target, ERRORS_PROPERTY,errors, false, false);
-        }
-    }
-
-    /**
-     * Checks whether validation should be performed
-     * @return true if the domain class should be validated
-     * @param arguments  The arguments to the validate method
-     * @param domainClass The domain class
-     */
-    @SuppressWarnings("rawtypes")
-    private boolean shouldValidate(Object[] arguments, GrailsDomainClass domainClass) {
-        if (domainClass == null) {
-            return false;
-        }
-
-        if (arguments.length == 0) {
-            return true;
-        }
-
-        if (arguments[0] instanceof Boolean) {
-            return (Boolean)arguments[0];
-        }
-
-        if (arguments[0] instanceof Map) {
-            Map argsMap = (Map)arguments[0];
-            if (argsMap.containsKey(ARGUMENT_VALIDATE)) {
-                return GrailsClassUtils.getBooleanFromMap(ARGUMENT_VALIDATE, argsMap);
-            }
-
-            return true;
-        }
-
-        return true;
-    }
-
-    /**
-     * Subclasses should override and perform a save operation, flushing the session if the second argument is true
-     *
-     * @param target The target object to save
-     * @param shouldFlush Whether to flush
-     * @return The target object
-     */
-    protected abstract Object performSave(Object target, boolean shouldFlush);
-
-    /**
-     * Subclasses should override and perform an insert operation, flushing the session if the second argument is true
-     *
-     * @param target The target object to save
-     * @param shouldFlush Whether to flush
-     * @return The target object
-     */
-    protected abstract Object performInsert(Object target, boolean shouldFlush);
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractStaticPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractStaticPersistentMethod.java
deleted file mode 100644
index 58b128c..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractStaticPersistentMethod.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.orm.HibernateCriteriaBuilder;
-import groovy.lang.Closure;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.metaclass.AbstractStaticMethodInvocation;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateSession;
-import org.codehaus.groovy.grails.orm.hibernate.query.HibernateQuery;
-import org.grails.datastore.gorm.finders.DynamicFinder;
-import org.grails.datastore.gorm.finders.FinderMethod;
-import org.grails.datastore.mapping.model.PersistentEntity;
-import org.hibernate.Criteria;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.util.Assert;
-
-/**
- * Abstract base class for static persistent methods.
- *
- * @author Steven Devijver
- * @author Graeme Rocher
- */
-@SuppressWarnings("rawtypes")
-public abstract class AbstractStaticPersistentMethod extends AbstractStaticMethodInvocation implements FinderMethod {
-
-    private ClassLoader classLoader;
-    private GrailsHibernateTemplate hibernateTemplate;
-    private SessionFactory sessionFactory;
-    protected final GrailsApplication application;
-
-    protected AbstractStaticPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, Pattern pattern, GrailsApplication application, int defaultFlushMode) {
-        Assert.notNull(sessionFactory, "Session factory is required!");
-        Assert.notNull(application, "Constructor argument 'application' cannot be null");
-        this.application = application;
-        setPattern(pattern);
-        this.classLoader = classLoader;
-        this.sessionFactory = sessionFactory;
-        hibernateTemplate = new GrailsHibernateTemplate(sessionFactory, application, defaultFlushMode);
-    }
-
-    protected SessionFactory getSessionFactory() {
-        return sessionFactory;
-    }
-
-    protected GrailsHibernateTemplate getHibernateTemplate() {
-        return hibernateTemplate;
-    }
-
-    @Override
-    public Object invoke(Class clazz, String methodName, Object[] arguments) {
-        return invoke(clazz, methodName, (Closure) null, arguments);
-    }
-
-    public Object invoke(Class clazz, String methodName, Closure additionalCriteria, Object[] arguments) {
-        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try {
-            Thread.currentThread().setContextClassLoader(classLoader);
-            return doInvokeInternal(clazz, methodName, additionalCriteria, arguments);
-        }
-        finally {
-            Thread.currentThread().setContextClassLoader(originalClassLoader);
-        }
-    }
-
-    public Object invoke(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try {
-            Thread.currentThread().setContextClassLoader(classLoader);
-            return doInvokeInternal(clazz, methodName, additionalCriteria, arguments);
-        }
-        finally {
-            Thread.currentThread().setContextClassLoader(originalClassLoader);
-        }
-    }
-
-    protected Criteria getCriteria(HibernateDatastore datastore, GrailsApplication appliation, Session session, DetachedCriteria detachedCriteria, Closure additionalCriteria, Class<?> clazz) {
-        if (additionalCriteria != null) {
-            HibernateCriteriaBuilder builder = new HibernateCriteriaBuilder(clazz, session.getSessionFactory());
-            builder.setGrailsApplication(appliation);
-            builder.setConversionService(datastore.getMappingContext().getConversionService());
-            builder.setDefaultFlushMode(datastore.getDefaultFlushMode());
-            return builder.buildCriteria(additionalCriteria);
-        }
-
-        Criteria criteria = session.createCriteria(clazz);
-        if (detachedCriteria != null) {
-            HibernateSession hibernateSession = new HibernateSession(datastore, session.getSessionFactory());
-            PersistentEntity persistentEntity = datastore.getMappingContext().getPersistentEntity(clazz.getName());
-            if (persistentEntity != null) {
-                DynamicFinder.applyDetachedCriteria(new HibernateQuery(criteria, hibernateSession, persistentEntity), detachedCriteria);
-            }
-        }
-        hibernateTemplate.applySettings(criteria);
-        return criteria;
-    }
-
-    protected abstract Object doInvokeInternal(Class clazz, String methodName, Closure additionalCriteria, Object[] arguments);
-
-    protected abstract Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments);
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/CountByPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/CountByPersistentMethod.java
deleted file mode 100644
index e871033..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/CountByPersistentMethod.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Disjunction;
-import org.hibernate.criterion.Projections;
-import org.hibernate.criterion.Restrictions;
-
-/**
- * Dynamic method that allows counting the values of the specified property names
- *
- * eg. Account.countByBranch('London') // returns how many accounts are in london
- *
- * @author Graeme Rocher
- */
-public class CountByPersistentMethod extends AbstractClausedStaticPersistentMethod {
-
-    private static final String OPERATOR_OR = "Or";
-    private static final String OPERATOR_AND = "And";
-
-    private static final Pattern METHOD_PATTERN = Pattern.compile("(countBy)(\\w+)");
-    private static final String[] OPERATORS = { OPERATOR_AND, OPERATOR_OR };
-    private HibernateDatastore datastore;
-
-    public CountByPersistentMethod(HibernateDatastore datastore, GrailsApplication application, SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(application, sessionFactory, classLoader, METHOD_PATTERN, OPERATORS, datastore.getMappingContext().getConversionService(), datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Long doInvokeInternalWithExpressions(final Class clazz, final String methodName, final Object[] arguments,
-            final List expressions, final String operatorInUse, final DetachedCriteria detachedCriteria, final Closure additionalCriteria) {
-
-        return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback<Long>() {
-            public Long doInHibernate(Session session) throws HibernateException, SQLException {
-                final Criteria crit = getCriteria(datastore, application, session, detachedCriteria, additionalCriteria, clazz);
-                crit.setProjection(Projections.rowCount());
-                String operator = OPERATOR_OR.equals(operatorInUse) ? OPERATOR_OR : OPERATOR_AND;
-                Map argsMap = (arguments.length > 1 && (arguments[1] instanceof Map)) ? (Map) arguments[1] : Collections.EMPTY_MAP;
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit,  argsMap, conversionService, false);
-
-                populateCriteriaWithExpressions(crit, operator, expressions);
-                return (Long) crit.uniqueResult();
-            }
-        });
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    protected void populateCriteriaWithExpressions(Criteria crit, String operator, List expressions) {
-        if (operator.equals(OPERATOR_OR)) {
-            Disjunction dis = Restrictions.disjunction();
-            for (GrailsMethodExpression current : (List<GrailsMethodExpression>)expressions) {
-                dis.add(current.getCriterion());
-            }
-            crit.add(dis);
-        }
-        else {
-            for (GrailsMethodExpression current : (List<GrailsMethodExpression>)expressions) {
-                crit.add(current.getCriterion());
-            }
-        }
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteQueryPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteQueryPersistentMethod.java
deleted file mode 100644
index c515746..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteQueryPersistentMethod.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.core.convert.ConversionService;
-
-/**
- * Allows the executing of arbitrary HQL queries.
- * <p/>
- * eg. Account.executeQuery("select distinct a.number from Account a where a.branch = ?", 'London') or
- * Account.executeQuery("select distinct a.number from Account a where a.branch = :branch", [branch:'London'])
- *
- * @author Graeme Rocher
- * @author Sergey Nebolsin
- * @see <a href="http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html">http://www.hibernate.org/hib_docs/reference/en/html/queryhql.html</a>
- * @since 30-Apr-2006
- */
-public class ExecuteQueryPersistentMethod extends AbstractStaticPersistentMethod {
-    private static final String METHOD_SIGNATURE = "executeQuery";
-    private static final Pattern METHOD_PATTERN = Pattern.compile("^executeQuery$");
-
-    private static final List<String> QUERY_META_PARAMS = Arrays.asList(
-            GrailsHibernateUtil.ARGUMENT_MAX,
-            GrailsHibernateUtil.ARGUMENT_OFFSET,
-            GrailsHibernateUtil.ARGUMENT_CACHE,
-            GrailsHibernateUtil.ARGUMENT_FLUSH_MODE,
-            GrailsHibernateUtil.ARGUMENT_TIMEOUT,
-            GrailsHibernateUtil.ARGUMENT_FETCH_SIZE,
-            GrailsHibernateUtil.ARGUMENT_READ_ONLY);
-
-    private final ConversionService conversionService;
-
-    public ExecuteQueryPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, METHOD_PATTERN, application, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, Closure additionalCriteria, Object[] arguments) {
-        checkMethodSignature(clazz, arguments);
-
-        final String query = arguments[0].toString();
-        final Map queryMetaParams = extractQueryMetaParams(arguments);
-        final List positionalParams = extractPositionalParams(arguments);
-        final Map namedParams = extractNamedParams(arguments);
-
-        return getHibernateTemplate().executeFind(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Query q = session.createQuery(query);
-                getHibernateTemplate().applySettings(q);
-                // process paginate params
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_MAX)) {
-                    Integer maxParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_MAX), Integer.class);
-                    q.setMaxResults(maxParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_OFFSET)) {
-                    Integer offsetParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_OFFSET), Integer.class);
-                    q.setFirstResult(offsetParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_CACHE)) {
-                    q.setCacheable((Boolean)queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_CACHE));
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_FETCH_SIZE)) {
-                    Integer fetchSizeParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_FETCH_SIZE), Integer.class);
-                    q.setFetchSize(fetchSizeParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_TIMEOUT)) {
-                    Integer timeoutParam = conversionService.convert(queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_TIMEOUT), Integer.class);
-                    q.setTimeout(timeoutParam.intValue());
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_READ_ONLY)) {
-                    q.setReadOnly((Boolean)queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_READ_ONLY));
-                }
-                if (queryMetaParams.containsKey(GrailsHibernateUtil.ARGUMENT_FLUSH_MODE)) {
-                    q.setFlushMode((FlushMode)queryMetaParams.get(GrailsHibernateUtil.ARGUMENT_FLUSH_MODE));
-                }
-                // process positional HQL params
-                int index = 0;
-                for (Object parameter : positionalParams) {
-                    q.setParameter(index++, parameter instanceof CharSequence ? parameter.toString() : parameter);
-                }
-
-                // process named HQL params
-                for (Object o : namedParams.entrySet()) {
-                    Map.Entry entry = (Map.Entry) o;
-                    if (!(entry.getKey() instanceof String)) {
-                        throw new GrailsQueryException("Named parameter's name must be of type String");
-                    }
-                    String parameterName = (String) entry.getKey();
-                    if (!QUERY_META_PARAMS.contains(parameterName)) {
-                        Object parameterValue = entry.getValue();
-                        if (parameterValue == null) {
-                            throw new IllegalArgumentException("Named parameter [" + entry.getKey() + "] value may not be null");
-                        }
-                        if (Collection.class.isAssignableFrom(parameterValue.getClass())) {
-                            q.setParameterList(parameterName, (Collection) parameterValue);
-                        }
-                        else if (parameterValue.getClass().isArray()) {
-                            q.setParameterList(parameterName, (Object[]) parameterValue);
-                        }
-                        else if (parameterValue instanceof CharSequence) {
-                            q.setParameter(parameterName, parameterValue.toString());
-                        }
-                        else {
-                            q.setParameter(parameterName, parameterValue);
-                        }
-                    }
-                }
-                return q.list();
-            }
-        });
-    }
-
-    @SuppressWarnings("rawtypes")
-    private void checkMethodSignature(Class clazz, Object[] arguments) {
-        boolean valid = true;
-        if (arguments.length < 1) valid = false;
-        else if (arguments.length == 3 && !(arguments[2] instanceof Map)) valid = false;
-        else if (arguments.length > 3) valid = false;
-
-        if (!valid) throw new MissingMethodException(METHOD_SIGNATURE, clazz, arguments);
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private Map extractQueryMetaParams(Object[] arguments) {
-        Map result = new HashMap();
-        int metaParamsIndex = 0;
-        if (arguments.length == 2 && arguments[1] instanceof Map) metaParamsIndex = 1;
-        else if (arguments.length == 3) metaParamsIndex = 2;
-        if (metaParamsIndex > 0) {
-            Map sourceMap = (Map) arguments[metaParamsIndex];
-            for (String queryMetaParam : QUERY_META_PARAMS) {
-                if (sourceMap.containsKey(queryMetaParam)) {
-                    result.put(queryMetaParam, sourceMap.get(queryMetaParam));
-                }
-            }
-        }
-        return result;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private List extractPositionalParams(Object[] arguments) {
-        List result = new ArrayList();
-        if (arguments.length < 2 || arguments[1] instanceof Map) return result;
-        if (arguments[1] instanceof Collection) {
-            result.addAll((Collection) arguments[1]);
-        }
-        else if (arguments[1].getClass().isArray()) {
-            result.addAll(Arrays.asList((Object[]) arguments[1]));
-        }
-        else {
-            result.add(arguments[1]);
-        }
-        return result;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    private Map extractNamedParams(Object[] arguments) {
-        Map result = new HashMap();
-        if (arguments.length < 2 || !(arguments[1] instanceof Map)) return result;
-        result.putAll((Map) arguments[1]);
-        return result;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteUpdatePersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteUpdatePersistentMethod.java
deleted file mode 100644
index d0953a2..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ExecuteUpdatePersistentMethod.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.orm.hibernate4.SessionHolder;
-import org.springframework.transaction.support.TransactionSynchronizationManager;
-
-/**
- * Allows the executing of arbitrary HQL updates.
- * <p/>
- * eg. Account.executeUpdate("delete from Account a where a.branch = ?", 'London') or
- * Account.executeUpdate("delete from Account a where a.branch = :branch", [branch:'London'])
- *
- * @author Burt Beckwith
- */
-@SuppressWarnings({ "unchecked", "rawtypes" })
-public class ExecuteUpdatePersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String METHOD_SIGNATURE = "executeUpdate";
-    private static final Pattern METHOD_PATTERN = Pattern.compile("^executeUpdate$");
-
-    public ExecuteUpdatePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, int defaultFlushMode) {
-        super(sessionFactory, classLoader, METHOD_PATTERN, application, defaultFlushMode);
-    }
-
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @Override
-    protected Object doInvokeInternal(final Class clazz, final String methodName, Closure additionalCriteria, final Object[] arguments) {
-
-        checkMethodSignature(clazz, arguments);
-
-        return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Query q = session.createQuery(arguments[0].toString());
-                getHibernateTemplate().applySettings(q);
-                SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
-                if (sessionHolder != null && sessionHolder.hasTimeout()) {
-                    q.setTimeout(sessionHolder.getTimeToLiveInSeconds());
-                }
-
-                // process positional HQL params
-                int index = 0;
-                for (Object parameter : extractPositionalParams(arguments)) {
-                    q.setParameter(index++, parameter);
-                }
-
-                // process named HQL params
-                for (Map.Entry entry : (Set<Map.Entry>)extractNamedParams(arguments).entrySet()) {
-                    if (!(entry.getKey() instanceof String)) {
-                        throw new GrailsQueryException("Named parameter's name must be of type String");
-                    }
-
-                    String parameterName = (String)entry.getKey();
-                    Object parameterValue = entry.getValue();
-                    if (Collection.class.isAssignableFrom(parameterValue.getClass())) {
-                        q.setParameterList(parameterName, (Collection)parameterValue);
-                    }
-                    else if (parameterValue.getClass().isArray()) {
-                        q.setParameterList(parameterName, (Object[])parameterValue);
-                    }
-                    else if (parameterValue instanceof CharSequence) {
-                        q.setParameter(parameterName, parameterValue.toString());
-                    }
-                    else {
-                        q.setParameter(parameterName, parameterValue);
-                    }
-                }
-                return q.executeUpdate();
-            }
-        });
-    }
-
-    private void checkMethodSignature(Class clazz, Object[] arguments) {
-        boolean valid = true;
-        if (arguments.length == 0 || arguments.length > 2) {
-            valid = false;
-        }
-        else if (arguments.length == 2 && !(arguments[1] instanceof Map || arguments[1] instanceof Collection)) {
-            valid = false;
-        }
-
-        if (!valid) {
-            throw new MissingMethodException(METHOD_SIGNATURE, clazz, arguments);
-        }
-    }
-
-    private List extractPositionalParams(Object[] arguments) {
-        if (arguments.length == 1 || arguments[1] instanceof Map) {
-            return Collections.EMPTY_LIST;
-        }
-
-        List result = new ArrayList();
-        if (arguments[1] instanceof Collection) {
-            result.addAll((Collection)arguments[1]);
-        }
-        else if (arguments[1].getClass().isArray()) {
-            result.addAll(Arrays.asList((Object[])arguments[1]));
-        }
-        else {
-            result.add(arguments[1]);
-        }
-
-        return result;
-    }
-
-    private Map extractNamedParams(Object[] arguments) {
-        if (arguments.length == 1 || !(arguments[1] instanceof Map)) {
-            return Collections.EMPTY_MAP;
-        }
-
-        return (Map)arguments[1];
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByBooleanPropertyPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByBooleanPropertyPersistentMethod.java
deleted file mode 100644
index 985fe1e..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByBooleanPropertyPersistentMethod.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-/**
- * The "findAll<booleanProperty>By*" static persistent method. This method allows querying for
- * instances of grails domain classes based on a boolean property and any other arbitrary
- * properties.
- *
- * eg.
- * Account.findAllActiveByHolder("Joe Blogs"); // Where class "Account" has a properties called "active" and "holder"
- * Account.findAllActiveByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "active', "holder" and "branch"
- *
- * In both of those queries, the query will only select Account objects where active=true.
- *
- * @author Jeff Brown
- */
-public class FindAllByBooleanPropertyPersistentMethod extends FindAllByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findAll)((\\w+)(By)([A-Z]\\w*)|(\\w+))";
-
-    public FindAllByBooleanPropertyPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore, application,sessionFactory, classLoader);
-        setPattern(Pattern.compile(METHOD_PATTERN));
-    }
-
-    @Override
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return true;
-    }
-}
\ No newline at end of file
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByPersistentMethod.java
deleted file mode 100644
index 985667d..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllByPersistentMethod.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Disjunction;
-import org.hibernate.criterion.Restrictions;
-
-/**
- * The "findBy*" static persistent method. This method allows querying for
- * instances of grails domain classes based on their properties. This method returns a list of all found results
- *
- * eg.
- * Account.findAllByHolder("Joe Blogs"); // Where class "Account" has a property called "holder"
- * Account.findAllByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "holder" and "branch"
- *
- * @author Graeme Rocher
- */
-public class FindAllByPersistentMethod extends AbstractClausedStaticPersistentMethod {
-
-    private static final String OPERATOR_OR = "Or";
-    private static final String OPERATOR_AND = "And";
-    private static final String METHOD_PATTERN = "(findAllBy)([A-Z]\\w*)";
-    private static final String[] OPERATORS = { OPERATOR_AND, OPERATOR_OR };
-    private HibernateDatastore datastore;
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     */
-    public FindAllByPersistentMethod(HibernateDatastore datastore,GrailsApplication application, SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(application, sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), OPERATORS, datastore.getMappingContext().getConversionService(), datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternalWithExpressions(final Class clazz, String methodName,
-                                                     final Object[] arguments, final List expressions, String operatorInUse,
-                                                     final DetachedCriteria detachedCriteria, final Closure additionalCriteria) {
-
-        final String operator = OPERATOR_OR.equals(operatorInUse) ? OPERATOR_OR : OPERATOR_AND;
-        return getHibernateTemplate().executeFind(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-
-                final Criteria c = getCriteria(datastore,application, session,detachedCriteria, additionalCriteria, clazz);
-
-                Map argsMap = (arguments.length > 0 && (arguments[0] instanceof Map)) ? (Map) arguments[0] : Collections.EMPTY_MAP;
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, argsMap, conversionService);
-
-                if (operator.equals(OPERATOR_OR)) {
-                    if (firstExpressionIsRequiredBoolean()) {
-                        GrailsMethodExpression expression = (GrailsMethodExpression) expressions.remove(0);
-                        c.add(expression.getCriterion());
-                    }
-
-                    Disjunction dis = Restrictions.disjunction();
-                    int numberOfForceNoResultsCriterion = 0;
-                    for (Object expression : expressions) {
-                        GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                        if (GrailsMethodExpression.FORCE_NO_RESULTS == current.getCriterion()) {
-                            numberOfForceNoResultsCriterion++;
-                        } else {
-                            dis.add(current.getCriterion());
-                        }
-                    }
-                    if (numberOfForceNoResultsCriterion > 0 && numberOfForceNoResultsCriterion == expressions.size()) {
-                        return Collections.EMPTY_LIST;
-                    }
-                    c.add(dis);
-                }
-                else {
-                    for (Object expression : expressions) {
-                        GrailsMethodExpression current = (GrailsMethodExpression) expression;
-                        if (GrailsMethodExpression.FORCE_NO_RESULTS == current.getCriterion()) {
-                            return Collections.emptyList();
-                        }
-                        c.add(current.getCriterion());
-                    }
-                }
-
-                c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                return c.list();
-            }
-        });
-    }
-
-    /**
-     * Indicates if the first expression in the query is a required boolean property and as such should
-     * be ANDed to the other expressions, not ORed.
-     *
-     * @return true if the first expression is a required boolean property, false otherwise
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.FindAllByBooleanPropertyPersistentMethod
-     */
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return false;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllPersistentMethod.java
deleted file mode 100644
index a800315..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindAllPersistentMethod.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.util.GrailsNameUtils;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Example;
-import org.springframework.core.convert.ConversionService;
-
-/**
- * <p>
- * The "findAll" persistent static method allows searching for instances using
- * either an example instance or an HQL query. Max results and offset parameters could
- * be specified. A GrailsQueryException is thrown if the query is not a valid query
- * for the domain class.
- * <p>
- * Syntax:
- *    DomainClass.findAll(query, params?)
- *    DomainClass.findAll(query, params?, max)
- *    DomainClass.findAll(query, params?, max, offset)
- *    DomainClass.findAll(query, params?, [max:10, offset:5])
- *
- * <p>
- * Examples in Groovy: <code>
- *         // retrieves all accounts
- *         def a = Account.findAll()
- *
- *         // retrieve all accounts ordered by account number
- *         def a = Account.findAll("from Account as a order by a.number asc")
- *
- *         // retrieve first 10 accounts ordered by account number
- *         def a = Account.findAll("from Account as a order by a.number asc",10)
- *
- *         // retrieve first 10 accounts ordered by account number started from 5th account
- *         def a = Account.findAll("from Account as a order by a.number asc",10,5)
- *
- *         // retrieve first 10 accounts ordered by account number started from 5th account
- *         def a = Account.findAll("from Account as a order by a.number asc",[max:10,offset:5])
- *
- *         // with query parameters
- *         def a = Account.find("from Account as a where a.number = ? and a.branch = ?", [38479, "London"])
- *
- *         // with query named parameters
- *         def a = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"])
- *
- *         // with query named parameters and max results and offset
- *         def a = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"], 10, 5)
- *
- *         // with query named parameters and max results and offset map
- *         def a = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"], [max:10, offset:5])
- *
- *         // query by example
- *         def a = new Account()
- *         a.number = 495749357
- *         def a = Account.find(a)
- *
- * </code>
- *
- * @author Graeme Rocher
- * @author Steven Devijver
- * @author Sergey Nebolsin
- *
- * @since 0.1
- */
-public class FindAllPersistentMethod extends AbstractStaticPersistentMethod {
-    private final ConversionService conversionService;
-
-    public FindAllPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, Pattern.compile("^findAll$"), application, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName, Closure additionalCriteria, final Object[] arguments) {
-        if (arguments.length == 0) {
-            return getHibernateTemplate().loadAll(clazz);
-        }
-
-        final Object arg = arguments[0] instanceof CharSequence ? arguments[0].toString() : arguments[0];
-
-        // if the arg is an instance of the class find by example
-        if (arg instanceof String) {
-            final String query = ((String) arg).trim();
-            final String shortName = GrailsNameUtils.getShortName(clazz);
-            if (!query.matches("(?i)from(?-i)\\s+[" + clazz.getName() + "|" + shortName + "].*")) {
-                throw new GrailsQueryException("Invalid query [" + query + "] for domain class [" + clazz + "]");
-            }
-
-            return getHibernateTemplate().executeFind(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                    Query q = session.createQuery(query);
-                    getHibernateTemplate().applySettings(q);
-
-                    Object[] queryArgs = null;
-                    Map queryNamedArgs = null;
-                    int max = retrieveMaxValue();
-                    int offset = retrieveOffsetValue();
-                    boolean useCache = useCache();
-                    if (arguments.length > 1) {
-                        if (arguments[1] instanceof Collection) {
-                            queryArgs = GrailsClassUtils.collectionToObjectArray((Collection) arguments[1]);
-                        }
-                        else if (arguments[1].getClass().isArray()) {
-                            queryArgs = (Object[]) arguments[1];
-                        }
-                        else if (arguments[1] instanceof Map) {
-                            queryNamedArgs = (Map) arguments[1];
-                        }
-                    }
-
-                    if (queryArgs != null) {
-                        for (int i = 0; i < queryArgs.length; i++) {
-                            if (queryArgs[i] instanceof CharSequence) {
-                                q.setParameter(i, queryArgs[i].toString());
-                            } else {
-                                q.setParameter(i, queryArgs[i]);
-                            }
-                        }
-                    }
-                    if (queryNamedArgs != null) {
-                        for (Object o : queryNamedArgs.entrySet()) {
-                            Map.Entry entry = (Map.Entry) o;
-                            if (!(entry.getKey() instanceof String)) {
-                                throw new GrailsQueryException("Named parameter's name must be String: " + queryNamedArgs);
-                            }
-                            String stringKey = (String) entry.getKey();
-                            // Won't try to bind these parameters since they are processed separately
-                            if (GrailsHibernateUtil.ARGUMENT_MAX.equals(stringKey) || GrailsHibernateUtil.ARGUMENT_OFFSET.equals(stringKey) || GrailsHibernateUtil.ARGUMENT_CACHE.equals(stringKey))
-                                continue;
-                            Object value = entry.getValue();
-                            if (value == null) {
-                                q.setParameter(stringKey, null);
-                            } else if (value instanceof CharSequence) {
-                                q.setParameter(stringKey, value.toString());
-                            } else if (List.class.isAssignableFrom(value.getClass())) {
-                                q.setParameterList(stringKey, (List) value);
-                            } else if (value.getClass().isArray()) {
-                                q.setParameterList(stringKey, (Object[]) value);
-                            } else {
-                                q.setParameter(stringKey, value);
-                            }
-                        }
-                    }
-                    if (max > 0) {
-                        q.setMaxResults(max);
-                    }
-                    if (offset > 0) {
-                        q.setFirstResult(offset);
-                    }
-                    q.setCacheable(useCache);
-                    return q.list();
-                }
-
-                private boolean useCache() {
-                    boolean useCache = getHibernateTemplate().isCacheQueries();
-                    if (arguments.length > 1 && arguments[arguments.length - 1] instanceof Map) {
-                        useCache = retrieveBoolean(arguments[arguments.length - 1], GrailsHibernateUtil.ARGUMENT_CACHE);
-                    }
-                    return useCache;
-                }
-
-                private int retrieveMaxValue() {
-                    int result = -1;
-                    if (arguments.length > 1) {
-                        result = retrieveInt(arguments[1], GrailsHibernateUtil.ARGUMENT_MAX);
-                        if (arguments.length > 2 && result == -1) {
-                            result = retrieveInt(arguments[2], GrailsHibernateUtil.ARGUMENT_MAX);
-                        }
-                    }
-                    return result;
-                }
-
-                private int retrieveOffsetValue() {
-                    int result = -1;
-                    if (arguments.length > 1) {
-                        if (isMapWithValue(arguments[1], GrailsHibernateUtil.ARGUMENT_OFFSET)) {
-                            result = ((Number)((Map)arguments[1]).get(GrailsHibernateUtil.ARGUMENT_OFFSET)).intValue();
-                        }
-                        if (arguments.length > 2 && result == -1) {
-                            if (isMapWithValue(arguments[2], GrailsHibernateUtil.ARGUMENT_OFFSET)) {
-                                result = retrieveInt(arguments[2], GrailsHibernateUtil.ARGUMENT_OFFSET);
-                            }
-                            else if (isIntegerOrLong(arguments[1]) && isIntegerOrLong(arguments[2])) {
-                                result = ((Number)arguments[2]).intValue();
-                            }
-                        }
-                        if (arguments.length > 3 && result == -1) {
-                            if (isIntegerOrLong(arguments[3])) {
-                                result = ((Number)arguments[3]).intValue();
-                            }
-                        }
-                    }
-                    return result;
-                }
-
-                private boolean retrieveBoolean(Object param, String key) {
-                    boolean value = false;
-                    if (isMapWithValue(param, key)) {
-                        value = conversionService.convert(((Map)param).get(key), Boolean.class);
-                    }
-                    return value;
-                }
-
-                private int retrieveInt(Object param, String key) {
-                    if (isMapWithValue(param, key)) {
-                        return conversionService.convert(((Map) param).get(key),Integer.class);
-                    }
-                    if (isIntegerOrLong(param)) {
-                        return ((Number)param).intValue();
-                    }
-                    return -1;
-                }
-
-                private boolean isIntegerOrLong(Object param) {
-                    return (param instanceof Integer) || (param instanceof Long);
-                }
-
-                private boolean isMapWithValue(Object param, String key) {
-                    return (param instanceof Map) && ((Map)param).containsKey(key);
-                }
-            });
-        }
-
-        if (clazz.isAssignableFrom(arg.getClass())) {
-            return getHibernateTemplate().executeFind(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-
-                    Example example = Example.create(arg).ignoreCase();
-
-                    Criteria crit = session.createCriteria(clazz);
-                    getHibernateTemplate().applySettings(crit);
-                    crit.add(example);
-
-                    Map argsMap = (arguments.length > 1 && (arguments[1] instanceof Map)) ? (Map) arguments[1] : Collections.EMPTY_MAP;
-                    GrailsHibernateUtil.populateArgumentsForCriteria(application,clazz, crit, argsMap, conversionService);
-                    return crit.list();
-                }
-            });
-        }
-
-        if (arguments[0] instanceof Map) {
-            return getHibernateTemplate().executeFind(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                    Criteria crit = session.createCriteria(clazz);
-                    getHibernateTemplate().applySettings(crit);
-                    GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit, (Map)arguments[0], conversionService);
-                    return crit.list();
-                }
-            });
-        }
-
-        throw new MissingMethodException(methodName, clazz, arguments);
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByBooleanPropertyPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByBooleanPropertyPersistentMethod.java
deleted file mode 100644
index c0ee00c..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByBooleanPropertyPersistentMethod.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/* 
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-/**
- * The "find<booleanProperty>By*" static persistent method. This method allows querying for
- * instances of grails domain classes based on a boolean property and any other arbitrary
- * properties. This method returns the first result of the query.
- *
- * eg.
- * Account.findActiveByHolder("Joe Blogs"); // Where class "Account" has a properties called "active" and "holder"
- * Account.findActiveByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "active', "holder" and "branch"
- *
- * In both of those queries, the query will only select Account objects where active=true.
- *
- * @author Jeff Brown
- */
-public class FindByBooleanPropertyPersistentMethod extends FindByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(find)((\\w+)(By)([A-Z]\\w*)|(\\w++))";
-
-    public FindByBooleanPropertyPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore, application,sessionFactory, classLoader);
-        setPattern(Pattern.compile(METHOD_PATTERN));
-    }
-
-    @Override
-    protected boolean firstExpressionIsRequiredBoolean() {
-        return true;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByPersistentMethod.java
deleted file mode 100644
index b2c5a95..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindByPersistentMethod.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/* 
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-/**
- * The "findBy*" static persistent method. This method allows querying for
- * instances of grails domain classes based on their properties. This method returns the first result of the query
- *
- * eg.
- * Account.findByHolder("Joe Blogs"); // Where class "Account" has a property called "holder"
- * Account.findByHolderAndBranch("Joe Blogs", "London"); // Where class "Account" has a properties called "holder" and "branch"
- *
- * @author Graeme Rocher
- * @since 31-Aug-2005
- */
-public class FindByPersistentMethod extends AbstractFindByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findBy)([A-Z]\\w*)";
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     */
-    public FindByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore,application,sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), OPERATORS);
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrCreateByPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrCreateByPersistentMethod.java
deleted file mode 100644
index 0065135..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrCreateByPersistentMethod.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/* 
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-import groovy.lang.MissingMethodException;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-@SuppressWarnings("rawtypes")
-public class FindOrCreateByPersistentMethod extends AbstractFindByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findOrCreateBy)([A-Z]\\w*)";
-
-    public FindOrCreateByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        this(datastore, application,sessionFactory, classLoader, METHOD_PATTERN);
-    }
-
-    public FindOrCreateByPersistentMethod(HibernateDatastore datastore, GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader, String pattern) {
-        super(datastore, application,sessionFactory, classLoader, Pattern.compile(pattern), OPERATORS);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    protected Object doInvokeInternalWithExpressions(Class clazz,
-                                                     String methodName, Object[] arguments, List expressions,
-                                                     String operatorInUse, DetachedCriteria detachedCriteria, Closure additionalCriteria) {
-        boolean isValidMethod = true;
-
-        if (OPERATOR_OR.equals(operatorInUse)) {
-            isValidMethod = false;
-        }
-
-        Iterator iterator = expressions.iterator();
-        while (isValidMethod && iterator.hasNext()) {
-            GrailsMethodExpression gme = (GrailsMethodExpression) iterator.next();
-            isValidMethod = GrailsMethodExpression.EQUAL.equals(gme.type);
-        }
-
-        if (!isValidMethod) {
-            throw new MissingMethodException(methodName, clazz, arguments);
-        }
-        Object result = super.doInvokeInternalWithExpressions(clazz, methodName, arguments,
-                expressions, operatorInUse, detachedCriteria, additionalCriteria);
-
-        if (result == null) {
-            Map m = new HashMap();
-            for (Object o : expressions) {
-                GrailsMethodExpression gme = (GrailsMethodExpression) o;
-                m.put(gme.getPropertyName(), gme.getArguments()[0]);
-            }
-            MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(clazz);
-            result = metaClass.invokeConstructor(new Object[]{m});
-            if (shouldSaveOnCreate()) {
-                metaClass.invokeMethod(result, "save", null);
-            }
-        }
-
-        return result;
-    }
-
-    protected boolean shouldSaveOnCreate() {
-        return false;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrSaveByPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrSaveByPersistentMethod.java
deleted file mode 100644
index c1dad7d..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindOrSaveByPersistentMethod.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/* 
- * Copyright 2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.SessionFactory;
-
-public class FindOrSaveByPersistentMethod extends FindOrCreateByPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(findOrSaveBy)([A-Z]\\w*)";
-
-    /**
-     * Constructor.
-     * @param application
-     * @param sessionFactory
-     * @param classLoader
-     */
-    public FindOrSaveByPersistentMethod(HibernateDatastore datastore,GrailsApplication application,SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(datastore, application,sessionFactory, classLoader, METHOD_PATTERN);
-    }
-
-    @Override
-    protected boolean shouldSaveOnCreate() {
-        return true;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindPersistentMethod.java
deleted file mode 100644
index 85e84df..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/FindPersistentMethod.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/* 
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.util.GrailsNameUtils;
-import groovy.lang.Closure;
-import groovy.lang.MissingMethodException;
-
-import java.sql.SQLException;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Query;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Example;
-import org.springframework.core.convert.ConversionService;
-
-/**
- * <p>
- * The "find" persistent static method allows searching for instances using
- * either an example instance or an HQL query. This method returns the first
- * result of the query. A GrailsQueryException is thrown if the query is not a
- * valid query for the domain class.
- *
- * <p>
- * Examples in Groovy: <code>
- *         // retrieve the first account ordered by account number
- *         def a = Account.find("from Account as a order by a.number asc")
- *
- *         // with query parameters
- *         def a  = Account.find("from Account as a where a.number = ? and a.branch = ?", [38479, "London"])
- *
- *         // with query named parameters
- *         def a  = Account.find("from Account as a where a.number = :number and a.branch = :branch", [number:38479, branch:"London"])
-
- *         // query by example
- *         def a = new Account()
- *         a.number = 495749357
- *         def a = Account.find(a)
- *
- * </code>
- *
- * @author Graeme Rocher
- * @author Sergey Nebolsin
- */
-public class FindPersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String    METHOD_PATTERN    = "^find$";
-    private final ConversionService conversionService;
-
-    public FindPersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), application, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName, Closure additionalCriteria, final Object[] arguments) {
-
-        if (arguments.length == 0) {
-            throw new MissingMethodException(methodName, clazz, arguments);
-        }
-
-        final Object arg = arguments[0] instanceof CharSequence ? arguments[0].toString() : arguments[0];
-
-        if (arg instanceof String) {
-            final String query = (String) arg;
-            final String shortName = GrailsNameUtils.getShortName(clazz);
-            if (!query.matches("(?i)from(?-i)\\s+[" + clazz.getName() + "|" + shortName    + "].*")) {
-                throw new GrailsQueryException("Invalid query [" + query + "] for domain class [" + clazz + "]");
-            }
-
-            return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                    Query q = session.createQuery(query);
-                    getHibernateTemplate().applySettings(q);
-                    Object[] queryArgs = null;
-                    Map queryNamedArgs = null;
-                    boolean useCache = useCache(arguments);
-
-                    if (arguments.length > 1) {
-                        if (arguments[1] instanceof Collection) {
-                            queryArgs = GrailsClassUtils.collectionToObjectArray((Collection) arguments[1]);
-                        }
-                        else if (arguments[1].getClass().isArray()) {
-                            queryArgs = (Object[]) arguments[1];
-                        }
-                        else if (arguments[1] instanceof Map) {
-                            queryNamedArgs = (Map) arguments[1];
-                        }
-                    }
-                    if (queryArgs != null) {
-                        for (int i = 0; i < queryArgs.length; i++) {
-                            if (queryArgs[i] instanceof CharSequence) {
-                                q.setParameter(i, queryArgs[i].toString());
-                            }
-                            else {
-                                q.setParameter(i, queryArgs[i]);
-                            }
-                        }
-                    }
-                    if (queryNamedArgs != null) {
-                        for (Iterator it = queryNamedArgs.entrySet().iterator(); it.hasNext();) {
-                            Map.Entry entry = (Map.Entry) it.next();
-                            if (!(entry.getKey() instanceof String)) {
-                                throw new GrailsQueryException("Named parameter's name must be String: " +
-                                        queryNamedArgs.toString());
-                            }
-                            String stringKey = (String) entry.getKey();
-                            Object value = entry.getValue();
-
-                            if (GrailsHibernateUtil.ARGUMENT_CACHE.equals(stringKey)) {
-                                continue;
-                            }
-                            else if (value instanceof CharSequence) {
-                                q.setParameter(stringKey, value.toString());
-                            }
-                            else if (List.class.isAssignableFrom(value.getClass())) {
-                                q.setParameterList(stringKey, (List) value);
-                            }
-                            else if (value.getClass().isArray()) {
-                                q.setParameterList(stringKey, (Object[]) value);
-                            }
-                            else {
-                                q.setParameter(stringKey, value);
-                            }
-                        }
-                    }
-                    // only want one result, could have used uniqueObject here
-                    // but it throws an exception if its not unique which is undesirable
-                    q.setMaxResults(1);
-                    q.setCacheable(useCache);
-                    List results = q.list();
-                    if (results.size() > 0) {
-                        return GrailsHibernateUtil.unwrapIfProxy(results.get(0));
-                    }
-                    return null;
-                }
-
-                private boolean useCache(Object[] args) {
-                    boolean useCache = getHibernateTemplate().isCacheQueries();
-                    if (args.length > 1 && args[args.length - 1] instanceof Map) {
-                        Object param = args[args.length - 1];
-                        String key = GrailsHibernateUtil.ARGUMENT_CACHE;
-                        boolean value = false;
-                        if ((param instanceof Map) && ((Map)param).containsKey(key)) {
-                            value = conversionService.convert(((Map)param).get(key), Boolean.class);
-                        }
-                        useCache = value;
-                    }
-                    return useCache;
-                }
-            });
-        }
-        else if (clazz.isAssignableFrom(arg.getClass())) {
-            // if the arg is an instance of the class find by example
-            return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-                public Object doInHibernate(Session session) throws HibernateException, SQLException {
-
-                    Example example = Example.create(arg).ignoreCase();
-
-                    Criteria crit = session.createCriteria(clazz);
-                    getHibernateTemplate().applySettings(crit);
-                    crit.add(example);
-                    crit.setMaxResults(1);
-                    List results = crit.list();
-                    if (results.size() > 0) {
-                        return results.get(0);
-                    }
-                    return null;
-                }
-            });
-        }
-
-        throw new MissingMethodException(methodName, clazz, arguments);
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListOrderByPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListOrderByPersistentMethod.java
deleted file mode 100644
index 1f98f9c..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListOrderByPersistentMethod.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/* 
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Locale;
-import java.util.Map;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.hibernate.criterion.Order;
-
-/**
- * The "listOrderBy*" static persistent method. Allows ordered listing of instances based on their properties.
- *
- * eg.
- * Account.listOrderByHolder();
- * Account.listOrderByHolder(max); // max results
- *
- * @author Graeme
- */
-public class ListOrderByPersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String METHOD_PATTERN = "(listOrderBy)(\\w+)";
-    private final HibernateDatastore datastore;
-
-    public ListOrderByPersistentMethod(HibernateDatastore datastore, GrailsApplication grailsApplication, SessionFactory sessionFactory, ClassLoader classLoader) {
-        super(sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), grailsApplication, datastore.getDefaultFlushMode());
-        this.datastore = datastore;
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractStaticPersistentMethod#doInvokeInternal(java.lang.Class, java.lang.String, java.lang.Object[])
-     */
-    @SuppressWarnings({ "unchecked", "rawtypes" })
-    @Override
-    protected Object doInvokeInternal(final Class clazz, String methodName, final Closure additionalCriteria, final Object[] arguments) {
-
-        Matcher match = getPattern().matcher(methodName);
-        match.find();
-
-        String nameInSignature = match.group(2);
-        final String propertyName = nameInSignature.substring(0,1).toLowerCase(Locale.ENGLISH) + nameInSignature.substring(1);
-
-        return getHibernateTemplate().executeFind(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Criteria crit = getCriteria(datastore, application, session, null, additionalCriteria, clazz);
-
-                if (arguments != null && arguments.length > 0) {
-                    if (arguments[0] instanceof Map) {
-                        Map argMap = (Map)arguments[0];
-                        argMap.put(GrailsHibernateUtil.ARGUMENT_SORT,propertyName);
-                        GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, crit, argMap, datastore.getMappingContext().getConversionService());
-                    }
-                    else {
-                        crit.addOrder(Order.asc(propertyName));
-                    }
-                }
-                else {
-                    crit.addOrder(Order.asc(propertyName));
-                }
-                crit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                return crit.list();
-            }
-        });
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListPersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListPersistentMethod.java
deleted file mode 100644
index 10eec0d..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ListPersistentMethod.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/* 
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.gorm.DetachedCriteria;
-import grails.orm.PagedResultList;
-import groovy.lang.Closure;
-
-import java.sql.SQLException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.hibernate.Criteria;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-import org.springframework.core.convert.ConversionService;
-
-/**
- * The "list" persistent static method. This method lists of of the persistent
- * instances up the maximum specified amount (if any)
- *
- * eg.
- * Account.list(); // list all
- * Account.list(max:10,offset:50,sort:"holder",order:"desc"); // list up to 10, offset by 50, sorted by holder and in descending order
- *
- * @author Graeme Rocher
- */
-public class ListPersistentMethod extends AbstractStaticPersistentMethod {
-
-    private static final String METHOD_PATTERN = "^list$";
-    private final ConversionService conversionService;
-
-    public ListPersistentMethod(GrailsApplication grailsApplication, SessionFactory sessionFactory, ClassLoader classLoader, ConversionService conversionService, int defaultFlushMode) {
-        super(sessionFactory, classLoader, Pattern.compile(METHOD_PATTERN), grailsApplication, defaultFlushMode);
-        this.conversionService = conversionService;
-    }
-
-    @Override
-    @SuppressWarnings("rawtypes")
-    protected Object doInvokeInternal(final Class clazz, String methodName, Closure additionalCriteria, final Object[] arguments) {
-        // and list up to the max
-        return getHibernateTemplate().executeFind(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Criteria c =  session.createCriteria(clazz);
-                getHibernateTemplate().applySettings(c);
-                if (arguments.length > 0 && arguments[0] instanceof Map) {
-                    Map argMap = (Map)arguments[0];
-                    if (argMap.containsKey(GrailsHibernateUtil.ARGUMENT_MAX)) {
-                        c.setMaxResults(Integer.MAX_VALUE);
-                        GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, argMap, conversionService);
-                        c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                        return new PagedResultList(getHibernateTemplate(), c);
-                    }
-
-                    GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, argMap, conversionService);
-                    c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                    return c.list();
-                }
-
-                GrailsHibernateUtil.populateArgumentsForCriteria(application, clazz, c, Collections.EMPTY_MAP, conversionService);
-                c.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
-                return c.list();
-            }
-        });
-    }
-
-    @SuppressWarnings("rawtypes")
-    @Override
-    protected Object doInvokeInternal(Class clazz, String methodName, DetachedCriteria additionalCriteria, Object[] arguments) {
-        return doInvokeInternal(clazz,methodName, (Closure) null,arguments) ;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/MergePersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/MergePersistentMethod.java
deleted file mode 100644
index 4b31312..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/MergePersistentMethod.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.sql.SQLException;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.hibernate.HibernateException;
-import org.hibernate.LockMode;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-
-/**
- * The merge() method follows the semantics of merge which attempts to "merge" an object
- * with a long lived session.
- *
- * @author Graeme Rocher
- * @since 0.3
- */
-public class MergePersistentMethod extends AbstractSavePersistentMethod {
-
-    public static final String METHOD_SIGNATURE = "merge";
-    public static final Pattern METHOD_PATTERN = Pattern.compile('^'+METHOD_SIGNATURE+'$');
-
-    public MergePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-               GrailsApplication application, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, datastore);
-    }
-
-    public MergePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-               GrailsApplication application, GrailsDomainClass dc, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, dc, datastore);
-    }
-
-    /* (non-Javadoc)
-     * @see org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod#performSave(java.lang.Object)
-     */
-    @Override
-    protected Object performSave(final Object target, final boolean flush) {
-        return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                Object merged = session.merge(target);
-                session.lock(merged, LockMode.NONE);
-
-                if (flush) {
-                    session.flush();
-                }
-                return merged;
-            }
-        });
-    }
-
-    @Override
-    protected Object performInsert(Object target, boolean shouldFlush) {
-        throw new IllegalArgumentException("The [insert] argument is not supported by the [merge] method");
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/SavePersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/SavePersistentMethod.java
deleted file mode 100644
index c05b0ed..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/SavePersistentMethod.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import java.sql.SQLException;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor;
-import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
-import org.hibernate.Session;
-import org.hibernate.SessionFactory;
-
-/**
- * Follows the semantics of saveOrUpdate of scheduling the object for persistence when a flush occurs.
- *
- * @author Steven Devijver
- * @author Graeme Rocher
- *
- * @since 0.1
- */
-public class SavePersistentMethod extends AbstractSavePersistentMethod {
-
-    public static final String METHOD_SIGNATURE = "save";
-    public static final Pattern METHOD_PATTERN = Pattern.compile('^'+METHOD_SIGNATURE+'$');
-
-    public SavePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-              GrailsApplication application, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, datastore);
-    }
-
-    public SavePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-              GrailsApplication application, GrailsDomainClass domainClass, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, domainClass, datastore);
-    }
-
-    @Override
-    protected Object performSave(final Object target, final boolean flush) {
-        return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                session.saveOrUpdate(target);
-                if (flush) {
-                    flushSession(session);
-                }
-                return target;
-            }
-        });
-    }
-
-    @Override
-    protected Object performInsert(final Object target, final boolean shouldFlush) {
-        return getHibernateTemplate().execute(new GrailsHibernateTemplate.HibernateCallback<Object>() {
-            public Object doInHibernate(Session session) throws HibernateException, SQLException {
-                try {
-                    ClosureEventTriggeringInterceptor.markInsertActive();
-                    session.save(target);
-                    if (shouldFlush) {
-                        flushSession(session);
-                    }
-                    return target;
-                } finally {
-                    ClosureEventTriggeringInterceptor.resetInsertActive();
-                }
-            }
-        });
-    }
-
-    protected void flushSession(Session session) throws HibernateException {
-        try {
-            session.flush();
-        } catch (HibernateException e) {
-            // session should not be flushed again after a data acccess exception!
-            session.setFlushMode(FlushMode.MANUAL);
-            throw e;
-        }
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ValidatePersistentMethod.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ValidatePersistentMethod.java
deleted file mode 100644
index 8819ce1..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/ValidatePersistentMethod.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/* 
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.metaclass;
-
-import grails.validation.ValidationErrors;
-import groovy.lang.GroovySystem;
-import groovy.lang.MetaClass;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.regex.Pattern;
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
-import org.codehaus.groovy.grails.orm.hibernate.validation.AbstractPersistentConstraint;
-import org.codehaus.groovy.grails.validation.CascadingValidator;
-import org.grails.datastore.mapping.engine.event.ValidationEvent;
-import org.hibernate.SessionFactory;
-import org.springframework.util.Assert;
-import org.springframework.validation.Errors;
-import org.springframework.validation.FieldError;
-import org.springframework.validation.ObjectError;
-import org.springframework.validation.Validator;
-
-/**
- * Validates an instance of a domain class against its constraints.
- *
- * @author Graeme Rocher
- * @since 07-Nov-2005
- */
-public class ValidatePersistentMethod extends AbstractDynamicPersistentMethod {
-
-    public static final String METHOD_SIGNATURE = "validate";
-    public static final Pattern METHOD_PATTERN = Pattern.compile('^'+METHOD_SIGNATURE+'$');
-    public static final String ARGUMENT_DEEP_VALIDATE = "deepValidate";
-    private static final String ARGUMENT_EVICT = "evict";
-    private Validator validator;
-    private HibernateDatastore datastore;
-
-    public ValidatePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader, GrailsApplication application) {
-        this(sessionFactory, classLoader, application, null, null);
-    }
-
-    public ValidatePersistentMethod(SessionFactory sessionFactory, ClassLoader classLoader,
-             GrailsApplication application, Validator validator, HibernateDatastore datastore) {
-        super(METHOD_PATTERN, sessionFactory, classLoader, application, datastore.getDefaultFlushMode());
-        Assert.notNull(application, "Constructor argument 'application' cannot be null");
-        this.validator = validator;
-        this.datastore = datastore;
-    }
-
-    @Override
-    @SuppressWarnings({"unchecked","rawtypes"})
-    protected Object doInvokeInternal(final Object target, Object[] arguments) {
-        Errors errors = setupErrorsProperty(target);
-
-        GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,
-                target.getClass().getName());
-
-        if (validator == null && domainClass != null) {
-            validator = domainClass.getValidator();
-        }
-
-        if (validator == null) {
-            return true;
-        }
-
-        Boolean valid = Boolean.TRUE;
-        // should evict?
-        boolean evict = false;
-        boolean deepValidate = true;
-        Set validatedFields = null;
-        List validatedFieldsList = null;
-
-        if (arguments.length > 0) {
-            if (arguments[0] instanceof Boolean) {
-                evict = (Boolean)arguments[0];
-            }
-            if (arguments[0] instanceof Map) {
-                Map argsMap = (Map)arguments[0];
-
-                if (argsMap.containsKey(ARGUMENT_DEEP_VALIDATE)) {
-                    deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, argsMap);
-                }
-
-                evict = GrailsClassUtils.getBooleanFromMap(ARGUMENT_EVICT, argsMap);
-            }
-            if (arguments[0] instanceof List) {
-                validatedFieldsList = (List)arguments[0];
-                validatedFields = new HashSet(validatedFieldsList);
-            }
-        }
-
-        fireEvent(target, validatedFieldsList);
-
-        AbstractPersistentConstraint.sessionFactory.set(datastore.getSessionFactory());
-        try {
-            if (deepValidate && (validator instanceof CascadingValidator)) {
-                ((CascadingValidator)validator).validate(target, errors, deepValidate);
-            }
-            else {
-                validator.validate(target,errors);
-            }
-        }
-        finally {
-            AbstractPersistentConstraint.sessionFactory.remove();
-        }
-
-        int oldErrorCount = errors.getErrorCount();
-        errors = filterErrors(errors, validatedFields, target);
-
-        if (errors.hasErrors()) {
-            valid = Boolean.FALSE;
-            if (evict) {
-                // if an boolean argument 'true' is passed to the method
-                // and validation fails then the object will be evicted
-                // from the session, ensuring it is not saved later when
-                // flush is called
-                if (getHibernateTemplate().contains(target)) {
-                    getHibernateTemplate().evict(target);
-                }
-            }
-        }
-
-        // If the errors have been filtered, update the 'errors' object attached to the target.
-        if (errors.getErrorCount() != oldErrorCount) {
-            MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(target.getClass());
-            metaClass.setProperty(target, ERRORS_PROPERTY, errors);
-        }
-
-        return valid;
-    }
-
-    private void fireEvent(Object target, List<?> validatedFieldsList) {
-        ValidationEvent event = new ValidationEvent(datastore, target);
-        event.setValidatedFields(validatedFieldsList);
-        datastore.getApplicationContext().publishEvent(event);
-    }
-
-    @SuppressWarnings("rawtypes")
-    private Errors filterErrors(Errors errors, Set validatedFields, Object target) {
-        if (validatedFields == null) return errors;
-
-        ValidationErrors result = new ValidationErrors(target);
-
-        final List allErrors = errors.getAllErrors();
-        for (Object allError : allErrors) {
-            ObjectError error = (ObjectError) allError;
-
-            if (error instanceof FieldError) {
-                FieldError fieldError = (FieldError) error;
-                if (!validatedFields.contains(fieldError.getField())) continue;
-            }
-
-            result.addError(error);
-        }
-
-        return result;
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwarePojoEntityTuplizer.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwarePojoEntityTuplizer.java
new file mode 100644
index 0000000..0ac02b2
--- /dev/null
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/GroovyAwarePojoEntityTuplizer.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2014 original authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.grails.orm.hibernate.proxy;
+
+import org.hibernate.mapping.PersistentClass;
+import org.hibernate.metamodel.binding.EntityBinding;
+import org.hibernate.property.Getter;
+import org.hibernate.property.Setter;
+import org.hibernate.proxy.ProxyFactory;
+import org.hibernate.tuple.entity.EntityMetamodel;
+import org.hibernate.tuple.entity.PojoEntityTuplizer;
+
+/**
+ * Ensures a Groovy aware proxy factory is registered
+ *
+ * @author Graeme Rocher
+ * @since 4.0
+ */
+public class GroovyAwarePojoEntityTuplizer extends PojoEntityTuplizer {
+
+    public GroovyAwarePojoEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappedEntity) {
+        super(entityMetamodel, mappedEntity);
+    }
+    public GroovyAwarePojoEntityTuplizer(EntityMetamodel entityMetamodel, EntityBinding mappedEntity) {
+        super(entityMetamodel, mappedEntity);
+    }
+
+    @Override
+    protected ProxyFactory buildProxyFactoryInternal(PersistentClass persistentClass, Getter idGetter, Setter idSetter) {
+        return new GroovyAwareJavassistProxyFactory();
+    }
+
+    @Override
+    protected ProxyFactory buildProxyFactoryInternal(EntityBinding entityBinding, Getter idGetter, Setter idSetter) {
+        return new GroovyAwareJavassistProxyFactory();
+    }
+}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java
index a00deec..822baaa 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/proxy/HibernateProxyHandler.java
@@ -15,17 +15,9 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.proxy;
 
-import java.lang.reflect.InvocationTargetException;
 
-import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.support.proxy.EntityProxyHandler;
-import org.grails.datastore.mapping.reflect.ClassPropertyFetcher;
-import org.hibernate.Hibernate;
 import org.hibernate.collection.internal.AbstractPersistentCollection;
 import org.hibernate.collection.spi.PersistentCollection;
-import org.hibernate.proxy.HibernateProxy;
-import org.hibernate.proxy.HibernateProxyHelper;
-import org.hibernate.proxy.LazyInitializer;
 
 /**
  * Implementation of the ProxyHandler interface for Hibernate.
@@ -33,96 +25,36 @@
  * @author Graeme Rocher
  * @since 1.2.2
  */
-public class HibernateProxyHandler implements EntityProxyHandler {
+public class HibernateProxyHandler extends SimpleHibernateProxyHandler {
 
     public boolean isInitialized(Object o) {
-        if (o instanceof HibernateProxy) {
-            return !((HibernateProxy)o).getHibernateLazyInitializer().isUninitialized();
-        }
-
         if (o instanceof PersistentCollection) {
             return ((PersistentCollection)o).wasInitialized();
         }
 
-        return true;
-    }
-
-    public boolean isInitialized(Object obj, String associationName) {
-        try {
-            Object proxy = ClassPropertyFetcher.forClass(obj.getClass()).getPropertyValue(obj, associationName);
-            return Hibernate.isInitialized(proxy);
-        }
-        catch (RuntimeException e) {
-            return false;
-        }
+        return super.isInitialized(o);
     }
 
     public Object unwrapIfProxy(Object instance) {
-        if (instance instanceof HibernateProxy) {
-            final HibernateProxy proxy = (HibernateProxy)instance;
-            return unwrapProxy(proxy);
-        }
-
         if (instance instanceof AbstractPersistentCollection) {
             initialize(instance);
             return instance;
         }
 
-        return instance;
-    }
-
-    public Object unwrapProxy(final HibernateProxy proxy) {
-        final LazyInitializer lazyInitializer = proxy.getHibernateLazyInitializer();
-        if (lazyInitializer.isUninitialized()) {
-            lazyInitializer.initialize();
-        }
-        final Object obj = lazyInitializer.getImplementation();
-        if (obj != null) {
-            GrailsHibernateUtil.ensureCorrectGroovyMetaClass(obj,obj.getClass());
-        }
-        return obj;
-    }
-
-    public HibernateProxy getAssociationProxy(Object obj, String associationName) {
-        try {
-            Object proxy = ClassPropertyFetcher.forClass(obj.getClass()).getPropertyValue(obj, associationName);
-            if (proxy instanceof HibernateProxy) {
-                return (HibernateProxy) proxy;
-            }
-            return null;
-        }
-        catch (RuntimeException e) {
-            return null;
-        }
+        return super.unwrapIfProxy(instance);
     }
 
     public boolean isProxy(Object o) {
-        return (o instanceof HibernateProxy) || (o instanceof AbstractPersistentCollection);
+        return super.isProxy(o) || (o instanceof AbstractPersistentCollection);
     }
 
     public void initialize(Object o) {
-        if (o instanceof HibernateProxy) {
-            final LazyInitializer hibernateLazyInitializer = ((HibernateProxy)o).getHibernateLazyInitializer();
-            if (hibernateLazyInitializer.isUninitialized()) {
-                hibernateLazyInitializer.initialize();
-            }
-        }
-        else if (o instanceof AbstractPersistentCollection) {
+        if (o instanceof AbstractPersistentCollection) {
             final AbstractPersistentCollection col = (AbstractPersistentCollection)o;
             if (!col.wasInitialized()) {
                 col.forceInitialization();
             }
         }
-    }
-
-    public Object getProxyIdentifier(Object o) {
-        if (o instanceof HibernateProxy) {
-            return ((HibernateProxy)o).getHibernateLazyInitializer().getIdentifier();
-        }
-        return null;
-    }
-
-    public Class<?> getProxiedClass(Object o) {
-        return HibernateProxyHelper.getClassWithoutInitializingProxy(o);
+        super.initialize(o);
     }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java
index ab28980..f296584 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventListener.java
@@ -28,11 +28,11 @@
 import org.apache.commons.logging.LogFactory;
 import org.codehaus.groovy.grails.commons.GrailsClassUtils;
 import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormValidationApi;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.Mapping;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractDynamicPersistentMethod;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.ValidatePersistentMethod;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
 import org.grails.datastore.gorm.support.BeforeValidateHelper.BeforeValidateEventTriggerCaller;
 import org.grails.datastore.gorm.support.EventTriggerCaller;
@@ -90,7 +90,7 @@
     Map validateParams;
     MetaMethod validateMethod;
     TimestampProvider timestampProvider;
-    
+
     public ClosureEventListener(Class<?> domainClazz, boolean failOnError, List failOnErrorPackages) {
         this(domainClazz, failOnError, failOnErrorPackages, new DefaultTimestampProvider());
     }
@@ -122,11 +122,11 @@
         }
 
         validateParams = new HashMap();
-        validateParams.put(ValidatePersistentMethod.ARGUMENT_DEEP_VALIDATE, Boolean.FALSE);
+        validateParams.put(AbstractHibernateGormValidationApi.ARGUMENT_DEEP_VALIDATE, Boolean.FALSE);
 
-        errorsProperty = domainMetaClass.getMetaProperty(AbstractDynamicPersistentMethod.ERRORS_PROPERTY);
+        errorsProperty = domainMetaClass.getMetaProperty(GrailsDomainClassProperty.ERRORS);
 
-        validateMethod = domainMetaClass.getMetaMethod(ValidatePersistentMethod.METHOD_SIGNATURE,
+        validateMethod = domainMetaClass.getMetaMethod("validate",
                 new Object[] { Map.class });
         
         try {
@@ -155,7 +155,7 @@
             shouldTimestamp = false;
         }
     }
-
+    
     private boolean verifyTimestampFieldTypeSupport(Class<?> domainClazz, TimestampProvider timestampProvider, MetaProperty timestampField) {
         if(timestampProvider.supportsCreating(timestampField.getType())) {
             return true;
@@ -253,7 +253,7 @@
 
     public void onPostInsert(PostInsertEvent event) {
         final Object entity = event.getEntity();
-        AbstractSavePersistentMethod.clearDisabledValidations(entity);
+        AbstractHibernateGormInstanceApi.clearDisabledValidations(entity);
         if (postInsertEventListener == null) {
             return;
         }
@@ -274,7 +274,7 @@
 
     public void onPostUpdate(PostUpdateEvent event) {
         final Object entity = event.getEntity();
-        AbstractSavePersistentMethod.clearDisabledValidations(entity);
+        AbstractHibernateGormInstanceApi.clearDisabledValidations(entity);
         if (postUpdateEventListener == null) {
             return;
         }
@@ -290,7 +290,7 @@
 
     public void onPostDelete(PostDeleteEvent event) {
         final Object entity = event.getEntity();
-        AbstractSavePersistentMethod.clearDisabledValidations(entity);
+        AbstractHibernateGormInstanceApi.clearDisabledValidations(entity);
         if (postDeleteEventListener == null) {
             return;
         }
@@ -316,7 +316,7 @@
             }
         });
     }
-    
+
     public boolean onPreUpdate(final PreUpdateEvent event) {
         return doWithManualSession(event, new Closure<Boolean>(this) {
             @Override
@@ -328,7 +328,7 @@
                     synchronizePersisterState(event, event.getState());
                 }
                 handleTimestampingBeforeUpdate(event, entity);
-                if (!AbstractSavePersistentMethod.isAutoValidationDisabled(entity)
+                if (!AbstractHibernateGormInstanceApi.isAutoValidationDisabled(entity)
                         && !DefaultTypeTransformation.castToBoolean(validateMethod.invoke(entity, new Object[] { validateParams }))) {
                     evict = true;
                     if (failOnErrorEnabled) {
@@ -372,7 +372,7 @@
                 }
 
                 boolean evict = false;
-                if (!AbstractSavePersistentMethod.isAutoValidationDisabled(entity)
+                if (!AbstractHibernateGormInstanceApi.isAutoValidationDisabled(entity)
                         && !DefaultTypeTransformation.castToBoolean(validateMethod.invoke(entity,
                                 new Object[] { validateParams }))) {
                     evict = true;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java
index 8e6368e..c0a88dc 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/ClosureEventTriggeringInterceptor.java
@@ -21,6 +21,7 @@
 import java.util.HashMap;
 import java.util.Map;
 
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
 import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore;
 import org.codehaus.groovy.grails.orm.hibernate.SessionFactoryProxy;
 import org.grails.datastore.mapping.core.Datastore;
@@ -91,7 +92,6 @@
     private ApplicationContext ctx;
     private Map<SessionFactory, HibernateDatastore> datastores;
 
-    private static final ThreadLocal<Boolean> insertActiveThreadLocal = new ThreadLocal<Boolean>();
 
 /*    public ClosureEventTriggeringInterceptor() {
         try {
@@ -226,7 +226,7 @@
      */
     @Override
     protected Boolean getAssumedUnsaved() {
-        return insertActiveThreadLocal.get();
+        return AbstractHibernateGormInstanceApi.getAssumedUnsaved();
     }
 
     /**
@@ -234,13 +234,13 @@
      * to set a ThreadLocal variable that determines the value for getAssumedUnsaved().
      */
     public static void markInsertActive() {
-        insertActiveThreadLocal.set(true);
+        AbstractHibernateGormInstanceApi.markInsertActive();
     }
 
     /**
      * Clears the ThreadLocal variable set by markInsertActive().
      */
     public static void resetInsertActive() {
-        insertActiveThreadLocal.remove();
+        AbstractHibernateGormInstanceApi.resetInsertActive();
     }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java
index d2434c9..5c05598 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/FlushOnRedirectEventListener.java
@@ -15,7 +15,7 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
-import org.codehaus.groovy.grails.web.servlet.mvc.RedirectEventListener;
+import grails.web.mapping.mvc.RedirectEventListener;
 import org.hibernate.FlushMode;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java
index 98b41e9..2d1e75a 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/GrailsOpenSessionInViewInterceptor.java
@@ -15,14 +15,10 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod;
-import org.codehaus.groovy.grails.web.servlet.mvc.GrailsWebRequest;
-import org.codehaus.groovy.grails.web.sitemesh.GrailsContentBufferingResponse;
+import org.grails.web.servlet.mvc.GrailsWebRequest;
 import org.hibernate.FlushMode;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
@@ -129,19 +125,6 @@
                 return;
             }
 
-            GrailsWebRequest webRequest = (GrailsWebRequest) request;
-            HttpServletResponse response = webRequest.getCurrentResponse();
-            GrailsContentBufferingResponse contentBufferingResponse = getContentBufferingResponse(response);
-            if (contentBufferingResponse == null) {
-                super.afterCompletion(request, ex);
-                return;
-            }
-
-            // if Sitemesh is still active disconnect the session, but don't close the session
-            if (!contentBufferingResponse.isActive()) {
-                super.afterCompletion(request, ex);
-                return;
-            }
 
             try {
                 SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory());
@@ -157,19 +140,10 @@
             }
         }
         finally {
-            AbstractSavePersistentMethod.clearDisabledValidations();
+            AbstractHibernateGormInstanceApi.clearDisabledValidations();
         }
     }
 
-    protected GrailsContentBufferingResponse getContentBufferingResponse(HttpServletResponse response) {
-        while (response instanceof HttpServletResponseWrapper) {
-            if (response instanceof GrailsContentBufferingResponse) {
-                return (GrailsContentBufferingResponse) response;
-            }
-            response = (HttpServletResponse) ((HttpServletResponseWrapper) response).getResponse();
-        }
-        return null;
-    }
 
     public void setFlushMode(int flushMode) {
         this.flushMode = flushMode;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
index 7ebd844..fef8338 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java
@@ -15,7 +15,9 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
-import groovy.util.ConfigObject;
+import grails.config.Config;
+import grails.core.GrailsApplication;
+import grails.core.support.GrailsApplicationAware;
 
 import java.sql.Connection;
 import java.sql.SQLException;
@@ -23,9 +25,7 @@
 
 import javax.sql.DataSource;
 
-import org.codehaus.groovy.grails.commons.GrailsApplication;
 import org.codehaus.groovy.grails.orm.hibernate.exceptions.CouldNotDetermineHibernateDialectException;
-import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware;
 import org.hibernate.HibernateException;
 import org.hibernate.boot.registry.classloading.internal.ClassLoaderServiceImpl;
 import org.hibernate.boot.registry.selector.internal.StrategySelectorImpl;
@@ -91,7 +91,7 @@
             connection = DataSourceUtils.getConnection(dataSource);
 
             try {
-                ConfigObject config = grailsApplication == null ? null : grailsApplication.getConfig();
+                Config config = grailsApplication == null ? null : grailsApplication.getConfig();
                 Properties properties = config == null ? new Properties() : config.toProperties();
                 final DialectFactory dialectFactory = createDialectFactory();
                 final Connection finalConnection = connection;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java
index 5a66dfd..e1c8495 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/support/HibernatePersistenceContextInterceptor.java
@@ -15,16 +15,15 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.support;
 
+import grails.core.GrailsDomainClassProperty;
+import grails.persistence.support.PersistenceContextInterceptor;
 import grails.validation.DeferredBindingActions;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
+import org.codehaus.groovy.grails.orm.hibernate.AbstractHibernateGormInstanceApi;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.AbstractSavePersistentMethod;
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor;
+import org.grails.core.lifecycle.ShutdownOperations;
 import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
 import org.hibernate.internal.SessionImpl;
@@ -105,7 +104,7 @@
             }
         }
         finally {
-            AbstractSavePersistentMethod.clearDisabledValidations();
+            AbstractHibernateGormInstanceApi.clearDisabledValidations();
         }
     }
 
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java
index 08c5d22..a548018 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateConstraintsEvaluator.java
@@ -16,11 +16,12 @@
 
 import java.util.Map;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClassProperty;
+import grails.validation.Constrained;
+import grails.validation.ConstrainedProperty;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder;
 import org.codehaus.groovy.grails.orm.hibernate.cfg.PropertyConfig;
-import org.codehaus.groovy.grails.validation.ConstrainedProperty;
-import org.codehaus.groovy.grails.validation.DefaultConstraintEvaluator;
+import org.grails.validation.DefaultConstraintEvaluator;
 
 /**
  * Extends default implementation to add Hibernate specific exceptions.
@@ -39,7 +40,7 @@
     }
 
     @Override
-    protected void applyDefaultNullableConstraint(GrailsDomainClassProperty p, ConstrainedProperty cp) {
+    protected void applyDefaultNullableConstraint(GrailsDomainClassProperty p, Constrained cp) {
         final PropertyConfig propertyConfig = new GrailsDomainBinder().getPropertyConfig(p);
         boolean insertable = propertyConfig != null ? propertyConfig.isInsertable() : true;
 
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java
index d98458a..d1545af 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/HibernateDomainClassValidator.java
@@ -15,12 +15,12 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.validation;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.core.support.proxy.ProxyHandler;
 import org.codehaus.groovy.grails.orm.hibernate.proxy.HibernateProxyHandler;
-import org.codehaus.groovy.grails.support.proxy.ProxyHandler;
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.grails.validation.GrailsDomainClassValidator;
 import org.hibernate.FlushMode;
 import org.hibernate.Hibernate;
 import org.hibernate.Session;
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java
deleted file mode 100644
index d0910c5..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraint.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2004-2005 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.validation;
-
-import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.validation.Constraint;
-import org.springframework.context.ApplicationContextAware;
-
-/**
- * Defines a persistent constraint that evaluates the database.
- *
- * @author Graeme Rocher
- * @since 10-Nov-2005
- */
-public interface PersistentConstraint extends Constraint, ApplicationContextAware {
-
-    /**
-     * Obtains the HibernateTemplate.
-     *
-     * @return the template
-     */
-    GrailsHibernateTemplate getHibernateTemplate();
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java
deleted file mode 100644
index a7c35ca..0000000
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/PersistentConstraintFactory.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2004-2005 Graeme Rocher
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.grails.orm.hibernate.validation;
-
-import org.codehaus.groovy.grails.exceptions.GrailsDomainException;
-import org.codehaus.groovy.grails.validation.Constraint;
-import org.codehaus.groovy.grails.validation.ConstraintFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.util.Assert;
-
-/**
- * Creates PersistentConstraint instances ensuring that dependencies are provided.
- *
- * @author Graeme Rocher
- * @since 0.4
- */
-public class PersistentConstraintFactory implements ConstraintFactory {
-
-    private Class<?> constraintClass;
-    private ApplicationContext applicationContext;
-
-    public PersistentConstraintFactory(ApplicationContext applicationContext, Class<?> persistentConstraint) {
-
-        Assert.notNull(applicationContext, "Argument [applicationContext] cannot be null");
-
-        if (persistentConstraint == null || !PersistentConstraint.class.isAssignableFrom(persistentConstraint)) {
-            throw new IllegalArgumentException(
-                    "Argument [persistentConstraint] must be an instance of " + PersistentConstraint.class.getName());
-        }
-
-        this.applicationContext = applicationContext;
-        this.constraintClass = persistentConstraint;
-    }
-
-    public Constraint newInstance() {
-        try {
-            PersistentConstraint instance = (PersistentConstraint)constraintClass.newInstance();
-            instance.setApplicationContext(applicationContext);
-            return instance;
-        }
-        catch (InstantiationException e) {
-            throw new GrailsDomainException("Error instantiating constraint [" + constraintClass +
-                    "] during validation: " + e.getMessage(), e);
-        }
-        catch (IllegalAccessException e) {
-            throw new GrailsDomainException("Error instantiating constraint [" + constraintClass +
-                    "] during validation: " + e.getMessage(), e);
-        }
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java
index 9fc0731..03f26e6 100644
--- a/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java
+++ b/grails-datastore-gorm-hibernate4/src/main/groovy/org/codehaus/groovy/grails/orm/hibernate/validation/UniqueConstraint.java
@@ -19,22 +19,20 @@
 import java.util.Collections;
 import java.util.List;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.exceptions.GrailsRuntimeException;
-import org.codehaus.groovy.grails.lifecycle.ShutdownOperations;
+import grails.core.GrailsApplication;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
+import grails.util.GrailsClassUtils;
+import grails.validation.ConstrainedProperty;
+import groovy.lang.Closure;
+
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
-import org.codehaus.groovy.grails.validation.ConstrainedProperty;
+import org.codehaus.groovy.grails.orm.hibernate.IHibernateTemplate;
 import org.codehaus.groovy.runtime.InvokerHelper;
-import org.hibernate.Criteria;
-import org.hibernate.FlushMode;
-import org.hibernate.HibernateException;
-import org.hibernate.LockMode;
-import org.hibernate.Session;
-import org.hibernate.TransientObjectException;
+import org.grails.core.artefact.DomainClassArtefactHandler;
+import org.grails.core.exceptions.GrailsRuntimeException;
+import org.grails.core.lifecycle.ShutdownOperations;
+import org.hibernate.*;
 import org.hibernate.criterion.Restrictions;
 import org.hibernate.metadata.ClassMetadata;
 import org.springframework.beans.BeanWrapper;
@@ -149,25 +147,25 @@
                   "domain classes and not custom user types or embedded instances");
         }
 
-        GrailsHibernateTemplate hibernateTemplate = getHibernateTemplate();
+        GrailsHibernateTemplate hibernateTemplate = (GrailsHibernateTemplate )getHibernateTemplate();
         hibernateTemplate.setFlushMode(GrailsHibernateTemplate.FLUSH_NEVER);
-        Assert.state(hibernateTemplate != null,
-              "Unable use [unique] constraint, no Hibernate SessionFactory found!");
-        List<?> results = hibernateTemplate.executeFind(new GrailsHibernateTemplate.HibernateCallback<List<?>>() {
-            public List<?> doInHibernate(Session session) throws HibernateException {
+        List<?> results = hibernateTemplate.execute(new Closure<List<?>>(this) {
+
+            public List<?> call(Object... args) {
+                Session session = (Session) args[0];
                 boolean shouldValidate = true;
                 Class<?> constraintClass = constraintOwningClass;
                 if (propertyValue != null && DomainClassArtefactHandler.isDomainClass(propertyValue.getClass())) {
                     shouldValidate = session.contains(propertyValue);
                 }
                 if (shouldValidate) {
-                    GrailsApplication application  = (GrailsApplication) applicationContext.getBean(GrailsApplication.APPLICATION_ID);
-                    GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE,constraintClass.getName());
+                    GrailsApplication application = (GrailsApplication) applicationContext.getBean(GrailsApplication.APPLICATION_ID);
+                    GrailsDomainClass domainClass = (GrailsDomainClass) application.getArtefact(DomainClassArtefactHandler.TYPE, constraintClass.getName());
                     if (domainClass != null && !domainClass.isRoot()) {
                         GrailsDomainClassProperty property = domainClass.getPropertyByName(constraintPropertyName);
                         while (property.isInherited() && domainClass != null) {
                             domainClass = (GrailsDomainClass) application.getArtefact(
-                                    DomainClassArtefactHandler.TYPE,domainClass.getClazz().getSuperclass().getName());
+                                    DomainClassArtefactHandler.TYPE, domainClass.getClazz().getSuperclass().getName());
                             if (domainClass != null) {
                                 property = domainClass.getPropertyByName(constraintPropertyName);
                             }
@@ -192,7 +190,7 @@
                         criteria.add(Restrictions.eq(constraintPropertyAlias + "." + identifierPropertyName, identifierPropertyValue));
                     } else {
                         criteria = session.createCriteria(constraintClass)
-                            .add(Restrictions.eq(constraintPropertyName, propertyValue));
+                                .add(Restrictions.eq(constraintPropertyName, propertyValue));
                     }
 
                     if (uniquenessGroup != null) {
@@ -204,15 +202,13 @@
                                 try {
                                     // We are merely verifying that the object is not transient here
                                     session.lock(uniquenessGroupPropertyValue, LockMode.NONE);
-                                }
-                                catch (TransientObjectException e) {
+                                } catch (TransientObjectException e) {
                                     shouldValidate = false;
                                 }
                             }
                             if (shouldValidate) {
                                 criteria.add(Restrictions.eq(uniquenessGroupPropertyName, uniquenessGroupPropertyValue));
-                            }
-                            else {
+                            } else {
                                 break; // we aren't validating, so no point continuing
                             }
                         }
@@ -258,4 +254,15 @@
         return uniquenessGroup;
     }
 
+
+    @Override
+    public IHibernateTemplate getHibernateTemplate() {
+        SessionFactory sf = sessionFactory.get();
+        if (sf == null) {
+            sf = applicationContext.getBean("sessionFactory", SessionFactory.class);
+        }
+        GrailsApplication app = applicationContext.getBean("grailsApplication", GrailsApplication.class);
+        GrailsHibernateTemplate hibernateTemplate = new GrailsHibernateTemplate(sf, app, GrailsHibernateTemplate.FLUSH_NEVER);
+        return hibernateTemplate;
+    }
 }
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializerSpec.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializerSpec.groovy
index 9a07d96..2d0f120 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializerSpec.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/grails/orm/bootstrap/HibernateDatastoreSpringInitializerSpec.groovy
@@ -17,13 +17,16 @@
 
             def datastoreInitializer = new HibernateDatastoreSpringInitializer(Person)
             def applicationContext = new GenericApplicationContext()
-            def dataSource = new DriverManagerDataSource(Driver.name, "jdbc:h2:mem:grailsDb;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_DELAY=-1", 'sa', '')
+            def dataSource = new DriverManagerDataSource("jdbc:h2:mem:grailsDb1;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_DELAY=-1", 'sa', '')
+            dataSource.driverClassName = Driver.name
             applicationContext.beanFactory.registerSingleton("dataSource", dataSource)
 
 
         when:"The application context is configured"
             datastoreInitializer.configureForBeanDefinitionRegistry(applicationContext)
+            boolean refreshCalled = false
             applicationContext.refresh()
+            refreshCalled = true
             def conn = dataSource.getConnection()
 
         then:"The database tables are created correctly"
@@ -50,7 +53,7 @@
 
 
         cleanup:
-            if(applicationContext.isRunning()) {
+            if(refreshCalled && applicationContext.isRunning()) {
                 applicationContext.stop()
             }
 
@@ -60,7 +63,9 @@
         given:"An initializer instance"
 
             def datastoreInitializer = new HibernateDatastoreSpringInitializer(Person)
-            def dataSource = new DriverManagerDataSource(Driver.name, "jdbc:h2:mem:grailsDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_DELAY=-1", 'sa', '')
+            def dataSource = new DriverManagerDataSource("jdbc:h2:mem:grailsDb2;MVCC=TRUE;LOCK_TIMEOUT=10000;DB_CLOSE_DELAY=-1", 'sa', '')
+            dataSource.driverClassName = Driver.name
+
 
         when:"The application context is configured"
             datastoreInitializer.configureForDataSource(dataSource)
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformerSpec.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformerSpec.groovy
index c919214..9267338 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformerSpec.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformerSpec.groovy
@@ -1,12 +1,12 @@
 package org.codehaus.groovy.grails.compiler.gorm
 
+import grails.compiler.ast.ClassInjector
 import grails.persistence.Entity
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
-import org.codehaus.groovy.grails.compiler.injection.ClassInjector
-import org.codehaus.groovy.grails.compiler.injection.DefaultGrailsDomainClassInjector
-import org.codehaus.groovy.grails.compiler.injection.GrailsAwareClassLoader
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
+import org.grails.compiler.injection.DefaultGrailsDomainClassInjector
+import org.grails.compiler.injection.GrailsAwareClassLoader
+import org.grails.core.DefaultGrailsDomainClass
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.gorm.GormStaticApi
 import org.grails.datastore.gorm.GormValidationApi
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformerSpec.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformerSpec.groovy
index ae6c64f..f1fcd25 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformerSpec.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformerSpec.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.compiler.gorm
 
-import org.codehaus.groovy.grails.compiler.injection.ClassInjector
-import org.codehaus.groovy.grails.compiler.injection.GrailsAwareClassLoader
+import grails.compiler.ast.ClassInjector
+import org.grails.compiler.injection.GrailsAwareClassLoader
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.gorm.GormValidationApi
 import org.grails.datastore.mapping.simple.SimpleMapDatastore
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy
index 331bf90..1f2ddda 100755
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/AbstractGrailsHibernateTests.groovy
@@ -1,8 +1,8 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
 import grails.gorm.tests.GormDatastoreSpec
 import junit.framework.Assert
-import org.codehaus.groovy.grails.commons.GrailsApplication
 import org.grails.datastore.mapping.core.DatastoreUtils
 import org.hibernate.Session
 import org.hibernate.SessionFactory
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy
index 4a993d6..1dc5ef0 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BasicArrayAndCollectionMappingTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 import static junit.framework.Assert.*
 /**
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy
index 6729263..69ae6f1 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalListMappingTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
+import grails.core.DefaultGrailsApplication
 import org.codehaus.groovy.grails.orm.hibernate.cfg.DefaultGrailsDomainConfiguration
 import org.hibernate.FetchMode
 import org.hibernate.engine.spi.CascadeStyle
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy
index 0daf708..639107a 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndCircularOneToManyTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 
 import static junit.framework.Assert.*
 import org.junit.Test
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy
index 54c8dfe..4d1d29b 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOneToManyAndUnidirectionalOneToManyTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy
index 6b9dcdd..21efb82 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/BidirectionalOnetoManyWithInheritanceRelationshipManagementTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy
index 75c4869..5b6ca1d 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviour2Tests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy
index e49edb8..1f49801 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CascadingDeleteBehaviourTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy
index 0c2ebb2..d608071 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CharSequenceAndGormTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
 import grails.gorm.tests.Plant
-import org.codehaus.groovy.grails.web.util.StreamCharBuffer
+import org.grails.buffer.StreamCharBuffer
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
index 87e87ec..a80ad14 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CompositeIdentifierWithAssociationsTests.groovy
@@ -76,9 +76,12 @@
     }
 }
 
+trait SomeTrait {
+    void foo(){}
+}
 
 @Entity
-class CompositeIdentifierWithAssociationsParent implements Serializable {
+class CompositeIdentifierWithAssociationsParent implements Serializable, SomeTrait {
     Long id
     Long version
 
@@ -118,4 +121,4 @@
     String postCode
     CompositeIdentifierWithAssociationsParent parent
     static belongsTo = [parent:CompositeIdentifierWithAssociationsParent]
-}
\ No newline at end of file
+}
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy
index d0d92d5..cca44df 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CustomIdSpec.groovy
@@ -1,9 +1,9 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
 import grails.persistence.Entity
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
 import org.hibernate.id.IdentifierGenerationException
 import org.springframework.orm.hibernate4.HibernateSystemException
 
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy
index 48121f0..9566cb7 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/CyclicManyToManyWithInheritanceTests.groovy
@@ -1,7 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-
+import grails.core.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy
index d28511b..5f995b2 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/GormSpec.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsApplication
 import grails.gorm.tests.GormDatastoreSpec
-import org.codehaus.groovy.grails.commons.GrailsApplication
 import org.hibernate.SessionFactory
 import org.springframework.context.ApplicationContext
 import spock.lang.Shared
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy
index f793bf3..7885dc8 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/HibernateCriteriaBuilderTests.groovy
@@ -1,11 +1,9 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.orm.HibernateCriteriaBuilder
 import grails.persistence.Entity
-
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.junit.Test
 import static junit.framework.Assert.*
 
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy
index a0df03f..2c1e235 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/JpaMappedDomainTests.groovy
@@ -1,7 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import grails.persistence.Entity
-
+import javax.persistence.Entity
 import javax.persistence.GeneratedValue
 import javax.persistence.Id
 import javax.persistence.JoinColumn
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy
index 5cd2994..4de74e3 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyLoadedOneToOneIdentifierTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.apache.commons.beanutils.PropertyUtils
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil
+import org.grails.core.util.ClassPropertyFetcher
 import org.hibernate.Hibernate
 import org.hibernate.proxy.HibernateProxy
 
@@ -19,6 +19,7 @@
 
     @Test
 	void testDynamicMethodOnProxiedObject() {
+        def cpf = ClassPropertyFetcher.forClass(LazyLoadedUserIdentifier)
 		def user = LazyLoadedUser.newInstance(name:"Fred")
 
 		assertNotNull user.save(flush:true)
@@ -29,7 +30,7 @@
 		session.clear()
 
 		id = LazyLoadedUserIdentifier.get(1)
-		def proxy = PropertyUtils.getProperty(id, "user")
+        def proxy = cpf.getPropertyValue(id, "user")
 		assertTrue "should be a hibernate proxy", (proxy instanceof HibernateProxy)
 		assertFalse "proxy should not be initialized", Hibernate.isInitialized(proxy)
 		assertNotNull "calling save() on the proxy should have worked",proxy.save()
@@ -37,6 +38,7 @@
 
     @Test
 	void testMethodCallsOnProxiedObjects() {
+        def cpf = ClassPropertyFetcher.forClass(LazyLoadedUserIdentifier)
 		def user = LazyLoadedUser.newInstance(name:"Fred")
 		assertNotNull user.save(flush:true)
 
@@ -47,7 +49,7 @@
 
 		id = LazyLoadedUserIdentifier.get(1)
 
-		def proxy = PropertyUtils.getProperty(id, "user")
+        def proxy = cpf.getPropertyValue(id, "user")
 		assertTrue "should be a hibernate proxy", (proxy instanceof HibernateProxy)
 		assertFalse "proxy should not be initialized", Hibernate.isInitialized(proxy)
 		assertEquals "Fred", proxy.name
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy
index 806d86d..b3bcac6 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/LazyProxiedAssociationsWithInheritanceTests.groovy
@@ -1,8 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
 import grails.persistence.Entity
-
-import org.apache.commons.beanutils.PropertyUtils
+import org.grails.core.util.ClassPropertyFetcher
 import org.hibernate.proxy.HibernateProxy
 
 import static junit.framework.Assert.*
@@ -29,7 +28,7 @@
 
     @Test
     void testMethodCallsOnProxiedObjects() {
-
+        def cpf = ClassPropertyFetcher.forClass(LazyProxiedAssociationsWithInheritanceBook)
         def addr = LazyProxiedAssociationsWithInheritanceAddress.newInstance(houseNumber:'52')
         def auth = LazyProxiedAssociationsWithInheritanceAuthor.newInstance(name:'Marc Palmer')
         assertNotNull addr.save()
@@ -44,7 +43,7 @@
         session.clear()
 
         book = LazyProxiedAssociationsWithInheritanceBook.get(1)
-        def proxy = PropertyUtils.getProperty(book, "author")
+        def proxy = cpf.getPropertyValue(book, "author")
         assertTrue "should be a hibernate proxy", (proxy instanceof HibernateProxy)
         assertFalse "proxy should not be initialized", org.hibernate.Hibernate.isInitialized(proxy)
 
@@ -61,6 +60,7 @@
 
     @Test
     void testSettersOnProxiedObjects() {
+        def cpf = ClassPropertyFetcher.forClass(LazyProxiedAssociationsWithInheritanceBook)
         def Author = ga.getDomainClass(LazyProxiedAssociationsWithInheritanceAuthor.name).clazz
         def Address = ga.getDomainClass(LazyProxiedAssociationsWithInheritanceAddress.name).clazz
         def Book = ga.getDomainClass(LazyProxiedAssociationsWithInheritanceBook.name).clazz
@@ -80,7 +80,7 @@
 
         book = Book.get(1)
 
-        def proxy = PropertyUtils.getProperty(book, "author")
+        def proxy = cpf.getPropertyValue(book, "author")
         // test setter with non-null value
         proxy.address.houseNumber = '123'
         book.save()
@@ -96,7 +96,7 @@
 
         // test setting property to null
         book = Book.get(1)
-        proxy = PropertyUtils.getProperty(book, "author")
+        proxy = cpf.getPropertyValue(book, "author")
         proxy.address.houseNumber = null
 
         book.save()
@@ -111,7 +111,7 @@
         // should delegate call to the closure defined in HibernatePluginSupport.enhanceProxy
         // this broke with previous code
         book = Book.get(1)
-        proxy = PropertyUtils.getProperty(book, "author")
+        proxy = cpf.getPropertyValue(book, "author")
         proxy.address = null
         book.save()
         session.flush()
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy
index d5035cc..b2c60d2 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyAndOneToOneTests.groovy
@@ -1,6 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
+
 import static junit.framework.Assert.*
 import org.junit.Test
 
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy
index ed7286e..5e93b2c 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/ManyToManyWithMapTests.groovy
@@ -1,7 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.junit.Test
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy
index f519e88..57b1c57 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/MappingDefaultsTests.groovy
@@ -1,10 +1,8 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
-import org.codehaus.groovy.grails.plugins.GrailsPlugin
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
 import org.hibernate.type.YesNoType
 
 import static junit.framework.Assert.*
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy
index 7fe0c03..baca56e 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/OneToOneSelfReferencedViaInheritanceTests.groovy
@@ -1,6 +1,7 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
+
 import static junit.framework.Assert.*
 import org.junit.Test
 
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy
index cac450e..923005e 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/PersistenceMethodTests.groovy
@@ -1,12 +1,11 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
+import grails.core.GrailsDomainClass
 import grails.persistence.Entity
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
 import org.codehaus.groovy.grails.orm.hibernate.exceptions.GrailsQueryException
-import org.codehaus.groovy.grails.orm.hibernate.metaclass.FindByPersistentMethod
 import org.codehaus.groovy.runtime.metaclass.MethodSelectionException
+import org.grails.core.artefact.DomainClassArtefactHandler
 import org.springframework.core.convert.ConversionFailedException
 import org.springframework.validation.Errors
 
@@ -24,15 +23,6 @@
     }
 
     @Test
-    void testMethodSignatures() {
-        FindByPersistentMethod findBy = new FindByPersistentMethod(grailsApplication.mainContext.hibernateDatastore,
-            grailsApplication, sessionFactory, new GroovyClassLoader())
-        assertTrue findBy.isMethodMatch("findByFirstName")
-        assertTrue findBy.isMethodMatch("findByFirstNameAndLastName")
-        assertFalse findBy.isMethodMatch("rubbish")
-    }
-
-    @Test
     void testSavePersistentMethod() {
         // init spring config
 
@@ -317,7 +307,7 @@
         assertEquals 1, returnList.size()
 
         // and case when automatic conversion cannot be applied
-        shouldFail(ConversionFailedException) {
+        shouldFail(MissingMethodException) {
             returnList = domainClass.findAllById("1.1")
         }
 
@@ -606,14 +596,14 @@
         // test find with max result
         namedArgs.clear()
         namedArgs.namesList = ["wilma","fred"] as Object[]
-        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, [max:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
         assertEquals 1, listResult.size()
 
         // test find with max result without params
-        returnValue = domainClass.findAll("from PersistentMethodTests as p", 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p", [max:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
@@ -643,7 +633,7 @@
         // test find with offset
         namedArgs.clear()
         namedArgs.namesList = ["wilma","fred"] as Object[]
-        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, 2, 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p where p.firstName in (:namesList)", namedArgs, [max:1, offset:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
@@ -651,7 +641,7 @@
         assertEquals 1, listResult.size()
 
         // test find with offset without params
-        returnValue = domainClass.findAll("from PersistentMethodTests as p", 2, 1)
+        returnValue = domainClass.findAll("from PersistentMethodTests as p", [max:1, offset:1])
         assertNotNull returnValue
         assertEquals ArrayList, returnValue.getClass()
         listResult = returnValue
@@ -783,12 +773,12 @@
             domainClass.executeQuery()
         }
 
-        shouldFail(MissingMethodException) {
+        shouldFail(IllegalArgumentException) {
             domainClass.executeQuery("query", "param", [:], "4")
         }
 
         // test query with wrong third param type (must be Map)
-        shouldFail(MissingMethodException) {
+        shouldFail(IllegalArgumentException) {
             domainClass.executeQuery("query", "param", "wrong third param")
         }
 
@@ -858,16 +848,11 @@
 
         // test with multiple positional parameters
         listResult = domainClass.executeQuery(
-            "select distinct p from PersistentMethodTests as p " +
-            "where p.firstName=? and p.lastName=?", ["fred", "flintstone"])
+                "select distinct p from PersistentMethodTests as p " +
+                        "where p.firstName=? and p.lastName=?", ["fred", "flintstone"])
         assertEquals 1, listResult.size()
         assertEquals "fred", listResult[0].getProperty("firstName")
 
-        def msg = shouldFail(IllegalArgumentException) {
-            domainClass.executeQuery 'select distinct p from PersistentMethodTests as p where p.firstName = :firstName and p.lastName = :lastName', [firstName: null, lastName: 'King']
-        }
-        assertEquals 'Named parameter [firstName] value may not be null', msg
-
         // Test that executeQuery does not mutate List and Map arguments (GRAILS-7841)
         paginateParams = [max: 1]
         domainClass.executeQuery("select p from PersistentMethodTests as p", paginateParams)
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy
index 75e1e2c..a4a9d07 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/SortMappingTests.groovy
@@ -142,7 +142,6 @@
     Long version
 
     String name
-    Set unibooks
 
     Set books
     static hasMany = [books:SortMappingBook]
@@ -174,7 +173,6 @@
     Long version
 
     String name
-    Set unibooks
 
     Set books
     static hasMany = [books:SortMappingBook2]
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy
index 90e2235..baa7736 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/TwoCircularUnidirectionalOneToManyTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
+import grails.core.GrailsDomainClass
 
 import static junit.framework.Assert.*
 import org.junit.Test
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy
index e755679..af22ce6 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UndirectionalOneToManyMappingTests.groovy
@@ -22,7 +22,7 @@
 
         a.addToBooks(MappedU2mBook.newInstance(title:"The Shining"))
          .addToBooks(MappedU2mBook.newInstance(title:"The Stand"))
-         .save(true)
+         .save(flush:true)
         assertEquals 2, MappedU2mBook.list().size()
 
         // now let's test the database state
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy
index 1c37eb0..5cb7205 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/UnidirectionalOneToManyHibernateMappedTests.groovy
@@ -1,6 +1,6 @@
 package org.codehaus.groovy.grails.orm.hibernate
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
+import grails.core.DefaultGrailsApplication
 import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
 
  /**
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy
index 26c4201..e9b4f8f 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/WithCriteriaMethodTests.groovy
@@ -49,7 +49,7 @@
     Long version
     String name
     Set books
-    def relatesToMany = [books:WithCriteriaMethodBook]
+    static hasMany = [books:WithCriteriaMethodBook]
     boolean equals(obj) { name == obj?.name }
     int hashCode() { name ? name.hashCode() : super.hashCode() }
     String toString() { name }
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy
index e76de35..b8a9695 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/cfg/GrailsDomainBinderTests.groovy
@@ -15,17 +15,19 @@
  */
 package org.codehaus.groovy.grails.orm.hibernate.cfg
 
+import grails.core.DefaultGrailsApplication
+import grails.core.GrailsDomainClass
+import grails.core.GrailsDomainClassProperty
+import grails.plugins.GrailsPlugin
+import grails.plugins.GrailsPluginManager
+import grails.util.Holders
+import grails.validation.ConstrainedProperty
+import org.grails.core.DefaultGrailsDomainClass
+import org.grails.plugins.MockGrailsPluginManager
+import org.grails.support.MockApplicationContext
+
 import java.lang.reflect.Field
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
-import org.codehaus.groovy.grails.plugins.GrailsPluginManager
-import org.codehaus.groovy.grails.plugins.MockGrailsPluginManager
-import org.codehaus.groovy.grails.plugins.PluginManagerHolder
-import org.codehaus.groovy.grails.support.MockApplicationContext
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
 import org.codehaus.groovy.grails.validation.TestClass
 import org.hibernate.cfg.ImprovedNamingStrategy
 import org.hibernate.mapping.Bag
@@ -243,7 +245,7 @@
 		super.setUp()
 		ExpandoMetaClass.enableGlobally()
 		MockGrailsPluginManager pluginManager = new MockGrailsPluginManager()
-		PluginManagerHolder.setPluginManager(pluginManager)
+		Holders.setPluginManager(pluginManager)
 		previousNamingStrategyClass = grailsDomainBinder.NAMING_STRATEGIES[GrailsDomainClassProperty.DEFAULT_DATA_SOURCE].getClass()
 	}
 
@@ -252,7 +254,7 @@
 		super.tearDown()
 		grailsDomainBinder.NAMING_STRATEGIES.clear()
 		grailsDomainBinder.NAMING_STRATEGIES[GrailsDomainClassProperty.DEFAULT_DATA_SOURCE] = ImprovedNamingStrategy.INSTANCE
-		PluginManagerHolder.setPluginManager(null)
+		Holders.setPluginManager(null)
 		grailsDomainBinder.configureNamingStrategy previousNamingStrategyClass
 	}
 
@@ -818,11 +820,11 @@
 
 		def myPluginMap = [:]
 		myPluginMap.getName = { -> 'MyPlugin' }
-		def myPlugin = myPluginMap as org.codehaus.groovy.grails.plugins.GrailsPlugin
+		def myPlugin = myPluginMap as GrailsPlugin
 
 		def publisherPluginMap = [:]
 		publisherPluginMap.getName = { -> 'Publisher' }
-		def publisherPlugin = publisherPluginMap as org.codehaus.groovy.grails.plugins.GrailsPlugin
+		def publisherPlugin = publisherPluginMap as GrailsPlugin
 
 		def pluginManagerMap = [setApplicationContext: { }]
 		def myPluginDomainClassNames = ['GadgetClass', 'MyPluginPersonClass']
@@ -841,7 +843,7 @@
 		// no config property specified
 		def cfg = new ConfigSlurper().parse('''
 ''')
-		grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
 		def config = getDomainConfig(grailsApplication, pluginManager)
 		def persistentClass = config.getClassMapping("WidgetClass")
 		assertEquals("widget_class", persistentClass.table.name)
@@ -856,7 +858,7 @@
 		cfg = new ConfigSlurper().parse('''
 grails.gorm.table.prefix.enabled = true
 ''')
-		grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
 		config = getDomainConfig(grailsApplication, pluginManager)
 		persistentClass = config.getClassMapping("WidgetClass")
 		assertEquals("widget_class", persistentClass.table.name)
@@ -871,7 +873,7 @@
 		cfg = new ConfigSlurper().parse('''
 grails.gorm.table.prefix.enabled = false
 ''')
-		grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
 		config = getDomainConfig(grailsApplication, pluginManager)
 		persistentClass = config.getClassMapping("WidgetClass")
 		assertEquals("widget_class", persistentClass.table.name)
@@ -886,7 +888,7 @@
 		cfg = new ConfigSlurper().parse('''
 grails.gorm.publisher.table.prefix.enabled = true
 ''')
-		grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
 		config = getDomainConfig(grailsApplication, pluginManager)
 		persistentClass = config.getClassMapping("WidgetClass")
 		assertEquals("widget_class", persistentClass.table.name)
@@ -902,7 +904,7 @@
 grails.gorm.table.prefix.enabled = true
 grails.gorm.myPlugin.table.prefix.enabled = false
 ''')
-		grailsApplication.config = cfg
+        grailsApplication.config.merge(cfg)
 		config = getDomainConfig(grailsApplication, pluginManager)
 		persistentClass = config.getClassMapping("WidgetClass")
 		assertEquals("widget_class", persistentClass.table.name)
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethodSpec.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethodSpec.groovy
deleted file mode 100644
index 57e689a..0000000
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/codehaus/groovy/grails/orm/hibernate/metaclass/AbstractFindByPersistentMethodSpec.groovy
+++ /dev/null
@@ -1,45 +0,0 @@
-package org.codehaus.groovy.grails.orm.hibernate.metaclass
-
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.orm.hibernate.Customer
-import org.codehaus.groovy.grails.orm.hibernate.GormSpec
-import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
-import org.grails.datastore.mapping.model.MappingContext
-import org.hibernate.Criteria
-import org.hibernate.SessionFactory
-import org.hibernate.internal.CriteriaImpl
-
-import spock.lang.Issue
-
-class AbstractFindByPersistentMethodSpec extends GormSpec {
-
-    @Issue('GRAILS-8762')
-    void "Test that findBy configures a limit of 1"() {
-        given:"A finder method"
-            final datastore = new HibernateDatastore(applicationContext.getBean(MappingContext), sessionFactory, grailsApplication.config)
-            datastore.applicationContext = applicationContext
-            def finder = new TestFindBy(datastore, grailsApplication)
-        when:"The finder is invoked"
-            CriteriaImpl c  = finder.invoke(Customer, "findByName", "Bob")
-
-        then: "ensure that the limit is one"
-            c.maxResults == 1
-    }
-
-    @Override
-    List getDomainClasses() {
-        [Customer]
-    }
-}
-
-class TestFindBy extends AbstractFindByPersistentMethod {
-
-    TestFindBy(HibernateDatastore datastore, GrailsApplication application) {
-        super(datastore, application, datastore.getSessionFactory(), Thread.currentThread().contextClassLoader, ~/(findBy)([A-Z]\w*)/, ["Or", "And"] as String[])
-    }
-
-    @Override
-    protected Object getResult(Criteria crit, boolean useLimit) {
-        return crit
-    }
-}
diff --git a/grails-datastore-gorm-hibernate4/src/test/groovy/org/grails/datastore/gorm/Setup.groovy b/grails-datastore-gorm-hibernate4/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
index e3a9abf..c1b5c45 100644
--- a/grails-datastore-gorm-hibernate4/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
+++ b/grails-datastore-gorm-hibernate4/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
@@ -1,12 +1,10 @@
 package org.grails.datastore.gorm
 
+import grails.core.DefaultGrailsApplication
 import groovy.sql.Sql
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
 import groovy.transform.CompileStatic
-
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.commons.metaclass.MetaClassEnhancer
 import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTransactionManager
 import org.codehaus.groovy.grails.orm.hibernate.GrailsSessionContext
 import org.codehaus.groovy.grails.orm.hibernate.HibernateDatastore
@@ -20,6 +18,9 @@
 import org.codehaus.groovy.grails.orm.hibernate.validation.PersistentConstraintFactory
 import org.codehaus.groovy.grails.orm.hibernate.validation.UniqueConstraint
 import org.codehaus.groovy.grails.validation.ConstrainedProperty
+import org.grails.core.metaclass.MetaClassEnhancer
+
+//import org.codehaus.groovy.grails.plugins.web.api.ControllersDomainBindingApi
 import org.grails.datastore.gorm.config.GrailsDomainClassMappingContext
 import org.grails.datastore.mapping.core.Session
 import org.grails.datastore.mapping.model.MappingContext
diff --git a/grails-datastore-gorm-hibernate4/src/test/resources/log4j.properties b/grails-datastore-gorm-hibernate4/src/test/resources/log4j.properties
new file mode 100644
index 0000000..c3e4822
--- /dev/null
+++ b/grails-datastore-gorm-hibernate4/src/test/resources/log4j.properties
@@ -0,0 +1,15 @@
+
+# Enable logging for everything. Rarely useful
+log4j.rootLogger=error, NULL
+log4j.appender.NULL=org.apache.log4j.varia.NullAppender
+log4j.appender.NULL.layout=org.apache.log4j.PatternLayout
+
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+
+log4j.logger.org.hibernate=debug,stdout
+log4j.logger.org.hibernate.SQL=trace,stdout
+log4j.logger.org.hibernate.type=trace,stdout
+
+log4j.logger.org.codehaus.groovy
\ No newline at end of file
diff --git a/grails-datastore-gorm-jcr/src/main/groovy/grails/persistence/Entity.java b/grails-datastore-gorm-jcr/src/main/groovy/grails/persistence/Entity.java
deleted file mode 100644
index c7e431b..0000000
--- a/grails-datastore-gorm-jcr/src/main/groovy/grails/persistence/Entity.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package grails.persistence;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * @author Graeme Rocher
- * @since 1.1
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Entity {
-}
\ No newline at end of file
diff --git a/grails-datastore-gorm-jpa/build.gradle b/grails-datastore-gorm-jpa/build.gradle
index c7b4325..409020a 100644
--- a/grails-datastore-gorm-jpa/build.gradle
+++ b/grails-datastore-gorm-jpa/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 configurations {
     grails
diff --git a/grails-datastore-gorm-jpa/src/test/groovy/grails/gorm/tests/OneToOneSpec.groovy b/grails-datastore-gorm-jpa/src/test/groovy/grails/gorm/tests/OneToOneSpec.groovy
deleted file mode 100644
index a363cfb..0000000
--- a/grails-datastore-gorm-jpa/src/test/groovy/grails/gorm/tests/OneToOneSpec.groovy
+++ /dev/null
@@ -1,57 +0,0 @@
-package grails.gorm.tests
-
-import grails.persistence.Entity
-import org.grails.datastore.mapping.model.types.OneToOne
-import org.grails.datastore.mapping.proxy.EntityProxy
-
-class OneToOneSpec extends GormDatastoreSpec {
-
-    def "Test persist and retrieve unidirectional many-to-one"() {
-        given:"A domain model with a many-to-one"
-        def person = new Person(firstName:"Fred", lastName: "Flintstone")
-        def pet = new Pet(name:"Dino", owner:person)
-        person.save()
-        pet.save(flush:true)
-        session.clear()
-
-        when:"The association is queried"
-        pet = Pet.findByName("Dino")
-
-        then:"The domain model is valid"
-        pet != null
-        pet.name == "Dino"
-        pet.ownerId == person.id
-        pet.owner.firstName == "Fred"
-    }
-
-    def "Test persist and retrieve one-to-one with inverse key"() {
-        given:"A domain model with a one-to-one"
-        def face = new Face(name:"Joe")
-        def nose = new Nose(hasFreckles: true, face:face)
-        face.nose = nose
-        face.save(flush:true)
-        session.clear()
-
-        when:"The association is queried"
-        face = Face.get(face.id)
-        def association = Face.gormPersistentEntity.getPropertyByName('nose')
-        then:"The domain model is valid"
-        association instanceof OneToOne
-        association.associatedEntity.javaClass == Nose
-        face != null
-        face.noseId == nose.id
-        face.nose != null
-        face.nose.hasFreckles == true
-
-        when:"The inverse association is queried"
-        session.clear()
-        nose = Nose.get(nose.id)
-
-        then:"The domain model is valid"
-        nose != null
-        nose.hasFreckles == true
-        nose.face != null
-        nose.face.name == "Joe"
-    }
-}
-
diff --git a/grails-datastore-gorm-jpa/src/test/groovy/org/grails/datastore/gorm/JpaSuite.groovy b/grails-datastore-gorm-jpa/src/test/groovy/org/grails/datastore/gorm/JpaSuite.groovy
index 08af12b..09a05be 100644
--- a/grails-datastore-gorm-jpa/src/test/groovy/org/grails/datastore/gorm/JpaSuite.groovy
+++ b/grails-datastore-gorm-jpa/src/test/groovy/org/grails/datastore/gorm/JpaSuite.groovy
@@ -14,6 +14,7 @@
 import grails.gorm.tests.NamedQuerySpec
 import grails.gorm.tests.NegationSpec
 import grails.gorm.tests.OneToManySpec
+import grails.gorm.tests.OneToOneSpec
 import grails.gorm.tests.OrderBySpec
 import grails.gorm.tests.PersistenceEventListenerSpec
 import grails.gorm.tests.ProxyLoadingSpec
@@ -61,7 +62,8 @@
 //SaveAllSpec,
 //DeleteAllSpec
 //    PersistenceEventListenerSpec
-UpdateWithProxyPresentSpec
+//UpdateWithProxyPresentSpec
+    OneToOneSpec
 ])
 class JpaSuite {
 
diff --git a/grails-datastore-gorm-mongo/build.gradle b/grails-datastore-gorm-mongo/build.gradle
index cf29189..725aee9 100644
--- a/grails-datastore-gorm-mongo/build.gradle
+++ b/grails-datastore-gorm-mongo/build.gradle
@@ -1,4 +1,4 @@
-version = "1.3.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 configurations {
     grails
 }
diff --git a/grails-datastore-gorm-mongodb/build.gradle b/grails-datastore-gorm-mongodb/build.gradle
index c9db815..255e76e 100644
--- a/grails-datastore-gorm-mongodb/build.gradle
+++ b/grails-datastore-gorm-mongodb/build.gradle
@@ -1,4 +1,4 @@
-version = "3.0.3.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 configurations {
     optional
 }
@@ -26,6 +26,7 @@
         exclude group:'oro',module:'oro'
         exclude group:'asm',module:'asm'
         exclude group:'cglib',module:'cglib'
+        exclude group:'cglib', module:'cglib-nodep'
         exclude group:'xalan',module:'serializer'
         exclude group:'org.springframework',module:'spring-core'
         exclude group:'org.springframework',module:'spring-tx'
diff --git a/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy b/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy
index c533d8f..27b07c3 100644
--- a/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy
+++ b/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/bootstrap/MongoDbDataStoreSpringInitializer.groovy
@@ -18,15 +18,17 @@
 import com.mongodb.Mongo
 import com.mongodb.MongoClientURI
 import com.mongodb.MongoOptions
+import grails.core.GrailsApplication
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.InstanceFactoryBean
 import org.grails.datastore.gorm.bootstrap.AbstractDatastoreInitializer
 import org.grails.datastore.gorm.mongo.MongoGormEnhancer
+import org.grails.datastore.gorm.mongo.bean.factory.DefaultMappingHolder
 import org.grails.datastore.gorm.mongo.bean.factory.GMongoFactoryBean
 import org.grails.datastore.gorm.mongo.bean.factory.MongoDatastoreFactoryBean
 import org.grails.datastore.gorm.mongo.bean.factory.MongoMappingContextFactoryBean
 import org.grails.datastore.mapping.transactions.DatastoreTransactionManager
+import org.grails.spring.beans.factory.InstanceFactoryBean
+import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
 import org.springframework.beans.factory.support.BeanDefinitionRegistry
 import org.springframework.context.ApplicationContext
 import org.springframework.context.support.GenericApplicationContext
@@ -68,11 +70,11 @@
         super(persistentClasses)
     }
 
-    MongoDbDataStoreSpringInitializer(Properties configuration, Collection<Class> persistentClasses) {
+    MongoDbDataStoreSpringInitializer(Map configuration, Collection<Class> persistentClasses) {
         super(configuration, persistentClasses)
     }
 
-    MongoDbDataStoreSpringInitializer(Properties configuration, Class... persistentClasses) {
+    MongoDbDataStoreSpringInitializer(Map configuration, Class... persistentClasses) {
         super(configuration, persistentClasses)
     }
 
@@ -94,13 +96,13 @@
     @Override
     Closure getBeanDefinitions(BeanDefinitionRegistry beanDefinitionRegistry) {
         return {
-            def config = configuration ? new ConfigSlurper().parse(configuration) : new ConfigObject()
-            def mongoConfig = config?.grails?.mongo?.clone() ?: config?.grails?.mongodb?.clone()
-            if(mongoConfig == null) mongoConfig = new ConfigObject()
+            String connectionString = configurationObject.getProperty('grails.mongodb.connectionString','') ?: null
+            Closure defaultMapping = configurationObject.getProperty('grails.mongodb.default.mapping',Closure, this.defaultMapping)
+            Map mongoOptions = configurationObject.getProperty('grails.mongodb.options', Map, null)
+            String hostSetting = configurationObject.getProperty('grails.mongodb.host', '')
+            Collection<String> replicaSetSetting = configurationObject.getProperty('grails.mongodb.replicaSet', Collection, [])
+            Collection<String> replicaPairSetting = configurationObject.getProperty('grails.mongodb.replicaPair', Collection, [])
 
-
-            def cso = mongoConfig?.connectionString
-            def connectionString = cso ? cso?.toString() : null
             MongoClientURI mongoClientURI = null
             if(connectionString) {
                 mongoClientURI = new MongoClientURI(connectionString)
@@ -111,11 +113,11 @@
             callable.delegate = delegate
             callable.call()
 
-            mongoMappingContext(MongoMappingContextFactoryBean) {
+            gormMongoMappingContext(MongoMappingContextFactoryBean) {
                 defaultDatabaseName = databaseName
                 grailsApplication = ref(GrailsApplication.APPLICATION_ID)
-                if (mongoConfig.default.mapping instanceof Closure) {
-                    delegate.defaultMapping = this.defaultMapping
+                if (defaultMapping) {
+                    delegate.defaultMapping = new DefaultMappingHolder(defaultMapping)
                 }
             }
 
@@ -124,12 +126,9 @@
             }
             else if(!beanDefinitionRegistry.containsBeanDefinition(mongoOptionsBeanName)) {
                 "$mongoOptionsBeanName"(MongoOptionsFactoryBean) {
-                    if (mongoConfig?.options) {
-                        def options = mongoConfig.remove("options")
-                        if(options instanceof Map) {
-                            for (option in options) {
-                                setProperty(option.key, option.value)
-                            }
+                    if (mongoOptions) {
+                        for (option in mongoOptions) {
+                            setProperty(option.key, option.value)
                         }
                     }
                 }
@@ -138,46 +137,61 @@
             if(mongo) {
                 "$mongoBeanName"(InstanceFactoryBean, mongo)
             }
-            else if(!beanDefinitionRegistry.containsBeanDefinition(mongoBeanName)) {
+            else  {
 
-                "gmongo"(GMongoFactoryBean) {
-                    delegate.mongoOptions = ref("$mongoOptionsBeanName")
-                    def mongoHost = mongoConfig?.get("host")
+                def existingBean = beanDefinitionRegistry.containsBeanDefinition(mongoBeanName) ? beanDefinitionRegistry.getBeanDefinition(mongoBeanName) : null
+                boolean registerMongoBean = false
+                if(existingBean instanceof AnnotatedBeanDefinition) {
+                    AnnotatedBeanDefinition annotatedBeanDefinition = (AnnotatedBeanDefinition)existingBean
+                    if(annotatedBeanDefinition.metadata.className == 'org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration') {
 
-                    if (mongoConfig?.replicaSet instanceof Collection) {
-                        def set = []
-                        for (server in mongoConfig.get("replicaSet")) {
-                            set << new DBAddress(server.indexOf("/") > 0 ? server : "$server/$databaseName")
-                        }
-
-                        replicaSetSeeds = set
-                    }
-                    else if (mongoConfig?.replicaPair instanceof Collection) {
-                        def pair = []
-                        for (server in mongoConfig.get("replicaPair")) {
-                            pair << new DBAddress(server.indexOf("/") > 0 ? server : "$server/$databaseName")
-                        }
-                        replicaPair = pair
-                    }
-                    else if(mongoClientURI) {
-                        clientURI = mongoClientURI
-                    }
-                    else if (mongoHost) {
-                        host = mongoHost
-                        def mongoPort = mongoConfig?.get("port")
-                        if (mongoPort) port = mongoPort
-                    }
-                    else {
-                        host = "localhost"
+                        registerMongoBean = true
                     }
                 }
+                else if(existingBean == null) {
+                    registerMongoBean = true
+                }
 
-                "$mongoBeanName"(gmongo:"getMongo")
+                if(registerMongoBean) {
+                    "gmongo"(GMongoFactoryBean) {
+                        delegate.mongoOptions = ref("$mongoOptionsBeanName")
+
+                        if(mongoClientURI) {
+                            clientURI = mongoClientURI
+                        }
+                        else if (replicaSetSetting) {
+                            def set = []
+                            for (server in replicaSetSetting) {
+                                set << new DBAddress(server.indexOf("/") > 0 ? server : "$server/$databaseName")
+                            }
+
+                            replicaSetSeeds = set
+                        }
+                        else if (replicaPairSetting) {
+                            def pair = []
+                            for (server in replicaPairSetting) {
+                                pair << new DBAddress(server.indexOf("/") > 0 ? server : "$server/$databaseName")
+                            }
+                            replicaPair = pair
+                        }
+                        else if (hostSetting) {
+                            host = hostSetting
+                            Integer mongoPort = configurationObject.getProperty('grails.mongodb.port', Integer, null)
+                            if (mongoPort) port = mongoPort
+                        }
+                        else {
+                            host = "localhost"
+                        }
+                    }
+
+                    "$mongoBeanName"(gmongo:"getMongo")
+                }
+
             }
             mongoDatastore(MongoDatastoreFactoryBean) {
                 delegate.mongo = ref(mongoBeanName)
-                mappingContext = mongoMappingContext
-                config = mongoConfig.toProperties()
+                mappingContext = gormMongoMappingContext
+                config = configurationObject
             }
             "mongoTransactionManager"(DatastoreTransactionManager) {
                 datastore = ref("mongoDatastore")
diff --git a/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/geo/Polygon.groovy b/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/geo/Polygon.groovy
index 5c602d0..5848d02 100644
--- a/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/geo/Polygon.groovy
+++ b/grails-datastore-gorm-mongodb/src/main/groovy/grails/mongodb/geo/Polygon.groovy
@@ -102,15 +102,15 @@
                     return new Polygon( [fromSingleCoordsList(coords)] ) // case (2) above
                 }
                 else if( ((List)coords[0])[0] instanceof Point){
-                    return new Polygon( coords.collect { List<Point> poly_ring ->
+                    return new Polygon( coords.collect { poly_ring ->
                         // each is a List<Point>
-                        return fromSingleCoordsList(poly_ring)
+                        return fromSingleCoordsList((List<Point>)poly_ring)
                     }) // case (3) above
                 }
                 else if( ((List)coords[0])[0] instanceof List && ((List)((List)coords[0])[0])[0] instanceof Number ){
-                    return new Polygon( coords.collect { List<List<Number>> poly_ring ->
+                    return new Polygon( coords.collect { poly_ring ->
                         // each is a List<Point>
-                        return fromSingleCoordsList(poly_ring)
+                        return fromSingleCoordsList((List<List<Number>>)poly_ring)
                     } ) // case (4) above
                 }
                 else {
diff --git a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/config/MongoDatastoreConfigurer.groovy b/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/config/MongoDatastoreConfigurer.groovy
deleted file mode 100644
index 4c80ff9..0000000
--- a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/config/MongoDatastoreConfigurer.groovy
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Copyright (C) 2011 SpringSource
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-*      http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package org.grails.datastore.gorm.mongo.config
-
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator
-import org.grails.datastore.gorm.events.AutoTimestampEventListener
-import org.grails.datastore.gorm.events.DomainEventListener
-import org.grails.datastore.gorm.mongo.MongoGormEnhancer
-import org.grails.datastore.mapping.mongo.MongoDatastore
-import org.grails.datastore.mapping.mongo.config.MongoMappingContext
-import org.grails.datastore.mapping.transactions.DatastoreTransactionManager
-import org.springframework.context.ConfigurableApplicationContext
-import org.springframework.context.support.GenericApplicationContext
-
-/**
- * Support class for easing configuration of MongoDB
- *
- * @deprecated Use {@link grails.mongodb.bootstrap.MongoDbDataStoreSpringInitializer} instead
- */
-@Deprecated
-class MongoDatastoreConfigurer {
-
-    /**
-     * Configures MongoDB for usage via GORM
-     *
-     * @param databaseName The database name
-     * @param classes The classes
-     * @param configuration The configuration
-     * @return The MongoDatastore instance
-     */
-    static MongoDatastore configure(String databaseName, Class[] classes, Map configuration = Collections.emptyMap() ) {
-        ExpandoMetaClass.enableGlobally()
-
-        def ctx = new GenericApplicationContext()
-        ctx.refresh()
-        return configure(ctx, databaseName, classes, configuration)
-    }
-
-    static MongoDatastore configure(ConfigurableApplicationContext ctx, String databaseName, Class[] classes, Map configuration) {
-        final context = new MongoMappingContext(databaseName)
-        def grailsApplication = new DefaultGrailsApplication(classes, Thread.currentThread().getContextClassLoader())
-        grailsApplication.initialise()
-        for (cls in classes) {
-            def validator = new GrailsDomainClassValidator()
-            validator.setGrailsApplication(grailsApplication)
-            validator.setMessageSource(ctx)
-            validator.setDomainClass(grailsApplication.getArtefact(DomainClassArtefactHandler.TYPE, cls.name))
-            final entity = context.addPersistentEntity(cls)
-            context.addEntityValidator(entity, validator)
-        }
-        def mongoDatastore = new MongoDatastore(context, configuration, ctx)
-        mongoDatastore.afterPropertiesSet()
-
-        def enhancer = new MongoGormEnhancer(mongoDatastore, new DatastoreTransactionManager(datastore: mongoDatastore))
-        enhancer.enhance()
-
-        mongoDatastore.applicationContext.addApplicationListener new DomainEventListener(mongoDatastore)
-        mongoDatastore.applicationContext.addApplicationListener new AutoTimestampEventListener(mongoDatastore)
-
-        return mongoDatastore
-    }
-}
diff --git a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/GeoJSONType.groovy b/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/GeoJSONType.groovy
index a11fc05..a211843 100644
--- a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/GeoJSONType.groovy
+++ b/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/GeoJSONType.groovy
@@ -70,7 +70,7 @@
         return null
     }
 
-    abstract T createFromCoords(List coords)
+    abstract T createFromCoords(List<List<Double>> coords)
 
     @Override
     protected void queryInternal(PersistentProperty property, String key, Query.PropertyCriterion value, DBObject nativeQuery) {
diff --git a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/LineStringType.groovy b/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/LineStringType.groovy
index 9a28228..0711d69 100644
--- a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/LineStringType.groovy
+++ b/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/gorm/mongo/geo/LineStringType.groovy
@@ -3,6 +3,7 @@
 import grails.mongodb.geo.LineString
 import grails.mongodb.geo.Point
 import groovy.transform.CompileStatic
+
 import org.springframework.dao.DataAccessResourceFailureException
 
 /**
@@ -18,7 +19,7 @@
     }
 
     @Override
-    LineString createFromCoords(List coords) {
+    LineString createFromCoords(List<List<Double>> coords) {
         if(coords.size() < 2) throw new DataAccessResourceFailureException("Invalid polygon data returned: $coords")
 
         def points = coords.collect() { List<Double> pos -> new Point(pos.get(0), pos.get(1)) }
diff --git a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/mapping/mongo/MongoDatastore.java b/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/mapping/mongo/MongoDatastore.java
index 9da2fb9..c40f1e2 100644
--- a/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/mapping/mongo/MongoDatastore.java
+++ b/grails-datastore-gorm-mongodb/src/main/groovy/org/grails/datastore/mapping/mongo/MongoDatastore.java
@@ -294,7 +294,7 @@
                     if (mappedForm != null) {
                         List<MongoCollection.Index> indices = mappedForm.getIndices();
                         for (MongoCollection.Index index : indices) {
-                            collection.ensureIndex(new BasicDBObject(index.getDefinition()), new BasicDBObject(index.getOptions()));
+                            collection.createIndex(new BasicDBObject(index.getDefinition()), new BasicDBObject(index.getOptions()));
                         }
 
                         for (Map compoundIndex : mappedForm.getCompoundIndices()) {
@@ -338,10 +338,10 @@
                         }
                         // continue using deprecated method to support older versions of MongoDB
                         if (options.toMap().isEmpty()) {
-                            collection.ensureIndex(dbObject);
+                            collection.createIndex(dbObject);
                         }
                         else {
-                            collection.ensureIndex(dbObject, options);
+                            collection.createIndex(dbObject, options);
                         }
                     }
                 }
diff --git a/grails-datastore-gorm-mongodb/src/test/groovy/org/grails/datastore/gorm/mongo/plugin/support/MongoSpringConfigurerSpec.groovy b/grails-datastore-gorm-mongodb/src/test/groovy/org/grails/datastore/gorm/mongo/plugin/support/MongoSpringConfigurerSpec.groovy
index ae5fc36..835ca72 100644
--- a/grails-datastore-gorm-mongodb/src/test/groovy/org/grails/datastore/gorm/mongo/plugin/support/MongoSpringConfigurerSpec.groovy
+++ b/grails-datastore-gorm-mongodb/src/test/groovy/org/grails/datastore/gorm/mongo/plugin/support/MongoSpringConfigurerSpec.groovy
@@ -2,14 +2,14 @@
 
 import com.gmongo.GMongo
 import com.mongodb.MongoClientURI
-import org.codehaus.groovy.grails.commons.GrailsApplication
+import grails.core.DefaultGrailsApplication
+import grails.core.GrailsApplication
+import grails.plugins.DefaultGrailsPluginManager
+import org.grails.core.artefact.DomainClassArtefactHandler
 import spock.lang.Specification
 import grails.spring.BeanBuilder
-import org.codehaus.groovy.grails.plugins.DefaultGrailsPluginManager
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
 import org.grails.datastore.mapping.mongo.config.MongoMappingContext
 import grails.gorm.tests.Person
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
 
 /**
  */
diff --git a/grails-datastore-gorm-neo4j/build.gradle b/grails-datastore-gorm-neo4j/build.gradle
index dc1d435..e9c5adc 100644
--- a/grails-datastore-gorm-neo4j/build.gradle
+++ b/grails-datastore-gorm-neo4j/build.gradle
@@ -1,5 +1,4 @@
- version = "2.0.0-SNAPSHOT"
-//version = "2.0.0-M02"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 ext.neo4jVersion = "2.0.3"
 ext.gdmVersion = "2.0.7.RELEASE"
diff --git a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/GraphPersistentEntity.groovy b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/GraphPersistentEntity.groovy
index eb62625..1cfdada 100644
--- a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/GraphPersistentEntity.groovy
+++ b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/GraphPersistentEntity.groovy
@@ -45,11 +45,16 @@
     }
 
     public Collection<String> getLabels(domainInstance=null) {
-        Object objs = mappedForm.getLabels();
-        def result = objs instanceof Object[] ?
-                objs.collect { getLabelFor(it, domainInstance) } :
-                [getLabelFor(objs, domainInstance)]
-        result.findAll { it }  // remove nulls
+        Object labels = mappedForm.getLabels();
+
+        List objs = labels instanceof Object[] ? labels as List : [labels]
+
+        // if labels consists solely of instance-dependent labels, add default label based on class name
+        if ( objs.every { (it instanceof Closure) && (it.maximumNumberOfParameters==2) }) {
+            objs << null // adding -> label defaults to discriminator
+        }
+
+        objs.collect { getLabelFor(it, domainInstance) }.findAll { it }  // remove nulls
     }
 
     private Object getLabelFor(Object obj, domainInstance) {
diff --git a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jGormEnhancer.groovy b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jGormEnhancer.groovy
index 30fa9af..3a5f0e3 100644
--- a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jGormEnhancer.groovy
+++ b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jGormEnhancer.groovy
@@ -49,14 +49,29 @@
         return api
     }
 
-    public static void amendMapWithUndeclaredProperties(Map<String, Object> simpleProps, Object pojo, MappingContext mappingContext) {
+    public static Map<String, List<Object>> amendMapWithUndeclaredProperties(Map<String, Object> simpleProps, Object pojo, MappingContext mappingContext) {
         GroovyObject obj = (GroovyObject) pojo;
+        Map<String, List<Object>> dynRelProps = [:].withDefault { [] }
         Map<String,Object> map = (Map) obj.getProperty(Neo4jGormEnhancer.UNDECLARED_PROPERTIES);
         if (map!=null) {
             for (Map.Entry<String,Object> entry : map.entrySet()) {
-                simpleProps.put(entry.getKey(), Neo4jUtils.mapToAllowedNeo4jType(entry.getValue(), mappingContext));
+                if  (mappingContext.isPersistentEntity(entry.getValue())) {
+                    dynRelProps[entry.getKey()] << entry.getValue()
+                } else if (isCollectionWithPersistentEntities(entry.getValue(), mappingContext)) {
+                    dynRelProps[entry.getKey()].addAll(entry.getValue())
+                } else {
+                    simpleProps.put(entry.getKey(), Neo4jUtils.mapToAllowedNeo4jType(entry.getValue(), mappingContext));
+                }
             }
         }
+        dynRelProps
+    }
+
+    static boolean isCollectionWithPersistentEntities(Object o, MappingContext mappingContext) {
+        if (!(o instanceof Collection)) {
+            return false;
+        }
+        return (!o.empty) && (o.every { mappingContext.isPersistentEntity(it) })
     }
 }
 
@@ -113,6 +128,11 @@
                 unwrappedInstance.metaClass."${Neo4jGormEnhancer.UNDECLARED_PROPERTIES}" = undeclaredProps
             }
             (val == null) ? undeclaredProps.remove(name) : undeclaredProps.put(name, val)
+            if (datastore.mappingContext.isPersistentEntity(val)) {
+                val.save()
+            } else if (Neo4jGormEnhancer.isCollectionWithPersistentEntities(val, datastore.mappingContext)) {
+                val.each { it.save() }
+            }
             if (unwrappedInstance instanceof DirtyCheckable) {
                 ((DirtyCheckable)unwrappedInstance).markDirty(name)
             }
diff --git a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jUtils.groovy b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jUtils.groovy
index 55ce568..84981b4 100644
--- a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jUtils.groovy
+++ b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/Neo4jUtils.groovy
@@ -3,10 +3,6 @@
 import groovy.transform.CompileStatic
 import groovy.util.logging.Slf4j
 import org.grails.datastore.mapping.model.MappingContext
-import org.grails.datastore.mapping.model.PersistentEntity
-import org.grails.datastore.mapping.model.types.*
-import org.neo4j.graphdb.Direction
-import org.neo4j.graphdb.DynamicRelationshipType
 import org.neo4j.graphdb.GraphDatabaseService
 import org.neo4j.graphdb.Node
 import org.neo4j.graphdb.Relationship
@@ -21,28 +17,6 @@
 abstract class Neo4jUtils {
 
     /**
-     *
-     * @return {@link org.neo4j.graphdb.RelationshipType}, {@link org.neo4j.graphdb.Direction}
-     */
-    static List relationTypeAndDirection(Association association) {
-        Direction direction = Direction.OUTGOING
-        String relTypeName = relationshipTypeName(association)
-
-        // switch direction and name if we have a bidi and ( (many2many with not owning side) or (onetomany))
-        if (association.bidirectional &&
-            ((association instanceof ManyToMany && (!association.owningSide)) ||
-            association instanceof ManyToOne)) {
-                direction = Direction.INCOMING
-                relTypeName = relationshipTypeName(association.inverseSide)
-        }
-        [DynamicRelationshipType.withName(relTypeName), direction ]
-    }
-
-    static String relationshipTypeName(Association association) {
-        association.name
-    }
-
-    /**
      * dump a given node with all properties and relationships
      * @param node
      * @param logger
diff --git a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/bean/factory/Neo4jMappingContextFactoryBean.groovy b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/bean/factory/Neo4jMappingContextFactoryBean.groovy
index 8ba7081..dd10bcf 100644
--- a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/bean/factory/Neo4jMappingContextFactoryBean.groovy
+++ b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/bean/factory/Neo4jMappingContextFactoryBean.groovy
@@ -15,6 +15,7 @@
 package org.grails.datastore.gorm.neo4j.bean.factory
 
 import org.grails.datastore.gorm.bean.factory.AbstractMappingContextFactoryBean
+import org.grails.datastore.gorm.neo4j.HashcodeEqualsAwareProxyFactory
 import org.grails.datastore.gorm.neo4j.Neo4jMappingContext
 import org.grails.datastore.mapping.model.MappingContext
 
@@ -26,6 +27,6 @@
 class Neo4jMappingContextFactoryBean extends AbstractMappingContextFactoryBean {
 
     protected MappingContext createMappingContext() {
-        new Neo4jMappingContext()
+        new Neo4jMappingContext(proxyFactory: new HashcodeEqualsAwareProxyFactory())
     }
 }
diff --git a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurer.groovy b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurer.groovy
index b1441e7..ee6cd0d 100644
--- a/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurer.groovy
+++ b/grails-datastore-gorm-neo4j/src/main/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurer.groovy
@@ -15,12 +15,14 @@
 package org.grails.datastore.gorm.neo4j.plugin.support
 
 import org.apache.tomcat.jdbc.pool.PoolProperties
+import org.grails.core.support.ClassEditor
 import org.grails.datastore.gorm.neo4j.engine.JdbcCypherEngine
 import org.grails.datastore.gorm.plugin.support.SpringConfigurer
 import org.grails.datastore.gorm.neo4j.bean.factory.Neo4jMappingContextFactoryBean
 import org.grails.datastore.gorm.neo4j.bean.factory.Neo4jDatastoreFactoryBean
 
 import org.apache.tomcat.jdbc.pool.DataSource
+import org.springframework.beans.factory.config.CustomEditorConfigurer
 
 /**
  * Spring configurer for Neo4j
@@ -48,7 +50,6 @@
             def neo4jUrl = config?.url ?: "jdbc:neo4j:mem"
             def neo4jProperties = [:]
 
-
             def m = neo4jUrl =~ /$JDBC_NEO4J_PREFIX(\w+)/
 
             if (m.matches()) {
@@ -57,9 +58,12 @@
                 def isHaMode = config.ha ?: false
 
                 def factoryClassName = isHaMode ? "org.neo4j.graphdb.factory.HighlyAvailableGraphDatabaseFactory" : "org.neo4j.graphdb.factory.GraphDatabaseFactory"
+
+                def factoryClazz = Thread.currentThread().contextClassLoader.loadClass(factoryClassName)
+
                 def factoryMethodName = isHaMode ? "newHighlyAvailableDatabaseBuilder" : "newEmbeddedDatabaseBuilder"
 
-                graphDbFactory(factoryClassName as Class)
+                graphDbFactory(factoryClazz)
                 graphDbBuilder(graphDbFactory : factoryMethodName,  config.location ?: neo4jDefaultLocation)
 
                 graphDbBuilderFinal(graphDbBuilder: "setConfig", config.dbProperties ?: [:])
@@ -72,7 +76,6 @@
             }
             neo4jProperties.putAll(config.dbProperties)
 
-
             neo4jPoolConfiguration(PoolProperties) {
                 url = neo4jUrl
                 driverClassName = "org.neo4j.jdbc.Driver"
@@ -102,6 +105,13 @@
 
             }
 
+            // reverting the change done for fixing GRAILS-11112
+            // since we supply a GraphDatabaseService instance to dbProperties we do not want
+            // it being converted to a String
+            customEditors(CustomEditorConfigurer) {
+                customEditors = [(Class.name): ClassEditor.name ]
+            }
+
         }
     }
 }
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareCollection.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareCollection.java
new file mode 100644
index 0000000..4dc7377
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareCollection.java
@@ -0,0 +1,196 @@
+package org.grails.datastore.gorm.neo4j;
+
+import org.grails.datastore.mapping.dirty.checking.DirtyCheckable;
+import org.grails.datastore.mapping.engine.EntityAccess;
+import org.grails.datastore.mapping.model.PersistentEntity;
+import org.grails.datastore.mapping.model.types.Association;
+import org.grails.datastore.mapping.model.types.ManyToMany;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * A {@link java.util.Collection} implementation setting it's owner's dirty status upon
+ * modification of the set. Internally {@link org.grails.datastore.mapping.dirty.checking.DirtyCheckable}
+ * is used which is applied to all domain classes using an AST transformation.
+ */
+public abstract class DirtyCheckableAwareCollection<T> implements Collection<T> {
+
+    private final EntityAccess owner;
+    private final Association association;
+    private final Collection<T> delegate;
+    private final Neo4jSession session;
+    private final boolean reversed;
+    private final String relType;
+
+    protected DirtyCheckableAwareCollection(EntityAccess owner, Association association, Collection<T> delegate, Neo4jSession session) {
+        this.owner = owner;
+        this.association = association;
+        this.delegate = delegate;
+        this.session = session;
+        reversed = RelationshipUtils.useReversedMappingFor(association);
+        relType = RelationshipUtils.relationshipTypeUsedFor(association);
+
+        for (T obj: delegate) {
+            session.addPendingInsert(new RelationshipPendingInsert(owner, relType, new EntityAccess(association.getAssociatedEntity(), obj), session.getNativeInterface()));
+        }
+    }
+
+    @Override
+    public int size() {
+        return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean contains(Object o) {
+        return delegate.contains(0);
+    }
+
+    @Override
+    public Iterator<T> iterator() {
+        return delegate.iterator();
+    }
+
+    @Override
+    public Object[] toArray() {
+        return delegate.toArray();
+    }
+
+    @Override
+    public <T> T[] toArray(T[] ts) {
+        return delegate.toArray(ts);
+    }
+
+    @Override
+    public boolean add(T t) {
+        boolean isAdded = delegate.add(t);
+        if (isAdded) {
+            markDirty();
+            adoptGraphUponAdd(t);
+        }
+        return isAdded;
+    }
+
+    protected void adoptGraphUponAdd(T t) {
+        if (session.getMappingContext().getProxyFactory().isProxy(t)) {
+            if (!isDomainInstance(t)) return;
+        }
+        EntityAccess target = new EntityAccess(association.getAssociatedEntity(), t);
+        if (association.isBidirectional()) {
+            if (association instanceof ManyToMany) {
+                Collection coll = (Collection) target.getProperty(association.getReferencedPropertyName());
+                coll.add(owner.getEntity());
+            } else {
+                target.setProperty(association.getReferencedPropertyName(), owner.getEntity());
+            }
+        }
+
+        if (target.getIdentifier() == null) { // non-persistent instance
+            session.persist(t);
+        }
+
+        if (!reversed) { // prevent duplicated rels
+            session.addPendingInsert(new RelationshipPendingInsert(owner, relType, target, session.getNativeInterface()));
+        }
+    }
+
+    /**
+     * UpdateWithProxyPresentSpec from TCK forces usage of {@link org.grails.datastore.gorm.proxy.GroovyProxyFactory},
+     * it's isProxy method is not 100% solid so we need to workaround here
+     * @param t
+     * @return
+     */
+    private boolean isDomainInstance(T t) {
+        boolean isDomainInstance = false;
+        for (PersistentEntity pe: session.getMappingContext().getPersistentEntities()) {
+            if (pe.getJavaClass().equals(t.getClass())) {
+                isDomainInstance = true;
+            }
+        }
+        return isDomainInstance;
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        boolean isDeleted = delegate.remove(o);
+        if (isDeleted) {
+            markDirty();
+            adoptGraphUponRemove(o);
+        }
+        return isDeleted;
+
+    }
+
+    protected void adoptGraphUponRemove(Object o) {
+        if (session.getMappingContext().getProxyFactory().isProxy(o)) {
+            return;
+        }
+        if (!reversed) {
+            session.addPendingInsert(new RelationshipPendingDelete(owner, relType,
+                    new EntityAccess(association.getAssociatedEntity(), o),
+                    session.getNativeInterface()));
+        }
+    }
+
+    @Override
+    public boolean containsAll(Collection<?> objects) {
+        return delegate.containsAll(objects);
+    }
+
+    @Override
+    public boolean addAll(Collection<? extends T> ts) {
+        boolean changed = delegate.addAll(ts);
+        if (changed) {
+            markDirty();
+        }
+        return changed;
+    }
+
+    public boolean addAll(Iterable<T> objects) {
+        boolean result = false;
+        for (T obj : objects) {
+            result |= add(obj);
+        }
+        return result;
+    }
+
+    @Override
+    public boolean removeAll(Collection<?> objects) {
+        markDirty();
+        return delegate.removeAll(objects);
+    }
+
+    @Override
+    public boolean retainAll(Collection<?> objects) {
+        markDirty();
+        return delegate.retainAll(objects);
+    }
+
+    @Override
+    public void clear() {
+        markDirty();
+        delegate.clear();
+    }
+
+    protected void markDirty() {
+        Object ownerEntity = owner.getEntity();
+        if (ownerEntity instanceof DirtyCheckable) {
+            ((DirtyCheckable) ownerEntity).markDirty(association.getName());
+        }
+    }
+
+    /*@Override
+    public boolean equals(Object o) {
+        return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+        return delegate.hashCode();
+    }*/
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareList.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareList.java
new file mode 100644
index 0000000..52c1977
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareList.java
@@ -0,0 +1,89 @@
+package org.grails.datastore.gorm.neo4j;
+
+import org.grails.datastore.mapping.engine.EntityAccess;
+import org.grails.datastore.mapping.model.types.Association;
+
+import java.util.*;
+
+/**
+ * A {@link java.util.Set} implementation setting it's owner's dirty status upon
+ * modification of the set. Internally {@link org.grails.datastore.mapping.dirty.checking.DirtyCheckable}
+ * is used which is applied to all domain classes using an AST transformation
+ */
+public class DirtyCheckableAwareList<T> extends DirtyCheckableAwareCollection<T> implements List<T> {
+
+    private final List<T> delegate;
+
+    public DirtyCheckableAwareList(EntityAccess owner, Association association, List<T> delegate, Neo4jSession session) {
+        super(owner, association, delegate, session);
+        this.delegate = delegate;
+    }
+
+    @Override
+    public boolean addAll(int i, Collection<? extends T> ts) {
+        boolean added = delegate.addAll(i, ts);
+        if (added) {
+            markDirty();
+            for (T t :ts) {
+                adoptGraphUponAdd(t);
+            }
+        }
+        return added;
+    }
+
+    @Override
+    public T get(int i) {
+        return delegate.get(i);
+    }
+
+    @Override
+    public T set(int i, T t) {
+        T old = delegate.set(i, t);
+        if (!t.equals(old)) {
+            markDirty();
+            adoptGraphUponRemove(old);
+            adoptGraphUponAdd(t);
+        }
+        return old;
+    }
+
+    @Override
+    public void add(int i, T t) {
+        markDirty();
+        delegate.add(i, t);
+        adoptGraphUponAdd(t);
+    }
+
+    @Override
+    public T remove(int i) {
+        markDirty();
+        T removed = delegate.remove(i);
+        adoptGraphUponRemove(removed);
+        return removed;
+    }
+
+    @Override
+    public int indexOf(Object o) {
+        return delegate.indexOf(o);
+    }
+
+    @Override
+    public int lastIndexOf(Object o) {
+        return delegate.lastIndexOf(o);
+    }
+
+    @Override
+    public ListIterator<T> listIterator() {
+        return delegate.listIterator();
+    }
+
+    @Override
+    public ListIterator<T> listIterator(int i) {
+        return delegate.listIterator(i);
+    }
+
+    @Override
+    public List<T> subList(int i, int i2) {
+        return delegate.subList(i, i2);
+    }
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareSet.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareSet.java
new file mode 100644
index 0000000..b79b94e
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/DirtyCheckableAwareSet.java
@@ -0,0 +1,22 @@
+package org.grails.datastore.gorm.neo4j;
+
+import org.grails.datastore.mapping.engine.EntityAccess;
+import org.grails.datastore.mapping.model.types.Association;
+
+import java.util.Set;
+
+/**
+ * A {@link java.util.Set} implementation setting it's owner's dirty status upon
+ * modification of the set. Internally {@link org.grails.datastore.mapping.dirty.checking.DirtyCheckable}
+ * is used which is applied to all domain classes using an AST transformation
+ */
+public class DirtyCheckableAwareSet<T> extends DirtyCheckableAwareCollection<T> implements Set<T> {
+
+    private final Set<T> delegate;
+
+    public DirtyCheckableAwareSet(EntityAccess owner, Association association, Set<T> delegate, Neo4jSession session) {
+        super(owner, association, delegate, session);
+        this.delegate = delegate;
+    }
+
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/HashcodeEqualsAwareProxyFactory.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/HashcodeEqualsAwareProxyFactory.java
new file mode 100644
index 0000000..4df6b9e
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/HashcodeEqualsAwareProxyFactory.java
@@ -0,0 +1,29 @@
+package org.grails.datastore.gorm.neo4j;
+
+import javassist.util.proxy.MethodHandler;
+import org.grails.datastore.mapping.core.Session;
+import org.grails.datastore.mapping.proxy.JavassistProxyFactory;
+import org.grails.datastore.mapping.proxy.SessionEntityProxyMethodHandler;
+
+import java.io.Serializable;
+
+/**
+ * extends {@link org.grails.datastore.mapping.proxy.JavassistProxyFactory} to capture method calls `hashCode` and `equals`
+ * without expanding the proxy
+ */
+public class HashcodeEqualsAwareProxyFactory extends JavassistProxyFactory {
+
+    @Override
+    protected MethodHandler createMethodHandler(Session session, Class cls, Class proxyClass, final Serializable id) {
+        return new SessionEntityProxyMethodHandler(proxyClass, session, cls, id) {
+            protected Object invokeEntityProxyMethods(Object self, String methodName, Object[] args) {
+                if (methodName.equals("hashCode")) {
+                    return id.hashCode();
+                } else {
+                    return super.invokeEntityProxyMethods(self, methodName, args);
+                }
+            }
+        };
+    }
+
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/LazyEnititySet.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/LazyEnititySet.java
deleted file mode 100644
index b3d1977..0000000
--- a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/LazyEnititySet.java
+++ /dev/null
@@ -1,173 +0,0 @@
-package org.grails.datastore.gorm.neo4j;
-
-import org.grails.datastore.gorm.neo4j.engine.CypherResult;
-import org.grails.datastore.mapping.dirty.checking.DirtyCheckable;
-import org.grails.datastore.mapping.engine.EntityAccess;
-import org.grails.datastore.mapping.model.types.Association;
-import org.grails.datastore.mapping.model.types.ManyToMany;
-import org.grails.datastore.mapping.proxy.ProxyFactory;
-
-import java.util.*;
-
-/**
- * Created by stefan on 20.03.14.
- */
-public class LazyEnititySet<T> implements Set<T> {
-
-    private final ProxyFactory proxyFactory;
-    private final Neo4jSession session;
-    private final EntityAccess owner;
-    private final Set<T> delegate = new HashSet<T>();
-    private final Association association;
-    private boolean initialized = false;
-    private boolean reversed;
-    private String relType;
-
-    public LazyEnititySet(EntityAccess owner, Association association, ProxyFactory proxyFactory, Neo4jSession session) {
-        this.owner = owner;
-        this.association = association;
-        this.proxyFactory = proxyFactory;
-        this.session = session;
-        reversed = RelationshipUtils.useReversedMappingFor(association);
-        relType = RelationshipUtils.relationshipTypeUsedFor(association);
-    }
-
-    private void initialize() {
-        if (!initialized) {
-            initialized = true;
-            String cypher = CypherBuilder.findRelationshipEndpointIdsFor(association);
-            CypherResult result = session.getNativeInterface().execute(cypher, Collections.singletonList(owner.getIdentifier()));
-
-            Class<T> clazz = association.getAssociatedEntity().getJavaClass();
-            for (Map<String, Object> row : result) {
-                Long endpoint = (Long) row.get("id");
-                delegate.add( proxyFactory.createProxy(session, clazz, endpoint));
-            }
-        }
-    }
-
-    @Override
-    public int size() {
-        initialize();
-        return delegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-        initialize();
-        return  delegate.isEmpty();
-    }
-
-    @Override
-    public boolean contains(Object o) {
-        initialize();
-        return delegate.contains(o);
-    }
-
-    @Override
-    public Iterator iterator() {
-        initialize();
-        return delegate.iterator();
-    }
-
-    @Override
-    public Object[] toArray() {
-        initialize();
-        return delegate.toArray();
-    }
-
-    @Override
-    public boolean add(Object o) {
-        initialize();
-        boolean isNew = delegate.add((T) o);
-        if (isNew) {
-            EntityAccess target = new EntityAccess(association.getAssociatedEntity(), o);
-
-            if (association.isBidirectional()) {
-                if (association instanceof ManyToMany) {
-                    Collection coll = (Collection) target.getProperty(association.getReferencedPropertyName());
-                    coll.add(owner.getEntity());
-                } else {
-                    target.setProperty(association.getReferencedPropertyName(), owner.getEntity());
-                }
-            }
-
-            if (target.getIdentifier()==null) { // non-persistent instance
-                session.persist(o);
-            }
-
-            if (!reversed) { // prevent duplicated rels
-                session.addPendingInsert(new RelationshipPendingInsert(owner, relType, target, session.getNativeInterface()));
-            }
-
-            markDirty();
-
-        }
-        return isNew;
-    }
-
-    @Override
-    public boolean remove(Object o) {
-        boolean isDeleted = delegate.remove(o);
-        if (isDeleted && (!reversed)) {
-            session.addPendingInsert(new RelationshipPendingDelete(owner, relType,
-                    new EntityAccess(association.getAssociatedEntity(), o),
-                    session.getNativeInterface()));
-        }
-        if (isDeleted) {
-            markDirty();
-        }
-        return isDeleted;
-    }
-
-    @Override
-    public boolean addAll(Collection collection) {
-        return addAll((Iterable)collection);
-    }
-
-    @Override
-    public void clear() {
-        throw new UnsupportedOperationException();
-
-    }
-
-    @Override
-    public boolean removeAll(Collection collection) {
-        throw new UnsupportedOperationException();
-//        return false;
-    }
-
-    @Override
-    public boolean retainAll(Collection collection) {
-        throw new UnsupportedOperationException();
-//        return false;
-    }
-
-    @Override
-    public boolean containsAll(Collection collection) {
-        throw new UnsupportedOperationException();
-//        return false;
-    }
-
-    @Override
-    public T[] toArray(Object[] objects) {
-        throw new UnsupportedOperationException();
-//        return new T[0];
-    }
-
-    public boolean addAll(Iterable objects) {
-        boolean hasChanged = false;
-        for (Object object: objects) {
-            hasChanged |= add(object);
-        }
-        return hasChanged;
-    }
-
-    private void markDirty() {
-        Object entity = owner.getEntity();
-        if (entity instanceof DirtyCheckable) {
-            ((DirtyCheckable) entity).markDirty(association.getName());
-        }
-    }
-
-}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/LazyEntitySetToSetConverter.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/LazyEntitySetToSetConverter.java
deleted file mode 100644
index 1721fda..0000000
--- a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/LazyEntitySetToSetConverter.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.grails.datastore.gorm.neo4j;
-
-import org.springframework.core.convert.converter.Converter;
-
-import java.util.Set;
-
-/**
- * bypass the default CollectionToCollectionConverter in order to not expand proxies
-*/
-public class LazyEntitySetToSetConverter implements Converter<LazyEnititySet, Set> {
-
-    @Override
-    public Set convert(LazyEnititySet source) {
-        return source;
-    }
-}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jEntityPersister.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jEntityPersister.java
index 9d857d8..6ce7422 100644
--- a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jEntityPersister.java
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jEntityPersister.java
@@ -3,6 +3,7 @@
 import groovy.lang.GroovyObject;
 import org.grails.datastore.gorm.neo4j.engine.CypherEngine;
 import org.grails.datastore.gorm.neo4j.engine.CypherResult;
+import org.grails.datastore.gorm.neo4j.parsers.PlingStemmer;
 import org.grails.datastore.mapping.core.Session;
 import org.grails.datastore.mapping.dirty.checking.DirtyCheckable;
 import org.grails.datastore.mapping.engine.EntityAccess;
@@ -96,31 +97,42 @@
         int longestInheritenceChain = -1;
 
         for (String l: labels) {
-            PersistentEntity persistentEntity = findPersistentEntityWithLabel(l);
-
-            int inheritenceChain = calcInheritenceChain(persistentEntity);
-            if (inheritenceChain > longestInheritenceChain) {
-                longestInheritenceChain = inheritenceChain;
-                result = persistentEntity;
+            PersistentEntity persistentEntity = findDerivedPersistentEntityWithLabel(pe, l);
+            if (persistentEntity!=null) {
+                int inheritenceChain = calcInheritenceChain(persistentEntity);
+                if (inheritenceChain > longestInheritenceChain) {
+                    longestInheritenceChain = inheritenceChain;
+                    result = persistentEntity;
+                }
             }
         }
         return result;
     }
 
-    private PersistentEntity findPersistentEntityWithLabel(String label) {
+    private PersistentEntity findDerivedPersistentEntityWithLabel(PersistentEntity parent, String label) {
         for (PersistentEntity pe: getMappingContext().getPersistentEntities()) {
-            if (((GraphPersistentEntity)pe).getLabels().contains(label)) {
-                return pe;
+            if (isInParentsChain(parent, pe)) {
+                if (((GraphPersistentEntity)pe).getLabels().contains(label)) {
+                    return pe;
+                }
             }
         }
-        throw new IllegalStateException("no persistententity with discriminator " + label);
+        return null;
     }
 
-    int calcInheritenceChain(PersistentEntity pe) {
-        if (pe == null) {
+    private boolean isInParentsChain(PersistentEntity parent, PersistentEntity it) {
+        if (it==null) {
+            return false;
+        } else if (it.equals(parent)) {
+            return true;
+        } else return isInParentsChain(parent, it.getParentEntity());
+    }
+
+    private int calcInheritenceChain(PersistentEntity current) {
+        if (current == null) {
             return 0;
         } else {
-            return calcInheritenceChain(pe.getParentEntity()) + 1;
+            return calcInheritenceChain(current.getParentEntity()) + 1;
         }
     }
 
@@ -132,43 +144,96 @@
         entityAccess.setIdentifier(id);
         data.remove("__id__");
 
+        Map<TypeDirectionPair, Map<String, Collection>> relationshipsMap = new HashMap<TypeDirectionPair, Map<String, Collection>>();
+        CypherResult relationships = getSession().getNativeInterface().execute(String.format("MATCH (m%s {__id__:{1}})-[r]-(o) RETURN type(r) as relType, startNode(r)=m as out, {ids: collect(o.__id__), labels: collect(labels(o))} as values", ((GraphPersistentEntity)persistentEntity).getLabelsAsString()), Collections.singletonList(id));
+        for (Map<String, Object> row : relationships) {
+            String relType = (String) row.get("relType");
+            Boolean outGoing = (Boolean) row.get("out");
+            Map<String, Collection> values = (Map<String, Collection>) row.get("values");
+            TypeDirectionPair key = new TypeDirectionPair(relType, outGoing);
+            relationshipsMap.put(key, values);
+        }
+
         for (PersistentProperty property: entityAccess.getPersistentEntity().getPersistentProperties()) {
 
             String propertyName = property.getName();
             if (property instanceof Simple) {  // implicitly sets version property as well
                 entityAccess.setProperty(propertyName, data.remove(propertyName));
-//            } else if (property instanceof OneToOne) {
-//                log.error("property " + property.getName() + " is of type " + property.getClass().getSuperclass());
-            } else if (property instanceof ToOne) {
-                ToOne to = (ToOne) property;
+            } else if (property instanceof Association) {
 
-                CypherResult cypherResult = getSession().getNativeInterface().execute(CypherBuilder.findRelationshipEndpointIdsFor(to), Collections.singletonList(id));
-
-                Map<String,Object> row = IteratorUtil.singleOrNull(cypherResult);
-                if (row != null) {
-                    Long endpointId = (Long) row.get("id");
-                    entityAccess.setProperty(propertyName,
-                            getMappingContext().getProxyFactory().createProxy(
-                                    session,
-                                    to.getAssociatedEntity().getJavaClass(),
-                                    endpointId
-                            )
-                    );
-                }
-            } else if ((property instanceof OneToMany) || (property instanceof ManyToMany)) {
-
-                LazyEnititySet lazyEnititySet = new LazyEnititySet(
-                        entityAccess,
-                        (Association) property,
-                        getMappingContext().getProxyFactory(),
-                        getSession()
+                Association association = (Association) property;
+                TypeDirectionPair typeDirectionPair = new TypeDirectionPair(
+                        RelationshipUtils.relationshipTypeUsedFor(association),
+                        !RelationshipUtils.useReversedMappingFor(association)
                 );
-                entityAccess.setProperty(propertyName, lazyEnititySet);
+
+                Map<String, Collection> idsAndLabels = relationshipsMap.remove(typeDirectionPair);
+                Collection<Long> targetIds = idsAndLabels == null ? null : idsAndLabels.get("ids");
+
+                if (association instanceof ToOne) {
+                    ToOne toOne = (ToOne) association;
+                    if (targetIds!=null) {
+                        Long targetId = IteratorUtil.single(targetIds);
+//                        if (targetId!=null) {
+                            entityAccess.setProperty(propertyName,
+                                    getMappingContext().getProxyFactory().createProxy(
+                                            session,
+                                            toOne.getAssociatedEntity().getJavaClass(),
+                                            targetId
+                                    )
+                            );
+//                        }
+                    }
+                } else if ((association instanceof OneToMany) || (association instanceof ManyToMany)) {
+                    Collection values = (Collection) entityAccess.getProperty(propertyName);
+                    values = createDirtyCheckableAwareCollection(entityAccess, association, values);
+                    entityAccess.setProperty(propertyName, values);
+
+                    if (targetIds!=null) {
+                        for (Long targetId : targetIds) {
+                            values.add(getMappingContext().getProxyFactory().createProxy(
+                                            session,
+                                            association.getAssociatedEntity().getJavaClass(),
+                                            targetId
+                                    )
+                            );
+
+                        }
+                    }
+                } else {
+                    throw new IllegalArgumentException("association " + association.getName() + " is of type " + association.getClass().getSuperclass().getName());
+                }
 
             } else {
-                    throw new IllegalArgumentException("property $property.name is of type ${property.class.superclass}");
-            }
+                throw new IllegalArgumentException("property " + property.getName() + " is of type " + property.getClass().getSuperclass().getName());
 
+            }
+        }
+
+        if (!relationshipsMap.isEmpty()) {
+            for (Map.Entry<TypeDirectionPair, Map<String,Collection>> entry: relationshipsMap.entrySet()) {
+
+                if (entry.getKey().isOutgoing()) {
+                    Iterator<Long> idIter = entry.getValue().get("ids").iterator();
+                    Iterator<Collection<String>> labelIter = entry.getValue().get("labels").iterator();
+
+                    Collection values = new ArrayList();
+                    while (idIter.hasNext() && labelIter.hasNext()) {
+                        Long targetId = idIter.next();
+                        Collection<String> labels = labelIter.next();
+                        Object proxy = getMappingContext().getProxyFactory().createProxy(
+                                session,
+                                ((Neo4jMappingContext) getMappingContext()).findPersistentEntityForLabels(labels).getJavaClass(),
+                                targetId
+                        );
+                        values.add(proxy);
+                    }
+
+                    // for single instances and singular property name do not use an array
+                    Object value = (values.size()==1) && isSingular(entry.getKey().getType()) ? IteratorUtil.single(values): values;
+                    data.put(entry.getKey().getType(), value);
+                }
+            }
         }
 
         if (!data.isEmpty()) {
@@ -176,10 +241,35 @@
             go.setProperty(Neo4jGormEnhancer.UNDECLARED_PROPERTIES, data);
         }
 
+
         firePostLoadEvent(entityAccess.getPersistentEntity(), entityAccess);
         return entityAccess.getEntity();
     }
 
+    private Collection createCollection(Association association) {
+        return association.isList() ? new ArrayList() : new HashSet();
+    }
+
+    private Collection createDirtyCheckableAwareCollection(EntityAccess entityAccess, Association association, Collection delegate) {
+        if (delegate==null) {
+            delegate = createCollection(association);
+        }
+        if (!(delegate instanceof DirtyCheckableAwareCollection)) {
+            delegate = association.isList() ?
+                    new DirtyCheckableAwareList(entityAccess, association, (List)delegate, getSession()) :
+                    new DirtyCheckableAwareSet(entityAccess, association, (Set) delegate, getSession());
+        }
+        return delegate;
+    }
+
+    private boolean isSingular(String key) {
+        return PlingStemmer.isSingular(key);
+    }
+
+    /*private Class<Object> findJavaClassForLabels(Object labels) {
+        return null;
+    }*/
+
     @Override
     protected Serializable persistEntity(PersistentEntity pe, Object obj) {
         if (obj == null) {
@@ -259,17 +349,14 @@
                             }
                         }
 
-                        Iterable targets = (Iterable) propertyValue;
+                        Collection targets = (Collection) propertyValue;
                         persistEntities(association.getAssociatedEntity(), targets, persistingColl);
 
                         boolean reversed = RelationshipUtils.useReversedMappingFor(association);
 
                         if (!reversed) {
-                            if (!(propertyValue instanceof LazyEnititySet)) {
-                                LazyEnititySet les = new LazyEnititySet(entityAccess, association, getMappingContext().getProxyFactory(), getSession());
-                                les.addAll(targets);
-                                entityAccess.setProperty(association.getName(), les);
-                            }
+                            Collection dcc = createDirtyCheckableAwareCollection(entityAccess, association, targets);
+                            entityAccess.setProperty(association.getName(), dcc);
                         }
                     }
                 } else if (pp instanceof ToOne) {
@@ -298,12 +385,14 @@
                         String relType = RelationshipUtils.relationshipTypeUsedFor(to);
 
                         if (!reversed) {
+                            if (isUpdate) {
+                                getSession().addPendingInsert(new RelationshipPendingDelete(entityAccess, relType, null , getCypherEngine()));
+                            }
                             getSession().addPendingInsert(new RelationshipPendingInsert(entityAccess, relType,
                                     new EntityAccess(to.getAssociatedEntity(), propertyValue),
                                     getCypherEngine()));
                         }
 
-
                     }
                 } else {
                     throw new IllegalArgumentException("wtf don't know how to handle " + pp + "(" + pp.getClass() +")" );
@@ -361,30 +450,34 @@
             // populate cascades
             for (Association association: pe.getAssociations()) {
                 Object property = entityAccess.getProperty(association.getName());
-                if (association.isOwningSide() && association.doesCascade(CascadeType.REMOVE) && (property!=null)) {
 
-                    PersistentEntity associatedEntity = association.getAssociatedEntity();
+                // TODO: check if property is an empty array -> exclude
+                if (association.isOwningSide() && association.doesCascade(CascadeType.REMOVE)) {
 
-                    Collection<Object> cascadesForPersistentEntity = cascades.get(associatedEntity);
-                    if (cascadesForPersistentEntity==null) {
-                        cascadesForPersistentEntity = new ArrayList<Object>();
-                        cascades.put(associatedEntity, cascadesForPersistentEntity);
+                    if (propertyNotEmpty(property)) {
+
+                        PersistentEntity associatedEntity = association.getAssociatedEntity();
+
+                        Collection<Object> cascadesForPersistentEntity = cascades.get(associatedEntity);
+                        if (cascadesForPersistentEntity==null) {
+                            cascadesForPersistentEntity = new ArrayList<Object>();
+                            cascades.put(associatedEntity, cascadesForPersistentEntity);
+                        }
+
+                        if (association instanceof ToOne) {
+                            cascadesForPersistentEntity.add(property);
+                        } else {
+                            cascadesForPersistentEntity.addAll((Collection<?>) property);
+                        }
                     }
-
-                    if (association instanceof ToOne) {
-                        cascadesForPersistentEntity.add(property);
-                    } else {
-                        cascadesForPersistentEntity.addAll((Collection<?>) property);
-                    }
-
                 }
             }
-
         }
 
         for (Map.Entry<PersistentEntity, Collection<Object>> entry: cascades.entrySet()) {
-            deleteEntities(entry.getKey(), entry.getValue());
-
+            if (!entry.getValue().isEmpty()) {
+                deleteEntities(entry.getKey(), entry.getValue());
+            }
         }
 
         getCypherEngine().execute(
@@ -396,6 +489,16 @@
         }
     }
 
+    private boolean propertyNotEmpty(Object property) {
+        if (property==null) {
+            return false;
+        }
+        if ((property instanceof Collection) && ( ((Collection) property).isEmpty() )) {
+            return false;
+        }
+        return true;
+    }
+
     @Override
     public Query createQuery() {
         return new Neo4jQuery(session, getPersistentEntity(), this);
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jMappingContext.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jMappingContext.java
index bb173c8..af215ae 100644
--- a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jMappingContext.java
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jMappingContext.java
@@ -15,13 +15,15 @@
 package org.grails.datastore.gorm.neo4j;
 
 //import org.grails.datastore.gorm.neo4j.converters.*;
-import org.grails.datastore.mapping.document.config.Attribute;
+import org.grails.datastore.mapping.engine.NonPersistentTypeException;
 import org.grails.datastore.mapping.model.AbstractMappingContext;
 import org.grails.datastore.mapping.model.MappingConfigurationStrategy;
 import org.grails.datastore.mapping.model.MappingFactory;
 import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.model.config.GormMappingConfigurationStrategy;
 
+import java.util.Collection;
+
 /**
  * @author Stefan Armbruster <stefan@armbruster-it.de>
  */
@@ -30,15 +32,9 @@
     MappingFactory mappingFactory = new GraphGormMappingFactory();
     MappingConfigurationStrategy mappingSyntaxStrategy = new GormMappingConfigurationStrategy(mappingFactory);
 
-//    Neo4jMappingContext() {
-//        mappingFactory = new GraphGormMappingFactory()
-//        syntaxStrategy =
-//    }
-
-
     public Neo4jMappingContext() {
         super();
-        addTypeConverter(new LazyEntitySetToSetConverter());
+//        addTypeConverter(new LazyEntitySetToSetConverter());
     }
 
     @Override
@@ -58,6 +54,18 @@
         return persistentEntity;
     }
 
+
+    public GraphPersistentEntity findPersistentEntityForLabels(Collection<String> labels) {
+        for (PersistentEntity pe : getPersistentEntities()) {
+            GraphPersistentEntity gpe = (GraphPersistentEntity) pe;
+
+            if (gpe.getLabels().equals(labels)) {
+                return gpe;
+            }
+        }
+        throw new NonPersistentTypeException(labels.toString());
+    }
+
 //    MappingFactory getMappingFactory() {
 //        mappingFactory
 //    }
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jSession.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jSession.java
index 504e2bf..53d9681 100644
--- a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jSession.java
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/Neo4jSession.java
@@ -77,7 +77,8 @@
                 if (pendingInsert instanceof NodePendingInsert) {
                     nodes.add(pendingInsert);
                 }
-                if (pendingInsert instanceof RelationshipPendingInsert) {
+                if ((pendingInsert instanceof RelationshipPendingInsert) ||
+                    (pendingInsert instanceof RelationshipPendingDelete)) {
                     relationships.add(pendingInsert);
                 }
 
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/NodePendingInsert.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/NodePendingInsert.java
index 55c1786..d96b4fb 100644
--- a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/NodePendingInsert.java
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/NodePendingInsert.java
@@ -4,12 +4,11 @@
 import org.grails.datastore.mapping.core.impl.PendingInsertAdapter;
 import org.grails.datastore.mapping.engine.EntityAccess;
 import org.grails.datastore.mapping.model.MappingContext;
+import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.model.PersistentProperty;
 import org.grails.datastore.mapping.model.types.Simple;
 
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 
 /**
  * Created by stefan on 15.02.14.
@@ -40,12 +39,23 @@
             }
         }
 
-        Neo4jGormEnhancer.amendMapWithUndeclaredProperties(simpleProps, getNativeEntry(), mappingContext);
+        Map<String, List<Object>> dynamicRelProps = Neo4jGormEnhancer.amendMapWithUndeclaredProperties(simpleProps, getNativeEntry(), mappingContext);
 
         String labels = ((GraphPersistentEntity)entity).getLabelsWithInheritance(getEntityAccess().getEntity());
         String cypher = String.format("CREATE (n%s {1})", labels);
 
         cypherEngine.execute(cypher, Collections.singletonList(simpleProps));
+
+        for (Map.Entry<String, List<Object>> e: dynamicRelProps.entrySet()) {
+            for (Object o: e.getValue()) {
+                GraphPersistentEntity gpe = (GraphPersistentEntity)mappingContext.getPersistentEntity(o.getClass().getName());
+                cypher = String.format("MATCH (a%s {__id__:{1}}), (b%s {__id__:{2}}) MERGE (a)-[:%s]->(b)", labels, gpe.getLabelsWithInheritance(o), e.getKey() );
+                List params = new ArrayList();
+                params.add(nativeKey);
+                params.add(new EntityAccess(gpe, o).getIdentifier());
+                cypherEngine.execute(cypher, params);
+            }
+        }
     }
 
 }
\ No newline at end of file
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/TypeDirectionPair.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/TypeDirectionPair.java
new file mode 100644
index 0000000..b988030
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/TypeDirectionPair.java
@@ -0,0 +1,61 @@
+package org.grails.datastore.gorm.neo4j;
+
+import org.grails.datastore.mapping.model.types.Association;
+
+/**
+ * combination of relationship type and direction to be used a key in a map
+ */
+public class TypeDirectionPair {
+
+    private String type;
+    private boolean outgoing;
+
+    public TypeDirectionPair(String type, boolean outgoing) {
+        this.type = type;
+        this.outgoing = outgoing;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public boolean isOutgoing() {
+        return outgoing;
+    }
+
+    public void setOutgoing(boolean outgoing) {
+        this.outgoing = outgoing;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        TypeDirectionPair that = (TypeDirectionPair) o;
+
+        if (outgoing != that.outgoing) return false;
+        if (!type.equals(that.type)) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = type.hashCode();
+        result = 31 * result + (outgoing ? 1 : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "TypeDirectionPair{" +
+                "type='" + type + '\'' +
+                ", outgoing=" + outgoing +
+                '}';
+    }
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/datatypes/FinalMap.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/datatypes/FinalMap.java
new file mode 100644
index 0000000..657cc29
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/datatypes/FinalMap.java
@@ -0,0 +1,43 @@
+package org.grails.datastore.gorm.neo4j.datatypes;
+import java.util.TreeMap;
+
+/** 
+This class is part of the Java Tools (see http://mpii.de/yago-naga/javatools).
+It is licensed under the Creative Commons Attribution License 
+(see http://creativecommons.org/licenses/by/3.0) by 
+the YAGO-NAGA team (see http://mpii.de/yago-naga).
+  
+
+  
+ 
+
+Provides a nicer constructor for a TreeMap. 
+Example:
+<PRE>
+   FinalMap<String,Integer> f=new FinalMap(
+     "a",1,
+     "b",2,
+     "c",3);
+   System.out.println(f.get("b"));
+   --> 2
+</PRE>
+*/
+public class FinalMap<T1 extends Comparable,T2> extends TreeMap<T1,T2>{
+	private static final long serialVersionUID = 1L;
+
+/** Constructs a FinalMap from an array that contains key/value sequences */  
+  @SuppressWarnings("unchecked")
+  public FinalMap(Object... a) {
+    super();    
+    for(int i=0;i<a.length-1;i+=2) {
+      if(containsKey((T1)a[i])) throw new RuntimeException("Duplicate key in FinalMap: "+a[i]);
+      put((T1)a[i],(T2)a[i+1]);
+    }
+  }
+  
+  /** Test routine */
+  public static void main(String[] args) {
+    FinalMap<String,Integer> f=new FinalMap<String,Integer>("a",1,"b",2);
+    System.out.println(f.get("b"));
+  }
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/datatypes/FinalSet.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/datatypes/FinalSet.java
new file mode 100644
index 0000000..fda8927
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/datatypes/FinalSet.java
@@ -0,0 +1,73 @@
+package org.grails.datastore.gorm.neo4j.datatypes;
+import java.util.AbstractList;
+import java.util.Arrays;
+import java.util.Set;
+
+import org.grails.datastore.gorm.neo4j.javatools.administrative.D;
+/** 
+This class is part of the Java Tools (see http://mpii.de/yago-naga/javatools).
+It is licensed under the Creative Commons Attribution License 
+(see http://creativecommons.org/licenses/by/3.0) by 
+the YAGO-NAGA team (see http://mpii.de/yago-naga).
+  
+
+  
+ 
+
+This class provides a very simple container implementation with zero overhead.
+A FinalSet bases on a sorted, unmodifiable array. The constructor
+can either be called with a sorted unmodifiable array (default constructor)
+or with an array that can be cloned and sorted beforehand if desired. 
+Example:
+<PRE>
+   FinalSet<String> f=new FinalSet("a","b","c");
+   // equivalently: 
+   //   FinalSet<String> f=new FinalSet(new String[]{"a","b","c"});
+   //   FinalSet<String> f=new FinalSet(SHALLNOTBECLONED,ISSORTED,"a","b","c");
+   System.out.println(f.get(1));
+   --> b
+</PRE>
+*/
+public class FinalSet<T extends Comparable<?>> extends AbstractList<T> implements Set<T>{
+  /** Holds the data, must be sorted */
+  public T[] data;  
+  /** Constructs a FinalSet from an array, clones and sorts the array if indicated. */
+  @SuppressWarnings("unchecked")
+  public FinalSet(boolean clone,T... a) {
+    if(clone) {
+      Comparable<?>[] b=new Comparable[a.length];
+      System.arraycopy(a,0,b,0,a.length);
+      a=(T[])b;
+    }
+    Arrays.sort(a);
+    data=a;
+  }
+  /** Constructs a FinalSet from an array that does not need to be cloned */
+  public FinalSet(T... a) {
+    this(false,a);
+  }
+  /** Tells whether x is in the container */
+  public boolean contains(T x) {
+    return(Arrays.binarySearch(data,x)>=0);
+  }
+  /** Returns the position in the array or -1 */
+  public int indexOf(T x) {
+    int r=Arrays.binarySearch(data,x);
+    return(r>=0?r:-1);
+  }
+  /** Returns the element at position i*/
+  public T get(int i) {
+    return(data[i]);
+  }
+  
+  /** Returns the number of elements in this FinalSet */
+  public int size() {
+    return(data.length);
+  }
+  
+  /** Test routine */
+  public static void main(String[] args) {
+    FinalSet<String> f=new FinalSet<String>("b","a","c");
+    D.p(f.get(1));
+  }
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/javatools/administrative/D.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/javatools/administrative/D.java
new file mode 100644
index 0000000..fea709a
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/javatools/administrative/D.java
@@ -0,0 +1,423 @@
+package org.grails.datastore.gorm.neo4j.javatools.administrative;
+
+import org.grails.datastore.gorm.neo4j.parsers.Char;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ This class is part of the Java Tools (see http://mpii.de/yago-naga/javatools).
+ It is licensed under the Creative Commons Attribution License 
+ (see http://creativecommons.org/licenses/by/3.0) by 
+ the YAGO-NAGA team (see http://mpii.de/yago-naga).
+ 
+ 
+ 
+
+ 
+ This class provides convenience methods for Input/Output.
+ Allows to do basic I/O with easy procedure calls
+ -- nearly like in normal programming languages.
+ Furthermore, the class provides basic set operations for EnumSets, NULL-safe
+ comparisons and adding to maps.<BR>
+ Example:
+ <PRE>
+ D.p("This is an easy way to write a string");
+ // And this is an easy way to read one:
+ String s=D.r();
+ 
+ // Here is a cool way to print something inline
+ computeProduct(factor1,(Integer)D.p(factor2));
+ 
+ // Here are some tricks with enums
+ enum T {a,b,c};
+ EnumSet&lt;T> i=D.intersection(EnumSet.of(T.a,T.b),EnumSet.of(T.b,T.c));
+ EnumSet&lt;T> u=D.union(EnumSet.of(T.a,T.b),EnumSet.of(T.b,T.c));
+ 
+ // Here is how to compare things, even if they are NULL
+ D.compare(object1, object2);
+ 
+ // Here is how to add something to maps that contain lists
+ Map&lt;String,List&lt;String>> string2list=new TreeMap&lt;String,List&lt;String>>();
+ D.addKeyValue(string2list,"key","new list element",ArrayList.class); 
+ // now, the map contains "key" -> [ "new list element" ]
+ D.addKeyValue(string2list,"key","again a new list element",ArrayList.class);
+ // now, the map contains "key" -> [ "new list element", "again a new list element" ]  
+
+ // Here is how to add something to maps that contain integers
+ Map&lt;String,Integer> string2list=new TreeMap&lt;String,Integer>();
+ D.addKeyValue(string2list,"key",7); // map now contains "key" -> 7
+ D.addKeyValue(string2list,"key",3); // map now contains "key" -> 10
+
+ </PRE>  
+ */
+public class D {
+
+  /** Indentation margin. All methods indent their output by indent spaces */
+  public static int indent = 0;
+
+  /** Prints <indent> spaces */
+  protected static void i() {
+    for (int i = 0; i < indent; i++)
+      System.out.print(" ");
+  }
+
+  /** Prints some Objects, returns them */
+  public static Object p(Object... a) {
+    pl(a);
+    System.out.println("");
+    if (a == null || a.length == 0) return (null);
+    if (a.length == 1) return (a[0]);
+    return (a);
+  }
+
+  /** Prints some Objects */
+  public static Object println(Object... a) {
+    return (p(a));
+  }
+
+  /** Prints some Objects on one line */
+  public static void pl(Object... a) {    
+    System.out.print(toString(a));
+  }
+
+  /** Prints an array of integers*/
+  public static int[] p(int[] a) {
+    i();
+    if (a == null) System.out.print("null-array");
+    else for (int i = 0; i < a.length; i++)
+      System.out.print(a[i] + ", ");
+    System.out.println("");
+    return (a);
+  }
+
+  /** Prints an array of doubles*/
+  public static double[] p(double[] a) {
+    i();
+    if (a == null) System.out.print("null-array");
+    else for (int i = 0; i < a.length; i++)
+      System.out.print(a[i] + ", ");
+    System.out.println("");
+    return (a);
+  }
+
+  /** Reads a line from the keyboard */
+  public static String r() {
+    String s = "";
+    i();
+    try {
+      s = new BufferedReader(new InputStreamReader(System.in)).readLine();
+    } catch (Exception whocares) {
+    }
+    return (s);
+  }
+
+  /** Reads a line from the keyboard */
+  public static String read() {
+    return (r());
+  }
+
+  /** Reads a long from the keyboard */
+  public static String read(String question) {
+    System.out.print(question+" ");
+    return (D.read());
+  }
+
+  /** Reads a long from the keyboard */
+  public static boolean readBoolean(String question) {
+    System.out.print(question+" ");
+    return (D.read().startsWith("y"));
+  }
+
+  /** Reads a long from the keyboard */
+  public static long readLong(String question) {
+    System.out.print(question);
+    return (Long.parseLong(D.r()));
+  }
+
+  /** Reads a double from the keyboard */
+  public static double readDouble(String question) {
+    System.out.print(question);
+    return (Double.parseDouble(D.r()));
+  }
+
+  /** Waits for a number of milliseconds */
+  public static void waitMS(long milliseconds) {
+    try {
+      Thread.sleep(milliseconds);
+    } catch (InterruptedException ex) {
+    }
+  }
+
+  /** Returns the intersection of two enumsets */
+  public static <E extends Enum<E>> EnumSet<E> intersection(EnumSet<E> s1, EnumSet<E> s2) {
+    // We have to clone, since retainAll modifies the set
+    EnumSet<E> s = s1.clone();
+    s.retainAll(s2);
+    // I tried coding this for arbitrary sets, but it failed because
+    // the interface Cloneable does not make sure that the clone-method
+    // is visible (!)
+    return (s);
+  }
+
+  /** Returns the union of two enumsets */
+  public static <E extends Enum<E>> EnumSet<E> union(EnumSet<E> s1, EnumSet<E> s2) {
+    EnumSet<E> s = s1.clone();
+    s.addAll(s2);
+    return (s);
+  }
+
+  /** Tells whether the intersection is non-empty */
+  public static <E extends Enum<E>> boolean containsOneOf(EnumSet<E> s1, EnumSet<E> s2) {
+    return (!intersection(s1, s2).isEmpty());
+  }
+
+  /** Exits with error code 0 */
+  public static void exit() {
+    System.exit(0);
+  }
+
+  /** Writes a line to a writer. Yes, this is possible */
+  public static void writeln(Writer out, Object s) throws IOException {
+    out.write(s.toString());
+    out.write("\n");
+  }
+
+  /** Writes a line to a writer. Yes, this is possible */
+  public static void writeln(OutputStream out, Object s) throws IOException {
+    String string = Char.encodeUTF8(s.toString());
+    for (int i = 0; i < string.length(); i++)
+      out.write(string.charAt(i));
+    out.write('\n');
+  }
+
+  /** Writes a line silently to a writer. */
+  public static void silentWriteln(Writer out, Object s) {
+    try {
+      out.write(s.toString());
+      out.write("\n");
+    } catch (Exception e) {
+    }
+  }
+
+  /** Executes a command */
+  public static void execute(String cmd, File folder) throws Exception {
+    Process p = Runtime.getRuntime().exec(cmd, null, folder);
+    BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
+    BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
+    String s1, s2 = null;
+    while (null != (s1 = bri.readLine()) || null != (s2 = bre.readLine())) {
+      if (s1 != null) System.out.println(s1);
+      if (s2 != null) System.err.println(s2);
+    }
+    p.waitFor();
+  }
+
+  /** Given a map that maps to collections, adds a new key/value pair or introduces the key*/
+  @SuppressWarnings({ "unchecked", "rawtypes" })
+  public static <K, V, C extends Collection<V>, L extends Collection> void addKeyValue(Map<K, C> map, K key, V value, Class<L> collectionType) {
+    C coll = map.get(key);
+    if (coll == null) {
+      try {
+        map.put(key, coll = (C) collectionType.newInstance());
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+    coll.add(value);
+  }
+
+  /** Given a map that maps to collections, adds a new key/value pair or introduces the key*/
+  @SuppressWarnings({ "rawtypes" })
+  public static <K, V, C extends Collection<V>, L extends Collection> void addKeyValues(Map<K, C> map, K key, C values, Class<L> collectionType) {
+    for(V val : values) addKeyValue(map,key,val,collectionType);
+  }
+  
+  /** Given a map that maps to integers, adds a new key/value pair or increases the counter*/
+  public static <K> void addKeyValue(Map<K, Integer> map, K key, int value) {
+    Integer coll = map.get(key);
+    if (coll == null) {
+      map.put(key, value);
+      return;
+
+    }
+    map.put(key, coll + value);
+  }
+
+  /** Given a map that maps to floats, adds a new key/value pair or increases the counter*/
+  public static <K> void addKeyValueFlt(Map<K, Float> map, K key, float value) {
+    Float coll = map.get(key);
+    if (coll == null) {
+      map.put(key, value);
+      return;
+    }
+    map.put(key, coll + value);    
+  }
+  
+  /** Given a map that maps to doubles, adds a new key/value pair or increases the counter*/
+  public static <K> void addKeyValueDbl(Map<K, Double> map, K key, double value) {
+    Double coll = map.get(key);
+    if (coll == null) {
+      map.put(key, value);
+      return;
+
+    }
+    map.put(key, coll + value);    
+  }
+  
+  /** Given a map that maps to comparable objects, sets a key to a given value iff the current value is null or smaller than the given value*/
+  public static <K ,V extends Comparable<V>> void setKeyValueIfGreaterThanCurrent(Map<K, V> map, K key, V value) {
+    V coll = map.get(key);
+    if (coll == null) {
+      map.put(key, value);
+      return;
+    }
+    if(coll.compareTo(value)<0)
+      map.put(key, value);    
+  }
+  
+
+  /** Returns the element of a map or 0*/
+  public static <K> int getOrZero(Map<K, Integer> map, K key) {
+    Integer i = map.get(key);
+    if (i == null) return (0);
+    return (i);
+  }
+
+  /** Returns the element of a map or 0*/
+  public static <K> double getOrZeroDouble(Map<K, Double> map, K key) {
+    Double i = map.get(key);
+    if (i == null) return (0);
+    return (i);
+  }
+  
+  /** Returns the element of a map or a default value*/
+  public static <K,V> V getOr(Map<K, V> map, K key, V defValue) {
+    V i = map.get(key);
+    if (i == null) return defValue;
+    return (i);
+  }
+
+  /** Returns a sorted list of the items*/
+  public static<T> List<T> sorted(final Map<T, Integer> map) {
+    List<T> list=new ArrayList<T>(map.keySet());
+    Collections.sort(list,new Comparator<T>(){
+
+      @Override
+      public int compare(T arg0, T arg1) {
+        return (map.get(arg1).compareTo(map.get(arg0)));
+      }});
+    return(list);
+  }
+  
+  /** Returns a sorted list of the items*/
+  public static<T> List<T> sortedDouble(final Map<T, Double> map) {
+    List<T> list=new ArrayList<T>(map.keySet());
+    Collections.sort(list,new Comparator<T>(){
+
+      @Override
+      public int compare(T arg0, T arg1) {
+        return (map.get(arg1).compareTo(map.get(arg0)));
+      }});
+    return(list);
+  }
+  
+  /** Returns true if two things are equal, including NULL */
+  public static <E> boolean equal(E s1, E s2) {
+    if (s1 == s2) return (true);
+    if (s1 == null) return (false);
+    if (s2 == null) return (false);
+    return (s1.equals(s2));
+  }
+
+  /** Compares two things, including NULL */
+  public static <E extends Comparable<E>> int compare(E s1, E s2) {
+    if (s1 == s2) return (0);
+    if (s1 == null) return (-1);
+    if (s2 == null) return (1);
+    return (s1.compareTo(s2));
+  }
+
+  /** Compares pairs of comparable things (a1,a2,b1,b2,...), including NULL */
+  @SuppressWarnings({ "unchecked", "rawtypes" })
+  public static int comparePairs(Object... o) {
+    for (int i = 0; i < o.length; i += 2) {
+      int c = compare((Comparable) o[i], (Comparable) o[i + 1]);
+      if (c != 0) return (c);
+    }
+    return (0);
+  }
+
+  /** Compares pairs of comparable things (a1,a2,b1,b2,...) for equality, including NULL */
+  public static boolean equalPairs(Object... o) {
+    for (int i = 0; i < o.length; i += 2) {
+      if (!equal(o[i], o[i + 1])) return (false);
+    }
+    return (true);
+  }
+
+  /** Returns the index of a thing in an array or -1*/
+  public static int indexOf(Object o, Object... os) {
+    for (int i = 0; i < os.length; i++) {
+      if (D.equal(os[i], o)) return (i);
+    }
+    return (-1);
+  }
+
+  /** TRUE if the first enum is before the second*/
+  public static <C extends Enum<C>> boolean smaller(Enum<C> e1, Enum<C> e2) {
+    return (e1.ordinal() < e2.ordinal());
+  }
+
+  /** Returns a reasonable String representation of a sequence of things. Handles arrays, deep arrays and NULL.*/
+  public static String toString(Object... o) {
+    if (o == null) {
+      return ("null");
+    }
+    StringBuilder b = new StringBuilder();
+    for (int i = 0; i < o.length; i++) {
+      if (o[i] == null) {
+        b.append("null");
+        continue;
+      }
+      if (o[i].getClass().isArray()) {
+        b.append("[");
+        if (((Object[]) o[i]).length != 0) {
+          for (Object obj : (Object[]) o[i]) {
+            b.append(toString(obj)).append(", ");
+          }
+        }
+        b.append("]");
+      } else {
+        b.append(o[i].toString());
+      }
+      if (i != o.length - 1) b.append(" ");
+    }
+    return (b.toString());
+  }
+  
+  /** Picks one element from a set or NULL*/
+  public static <T> T pick(Collection<T> set) {
+    if(set==null || set.isEmpty()) return(null);
+    return(set.iterator().next());
+  }
+  
+  /** Returns the size of the intersection*/
+  public static<T> int intersectionSize(Collection<T> c1, Collection<T> c2) {
+	  if(c1.size()>c2.size()) return(intersectionSize(c2,c1));
+	  int result=0;
+	  for(T t : c1) if(c2.contains(t)) result++;
+	  return(result);
+  }
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/Char.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/Char.java
new file mode 100644
index 0000000..8a5e5b9
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/Char.java
@@ -0,0 +1,1436 @@
+package org.grails.datastore.gorm.neo4j.parsers;
+
+import org.grails.datastore.gorm.neo4j.datatypes.FinalMap;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.Map;
+import java.util.TreeMap;
+
+
+/** 
+This class is part of the Java Tools (see http://mpii.de/yago-naga/javatools).
+It is licensed under the Creative Commons Attribution License 
+(see http://creativecommons.org/licenses/by/3.0) by 
+the YAGO-NAGA team (see http://mpii.de/yago-naga).
+  
+
+  
+
+  This class provides static methods to <I>decode, encode</I> and <I>normalize</I> Strings.<BR>
+  <B>Decoding</B> converts the following codes to Java 16-bit characters (<TT>char</TT>):
+  <UL>
+   <LI>all HTML ampersand codes (like &amp;nbsp;) as specified by the W3C
+   <LI>all backslash codes (like \ b) as specified by the Java language specification
+   <LI>all percentage codes (like %2C) as used in URLs and E-Mails
+   <LI>all UTF-8 codes (like Ä«) as specified in Wikipedia
+  </UL>
+  <P>
+  <B>Encoding</B> is the inverse operation. It takes a Java 16-bit character (<TT>char</TT>) and
+  outputs its encoding in HTML, as a backslash code, as a percentage code or in UTF8.
+  <P>
+  <B>Normalization</B> converts the following Unicode characters (Java 16-bit <TT>char</TT>s)
+  to ASCII-characters in the range 0x20-0x7F:
+  <UL>
+   <LI>all ASCII control characters (0x00-0x1F)
+   <LI>all Latin-1 characters (0x80-0xFF) to the closest transliteration
+   <LI>all Latin Extended-A characters (0x100-0x17F) to the closest transliteration
+   <LI>all Greek characters (0x374-0x3D6) to the closest transliteration as specified in Wikipedia
+   <LI>all General-Punctuation characters (0x2016-0x2055) to the closest ASCII punctuation
+   <LI>most mathematical symbols (in the range of 0x2000) to the common program code identifier or text
+   <LI>all ligatures (0xFB00-0xFB06, the nasty things you get when you copy/paste from PDFs) to
+       the separate characters
+  </UL>
+  <P>
+  <CENTER><H3>Usage</H3></CENTER>
+  <P>
+  <B>Decoding</B> is done by methods that "eat" a code from the string.
+  They require as an additional parameter an integer array of length 1,
+  in which they store the length of the code that they chopped off.<BR>
+  Example:
+  <PRE>
+     int[] eatLength=new int[1];
+     char c=eatPercentage("%2Cblah blah",eatLength);
+     -->  c=','
+          eatLength[0]=3  // the code was 3 characters long
+  </PRE>
+  There is a static integer array Char.eatLength, which you can use for this purpose.
+  The methods store 0 in case the String does not start with the correct code.
+  They store -1 in case the String starts with a corrupted code. Of course, you can
+  use the <TT>eat...</TT> methods also to decode one single code. There are methods
+  <TT>decode...</TT> that decode the percentage code, the UTF8-codes, the backslash codes
+  or the Ampersand codes, respectively. 
+  The method <TT>decode(String)</TT> decodes all codes of a String.<BR>
+  Example:
+  <PRE>
+     decode("This String contains some codes: &amp;amp; %2C \ u0041");
+     --> "This String contains some codes: &amp; , A"
+  </PRE>
+  <P>
+  <B>Normalization</B> is done by the method <TT>normalize(int c)</TT>. It converts a Unicode 
+  character (a 16-bit Java character <TT>char</TT>)
+  to a sequence of normal characters (i.e. characters in the range 0x20-0x7F). 
+  The transliteration may consist of multiple chars (e.g. for umlauts) and also of no
+  chars at all (e.g. for Unicode Zero-Space-Characters). <BR>
+  Example:
+  <PRE>
+    normalize('&auml;');
+    --> "ae"
+  </PRE>  
+  The method <TT>normalize(String)</TT>  normalizes all characters in a String.<BR>
+  Example:
+  <PRE>
+     normalize("This String contains the umlauts �, � and �");
+     -->  "This String contains the umlauts Ae, Oe and Ue"
+  </PRE>
+  If the method cannot find a normalization, it calls defaultNormalizer.apply(char c).
+  Decoding and normalizing can be combined by the method decodeAndNormalize(String s).
+  <P>
+  <B>Encoding</B> is done by methods called <TT>encode...(char)</TT>. These methods take a character
+  and transform it to a UTF8 code, a percentage code, an ampersand code or a backslash code,
+  respectively. If the character is normal (i.e. in the range 0x20-0x7F), they simply return the input
+  character without any change.<BR>
+  Example:
+  <PRE>
+     encodePercentage('�');
+     -->  "%C4"
+  </PRE>  
+  There are also methods that work on entire Strings<BR>
+  Example:
+  <PRE>
+     encodePercentage("This String contains the umlauts �, � and �");
+     -->  "This String contains the umlauts %C4, %D6 and %DC;"
+  </PRE>  
+  <P>
+  Last, this class provides the character categorization for URIs, as given in
+  http://tools.ietf.org/html/rfc3986 . It also provides a method to encode only those
+  characters that are not valid path component characters<BR>
+  Example:
+  <PRE>
+     isReserved(';');
+     -->  true
+     encodeURIPathComponent("a: b")
+     -->  "a:%20b"
+  </PRE>    
+ */
+public class Char {
+
+  /** Defines just one function from an int to a String */
+  public interface Char2StringFn {
+
+    /** Function from a char to a String */
+    String apply(char c);
+  }
+
+  /** Called by normalize(int) in case the character cannot be normalized.
+   * The default implementation returns UNKNOWN.
+   * Feel free to create a new Char2StringFn and assign it to defaultNormalizer. */
+  public static Char2StringFn defaultNormalizer = new Char2StringFn() {
+
+    public String apply(char c) {
+      return (UNKNOWN);
+    }
+  };
+
+  /** String returned by the default implementation of defaultNormalizer, "[?]"*/
+  public static String UNKNOWN = "[?]";
+
+  /** Maps a special character to a HTML ampersand sequence */
+  public static Map<Character, String> charToAmpersand = new FinalMap<Character, String>('&', "&amp;", '\'', "&apos;", '<', "&lt;", '>', "&gt;", '"', "&quot;");
+
+  /** Maps a special character to a backslash sequence */
+  public static Map<Character, String> charToBackslash= new FinalMap<Character, String>('\\', "\\\\", '\n', "\\n");
+
+  /** Maps HTML ampersand sequences to strings */
+  public static Map<String, Character> ampersandMap = new FinalMap<String, Character>("nbsp", (char) 160, "iexcl", (char) 161, "cent", (char) 162, "pound", (char) 163, "curren", (char) 164, "yen", (char) 165, "brvbar", (char) 166, "sect",
+      (char) 167, "uml", (char) 168, "copy", (char) 169, "ordf", (char) 170, "laquo", (char) 171, "not", (char) 172, "shy", (char) 173, "reg", (char) 174, "macr", (char) 175, "deg", (char) 176, "plusmn", (char) 177, "sup2", (char) 178, "sup3",
+      (char) 179, "acute", (char) 180, "micro", (char) 181, "para", (char) 182, "middot", (char) 183, "cedil", (char) 184, "sup1", (char) 185, "ordm", (char) 186, "raquo", (char) 187, "frac14", (char) 188, "frac12", (char) 189, "frac34", (char) 190,
+      "iquest", (char) 191, "Agrave", (char) 192, "Aacute", (char) 193, "Acirc", (char) 194, "Atilde", (char) 195, "Auml", (char) 196, "Aring", (char) 197, "AElig", (char) 198, "Ccedil", (char) 199, "Egrave", (char) 200, "Eacute", (char) 201,
+      "Ecirc", (char) 202, "Euml", (char) 203, "Igrave", (char) 204, "Iacute", (char) 205, "Icirc", (char) 206, "Iuml", (char) 207, "ETH", (char) 208, "Ntilde", (char) 209, "Ograve", (char) 210, "Oacute", (char) 211, "Ocirc", (char) 212, "Otilde",
+      (char) 213, "Ouml", (char) 214, "times", (char) 215, "Oslash", (char) 216, "Ugrave", (char) 217, "Uacute", (char) 218, "Ucirc", (char) 219, "Uuml", (char) 220, "Yacute", (char) 221, "THORN", (char) 222, "szlig", (char) 223, "agrave",
+      (char) 224, "aacute", (char) 225, "acirc", (char) 226, "atilde", (char) 227, "auml", (char) 228, "aring", (char) 229, "aelig", (char) 230, "ccedil", (char) 231, "egrave", (char) 232, "eacute", (char) 233, "ecirc", (char) 234, "euml",
+      (char) 235, "igrave", (char) 236, "iacute", (char) 237, "icirc", (char) 238, "iuml", (char) 239, "eth", (char) 240, "ntilde", (char) 241, "ograve", (char) 242, "oacute", (char) 243, "ocirc", (char) 244, "otilde", (char) 245, "ouml",
+      (char) 246, "divide", (char) 247, "oslash", (char) 248, "ugrave", (char) 249, "uacute", (char) 250, "ucirc", (char) 251, "uuml", (char) 252, "yacute", (char) 253, "thorn", (char) 254, "yuml", (char) 255, "fnof", (char) 402, "Alpha",
+      (char) 913, "Beta", (char) 914, "Gamma", (char) 915, "Delta", (char) 916, "Epsilon", (char) 917, "Zeta", (char) 918, "Eta", (char) 919, "Theta", (char) 920, "Iota", (char) 921, "Kappa", (char) 922, "Lambda", (char) 923, "Mu", (char) 924, "Nu",
+      (char) 925, "Xi", (char) 926, "Omicron", (char) 927, "Pi", (char) 928, "Rho", (char) 929, "Sigma", (char) 931, "Tau", (char) 932, "Upsilon", (char) 933, "Phi", (char) 934, "Chi", (char) 935, "Psi", (char) 936, "Omega", (char) 937, "alpha",
+      (char) 945, "beta", (char) 946, "gamma", (char) 947, "delta", (char) 948, "epsilon", (char) 949, "zeta", (char) 950, "eta", (char) 951, "theta", (char) 952, "iota", (char) 953, "kappa", (char) 954, "lambda", (char) 955, "mu", (char) 956, "nu",
+      (char) 957, "xi", (char) 958, "omicron", (char) 959, "pi", (char) 960, "rho", (char) 961, "sigmaf", (char) 962, "sigma", (char) 963, "tau", (char) 964, "upsilon", (char) 965, "phi", (char) 966, "chi", (char) 967, "psi", (char) 968, "omega",
+      (char) 969, "thetasym", (char) 977, "upsih", (char) 978, "piv", (char) 982, "bull", (char) 8226, "hellip", (char) 8230, "prime", (char) 8242, "Prime", (char) 8243, "oline", (char) 8254, "frasl", (char) 8260, "weierp", (char) 8472, "image",
+      (char) 8465, "real", (char) 8476, "trade", (char) 8482, "alefsym", (char) 8501, "larr", (char) 8592, "uarr", (char) 8593, "rarr", (char) 8594, "darr", (char) 8595, "harr", (char) 8596, "crarr", (char) 8629, "lArr", (char) 8656, "uArr",
+      (char) 8657, "rArr", (char) 8658, "dArr", (char) 8659, "hArr", (char) 8660, "forall", (char) 8704, "part", (char) 8706, "exist", (char) 8707, "empty", (char) 8709, "nabla", (char) 8711, "isin", (char) 8712, "notin", (char) 8713, "ni",
+      (char) 8715, "prod", (char) 8719, "sum", (char) 8721, "minus", (char) 8722, "lowast", (char) 8727, "radic", (char) 8730, "prop", (char) 8733, "infin", (char) 8734, "ang", (char) 8736, "and", (char) 8743, "or", (char) 8744, "cap", (char) 8745,
+      "cup", (char) 8746, "int", (char) 8747, "there4", (char) 8756, "sim", (char) 8764, "cong", (char) 8773, "asymp", (char) 8776, "ne", (char) 8800, "equiv", (char) 8801, "le", (char) 8804, "ge", (char) 8805, "sub", (char) 8834, "sup",
+      (char) 8835, "nsub", (char) 8836, "sube", (char) 8838, "supe", (char) 8839, "oplus", (char) 8853, "otimes", (char) 8855, "perp", (char) 8869, "sdot", (char) 8901, "lceil", (char) 8968, "rceil", (char) 8969, "lfloor", (char) 8970, "rfloor",
+      (char) 8971, "lang", (char) 9001, "rang", (char) 9002, "loz", (char) 9674, "spades", (char) 9824, "clubs", (char) 9827, "hearts", (char) 9829, "diams", (char) 9830, "quot", (char) 34, "amp", (char) 38, "lt", (char) 60, "gt", (char) 62,
+      "OElig", (char) 338, "oelig", (char) 339, "Scaron", (char) 352, "scaron", (char) 353, "Yuml", (char) 376, "circ", (char) 710, "tilde", (char) 732, "ensp", (char) 8194, "emsp", (char) 8195, "thinsp", (char) 8201, "zwnj", (char) 8204, "zwj",
+      (char) 8205, "lrm", (char) 8206, "rlm", (char) 8207, "ndash",
+      (char) 8211, //0x2013
+      "mdash", (char) 8212, "lsquo", (char) 8216, "rsquo", (char) 8217, "sbquo", (char) 8218, "ldquo", (char) 8220, "rdquo", (char) 8221, "bdquo", (char) 8222, "dagger", (char) 8224, "Dagger", (char) 8225, "permil", (char) 8240, "lsaquo",
+      (char) 8249, "rsaquo", (char) 8250, "euro", (char) 8364, "apos", '\'');
+
+  /** Maps characters to normalizations */
+  public static Map<Character, String> normalizeMap = new TreeMap<Character, String>();
+  static {
+    Object[] o = new Object[] {
+        // ASCII
+        (char) 7,
+        "BEEP",
+        (char) 9,
+        " ",
+        (char) 10,
+        "\n",
+
+        // Latin-1
+        (char) 160,
+        " ",
+        (char) 161,
+        "!",
+        (char) 162,
+        "cent",
+        (char) 163,
+        "pound",
+        (char) 164,
+        "currency",
+        (char) 165,
+        "yen",
+        (char) 166,
+        "|",
+        (char) 167,
+        "/",
+        (char) 169,
+        "(c)",
+        (char) 170,
+        "^a",
+        (char) 171,
+        "\"",
+        (char) 172,
+        "~",
+        (char) 173,
+        "",
+        (char) 174,
+        "(R)",
+        (char) 176,
+        "degree",
+        (char) 177,
+        "+/-",
+        (char) 178,
+        "^2",
+        (char) 179,
+        "^3",
+        (char) 180,
+        "'",
+        (char) 181,
+        "mu",
+        (char) 182,
+        "P",
+        (char) 183,
+        ".",
+        (char) 184,
+        ",",
+        (char) 185,
+        "^1",
+        (char) 186,
+        "^o",
+        (char) 187,
+        "\"",
+        (char) 188,
+        "1/4",
+        (char) 189,
+        "1/2",
+        (char) 190,
+        "3/4",
+        (char) 191,
+        "?",
+        (char) 0xC4,
+        "Ae",
+        (char) 0xD6,
+        "Oe",
+        (char) 0xDC,
+        "Ue",
+        (char) 0xDF,
+        "ss",
+        (char) 0xC6,
+        "Ae",
+        (char) 0xC7,
+        "C",
+        (char) 0xD0,
+        "D",
+        (char) 0xD1,
+        "N",
+        (char) 0xD7,
+        "x",
+        (char) 0xDD,
+        "Y",
+        (char) 0xDE,
+        "b",
+        (char) 0xF7,
+        "/",
+        (char) 0xFF,
+        "y",
+
+        // Latin Extended-A
+        (char) 0x132,
+        "IJ",
+        (char) 0x134,
+        "J",
+        (char) 0x170,
+        "Ue",
+        (char) 0x174,
+        "W",
+        (char) 0x17F,
+        "f",
+
+        // Greek
+        (char) 0x374,
+        "'",
+        (char) 0x375,
+        ",",
+        (char) 0x37A,
+        ",",
+        (char) 0x37E,
+        ";",
+        (char) 0x384,
+        "'",
+        (char) 0x385,
+        "'",
+        (char) 0x386,
+        "A",
+        (char) 0x387,
+        ".",
+        (char) 0x388,
+        "E",
+        (char) 0x380,
+        "I",
+        (char) 0x38C,
+        "O",
+        (char) 0x38E,
+        "Y",
+        (char) 0x38F,
+        "O",
+        (char) 0x390,
+        "i",
+        (char) 215,
+        "*",
+        (char) 913,
+        "A",
+        (char) 914,
+        "B",
+        (char) 915,
+        "G",
+        (char) 916,
+        "D",
+        (char) 917,
+        "E",
+        (char) 918,
+        "Z",
+        (char) 919,
+        "E",
+        (char) 920,
+        "Th",
+        (char) 921,
+        "I",
+        (char) 922,
+        "K",
+        (char) 923,
+        "L",
+        (char) 924,
+        "M",
+        (char) 925,
+        "N",
+        (char) 926,
+        "X",
+        (char) 927,
+        "O",
+        (char) 928,
+        "P",
+        (char) 929,
+        "R",
+        (char) 931,
+        "S",
+        (char) 932,
+        "T",
+        (char) 933,
+        "Y",
+        (char) 934,
+        "Ph",
+        (char) 935,
+        "Ch",
+        (char) 936,
+        "Ps",
+        (char) 937,
+        "O",
+        (char) 977,
+        "th",
+        (char) 978,
+        "y",
+        (char) 982,
+        "pi",
+
+        // General Punctuation
+        (char) 0x2013,
+        "-",
+        (char) 0x2016,
+        "||",
+        (char) 0x2017,
+        "_",
+        (char) 0x2020,
+        "+",
+        (char) 0x2021,
+        "++",
+        (char) 0x2022,
+        "*",
+        (char) 0x2023,
+        "*",
+        (char) 0x2024,
+        ".",
+        (char) 0x2025,
+        "..",
+        (char) 0x2026,
+        "...",
+        (char) 0x2027,
+        ".",
+        (char) 0x2028,
+        "\n",
+        (char) 0x2030,
+        "/1000",
+        (char) 0x2031,
+        "/10000",
+        (char) 0x2032,
+        "'",
+        (char) 0x2033,
+        "''",
+        (char) 0x2034,
+        "'''",
+        (char) 0x2035,
+        "'",
+        (char) 0x2036,
+        "''",
+        (char) 0x2037,
+        "'''",
+        (char) 0x2038,
+        "^",
+        (char) 0x2039,
+        "\"",
+        (char) 0x203A,
+        "\"",
+        (char) 0x203B,
+        "*",
+        (char) 0x203C,
+        "!!",
+        (char) 0x203D,
+        "?!",
+        (char) 0x2041,
+        ",",
+        (char) 0x2042,
+        "***",
+        (char) 0x2043,
+        "-",
+        (char) 0x2044,
+        "/",
+        (char) 0x2045,
+        "[",
+        (char) 0x2046,
+        "]",
+        (char) 0x2047,
+        "??",
+        (char) 0x2048,
+        "?!",
+        (char) 0x2049,
+        "!?",
+        (char) 0x204A,
+        "-",
+        (char) 0x204B,
+        "P",
+        (char) 0x204C,
+        "<",
+        (char) 0x204D,
+        ">",
+        (char) 0x204F,
+        ";",
+        (char) 0x2050,
+        "-",
+        (char) 0x2051,
+        "**",
+        (char) 0x2052,
+        "./.",
+        (char) 0x2053,
+        "~",
+        (char) 0x2054,
+        "_",
+        (char) 0x2055,
+        "_",
+
+        // Mathematical symbols
+        (char) 8465,
+        "I",
+        (char) 8476,
+        "R",
+        (char) 8482,
+        "(TM)",
+        (char) 8501,
+        "a",
+        (char) 8592,
+        "<-",
+        (char) 8593,
+        "^",
+        (char) 8594,
+        "->",
+        (char) 8595,
+        "v",
+        (char) 8596,
+        "<->",
+        (char) 8629,
+        "<-'",
+        (char) 8656,
+        "<=",
+        (char) 8657,
+        "^",
+        (char) 8658,
+        "=>",
+        (char) 8659,
+        "v",
+        (char) 8660,
+        "<=>",
+        (char) 8704,
+        "FOR ALL",
+        (char) 8706,
+        "d",
+        (char) 8707,
+        "EXIST",
+        (char) 8709,
+        "{}",
+        (char) 8712,
+        "IN",
+        (char) 8713,
+        "NOT IN",
+        (char) 8715,
+        "CONTAINS",
+        (char) 8719,
+        "PRODUCT",
+        (char) 8721,
+        "SUM",
+        (char) 8722,
+        "-",
+        (char) 8727,
+        "*",
+        (char) 8730,
+        "SQRT",
+        (char) 8733,
+        "~",
+        (char) 8734,
+        "INF",
+        (char) 8736,
+        "angle",
+        (char) 8743,
+        "&",
+        (char) 8744,
+        "|",
+        (char) 8745,
+        "INTERSECTION",
+        (char) 8746,
+        "UNION",
+        (char) 8747,
+        "INTEGRAL",
+        (char) 8756,
+        "=>",
+        (char) 8764,
+        "~",
+        (char) 8773,
+        "~=",
+        (char) 8776,
+        "~=",
+        (char) 8800,
+        "!=",
+        (char) 8801,
+        "==",
+        (char) 8804,
+        "=<",
+        (char) 8805,
+        ">=",
+        (char) 8834,
+        "SUBSET OF",
+        (char) 8835,
+        "SUPERSET OF",
+        (char) 8836,
+        "NOT SUBSET OF",
+        (char) 8838,
+        "SUBSET OR EQUAL",
+        (char) 8839,
+        "SUPERSET OR EQUAL",
+        (char) 8853,
+        "(+)",
+        (char) 8855,
+        "(*)",
+        (char) 8869,
+        "_|_",
+        (char) 8901,
+        "*",
+        (char) 8364,
+        "EUR",
+
+        // Ligatures
+        (char) 0xFB00,
+        "ff",
+        (char) 0xFB01,
+        "fi",
+        (char) 0xFB02,
+        "fl",
+        (char) 0xFB03,
+        "ffi",
+        (char) 0xFB04,
+        "ffl",
+        (char) 0xFB05,
+        "ft",
+        (char) 0xFB06,
+        "st" };
+    for (int i = 0; i < o.length; i += 2)
+      normalizeMap.put((Character) o[i], (String) o[i + 1]);
+  }
+
+  /** Normalizes a character to a String of characters in the range 0x20-0x7F.
+   *  Returns a String, because some characters are
+    * normalized to multiple characters (e.g. umlauts) and
+    * some characters are normalized to zero characters (e.g. special Unicode space chars).
+    * Returns null for the EndOfFile character -1 */
+  public static String normalize(int c) {
+    // EOF
+    if (c == -1) return (null);
+
+    // ASCII chars
+    if (c >= ' ' && c <= 128) return ("" + (char) c);
+
+    // Upper case
+    boolean u = Character.isUpperCase(c);
+    char cu = (char) Character.toUpperCase(c);
+
+    // Check map
+    if (normalizeMap.get(cu) != null) return (u ? normalizeMap.get(cu) : normalizeMap.get(cu).toLowerCase());
+
+    // ASCII
+    if (c < ' ') return ("");
+
+    // Latin-1
+    if (cu >= 0xC0 && cu <= 0xC5) return (u ? "A" : "a");
+    if (cu >= 0xC8 && cu <= 0xCB) return (u ? "E" : "e");
+    if (cu >= 0xCC && cu <= 0xCF) return (u ? "I" : "i");
+    if (cu >= 0xD2 && cu <= 0xD8) return (u ? "O" : "o");
+    if (cu >= 0x80 && cu <= 0xA0) return (" ");
+
+    //  Latin Extended-A
+    if (cu >= 0x100 && cu <= 0x105) return (u ? "A" : "a");
+    if (cu >= 0x106 && cu <= 0x10D) return (u ? "C" : "c");
+    if (cu >= 0x10E && cu <= 0x111) return (u ? "D" : "d");
+    if (cu >= 0x112 && cu <= 0x11B) return (u ? "E" : "e");
+    if (cu >= 0x11C && cu <= 0x123) return (u ? "G" : "g");
+    if (cu >= 0x124 && cu <= 0x127) return (u ? "H" : "h");
+    if (cu >= 0x128 && cu <= 0x131) return (u ? "I" : "i");
+    if (cu >= 0x136 && cu <= 0x138) return (u ? "K" : "k");
+    if (cu >= 0x139 && cu <= 0x142) return (u ? "L" : "l");
+    if (cu >= 0x143 && cu <= 0x14B) return (u ? "N" : "n");
+    if (cu >= 0x14C && cu <= 0x14F) return (u ? "O" : "o");
+    if (cu >= 0x150 && cu <= 0x153) return (u ? "Oe" : "oe");
+    if (cu >= 0x156 && cu <= 0x159) return (u ? "R" : "r");
+    if (cu >= 0x15A && cu <= 0x161) return (u ? "S" : "s");
+    if (cu >= 0x161 && cu <= 0x167) return (u ? "T" : "t");
+    if (cu >= 0x176 && cu <= 0x178) return (u ? "Y" : "y");
+    if (cu >= 0x179 && cu <= 0x17E) return (u ? "Z" : "z");
+
+    // General Punctuation
+    if (cu >= 0x2000 && cu <= 0x200A) return (" ");
+    if (cu >= 0x200B && cu <= 0x200F) return ("");
+    if (cu >= 0x2010 && cu <= 0x2015) return ("--");
+    if (cu >= 0x2018 && cu <= 0x201B) return ("'");
+    if (cu >= 0x201C && cu <= 0x201F) return ("\"");
+    if (cu >= 0x2029 && cu <= 0x202F) return (" ");
+    if (cu >= 0x203E && cu <= 0x2040) return ("-");
+    if (cu >= 0x2056 && cu <= 0x205E) return (".");
+
+    return (defaultNormalizer.apply((char) c));
+  }
+
+  /** Eats a String of the form "%xx" from a string, where
+   * xx is a hexadecimal code. If xx is a UTF8 code start, 
+   * tries to complete the UTF8-code and decodes it.*/
+  public static char eatPercentage(String a, int[] n) {
+    // Length 0
+    if (!a.startsWith("%") || a.length() < 3) {
+      n[0] = 0;
+      return ((char) 0);
+    }
+    char c;
+    // Try to parse first char
+    try {
+      c = (char) Integer.parseInt(a.substring(1, 3), 16);
+    } catch (Exception e) {
+      n[0] = -1;
+      return ((char) 0);
+    }
+    // For non-UTF8, return the char    
+    int len = Utf8Length(c);
+    n[0] = 3;
+    if (len <= 1) return (c);
+    // Else collect the UTF8
+    String dec = "" + c;
+    for (int i = 1; i < len; i++) {
+      try {
+        dec += (char) Integer.parseInt(a.substring(1 + i * 3, 3 + i * 3), 16);
+      } catch (Exception e) {
+        return (c);
+      }
+    }
+    // Try to decode the UTF8
+    int[] eatLength = new int[1];
+    char utf8 = eatUtf8(dec, eatLength);
+    if (eatLength[0] != len) return (c);
+    n[0] = len * 3;
+    return (utf8);
+  }
+
+  /** Eats an HTML ampersand code from a String*/
+  public static char eatAmpersand(String a, int[] n) {
+    n[0] = 0;
+    if (!a.startsWith("&")) return ((char) 0);
+    // Seek to ';'
+    // We also accept spaces and the end of the String as a delimiter
+    while (n[0] < a.length() && !Character.isSpaceChar(a.charAt(n[0])) && a.charAt(n[0]) != ';')
+      n[0]++;
+    if (n[0] <= 1) {
+      n[0] = -1;
+      return ((char) 0);
+    }
+    if (n[0] < a.length() && a.charAt(n[0]) == ';') {
+      a = a.substring(1, n[0]);
+      n[0]++;
+    } else {
+      a = a.substring(1, n[0]);
+    }
+    // Hexadecimal characters
+    if (a.startsWith("#x")) {
+      try {
+        return ((char) Integer.parseInt(a.substring(2), 16));
+      } catch (Exception e) {
+        n[0] = -1;
+        return ((char) 0);
+      }
+    }
+    // Decimal characters
+    if (a.startsWith("#")) {
+      try {
+        return ((char) Integer.parseInt(a.substring(1)));
+      } catch (Exception e) {
+        n[0] = -1;
+        return ((char) 0);
+      }
+    }
+    // Others
+    if (ampersandMap.get(a) != null) return (ampersandMap.get(a));
+    else if (ampersandMap.get(a.toLowerCase()) != null) return (ampersandMap.get(a.toLowerCase()));
+    n[0] = -1;
+    return ((char) 0);
+  }
+
+  /** Tells from the first UTF-8 code character how long the code is.
+   * Returns -1 if the character is not an UTF-8 code start.
+   * Returns 1 if the character is ASCII<128*/
+  public static int Utf8Length(char c) {
+    // 0xxx xxxx
+    if ((c & 0x80) == 0x00) return (1);
+    // 110x xxxx
+    if ((c & 0xE0) == 0xC0) return (2);
+    // 1110 xxxx
+    if ((c & 0xF0) == 0xE0) return (3);
+    // 1111 0xxx
+    if ((c & 0xF8) == 0xF0) return (4);
+    return (-1);
+  }
+
+  /** Eats a UTF8 code from a String. There is also a built-in way in Java that converts
+   * UTF8 to characters and back, but it does not work with all characters. */
+  public static char eatUtf8(String a, int[] n) {
+    if (a.length() == 0) {
+      n[0] = 0;
+      return ((char) 0);
+    }
+    n[0] = Utf8Length(a.charAt(0));
+    if (a.length() >= n[0]) {
+      switch (n[0]) {
+        case 1:
+          return (a.charAt(0));
+        case 2:
+          if ((a.charAt(1) & 0xC0) != 0x80) break;
+          return ((char) (((a.charAt(0) & 0x1F) << 6) + (a.charAt(1) & 0x3F)));
+        case 3:
+          if ((a.charAt(1) & 0xC0) != 0x80 || (a.charAt(2) & 0xC0) != 0x80) break;
+          return ((char) (((a.charAt(0) & 0x0F) << 12) + ((a.charAt(1) & 0x3F) << 6) + ((a.charAt(2) & 0x3F))));
+        case 4:
+          if ((a.charAt(1) & 0xC0) != 0x80 || (a.charAt(2) & 0xC0) != 0x80 || (a.charAt(3) & 0xC0) != 0x80) break;
+          return ((char) (((a.charAt(0) & 0x07) << 18) + ((a.charAt(1) & 0x3F) << 12) + ((a.charAt(2) & 0x3F) << 6) + ((a.charAt(3) & 0x3F))));
+      }
+    }
+    n[0] = -1;
+    return ((char) 0);
+  }
+
+  /** Decodes all UTF8 characters in the string*/
+  public static String decodeUTF8(String s) {
+    StringBuilder result = new StringBuilder();
+    int[] eatLength = new int[1];
+    while (s.length() != 0) {
+      char c = eatUtf8(s, eatLength);
+      if (eatLength[0] != -1) {
+        result.append(c);
+        s = s.substring(eatLength[0]);
+      } else {
+        result.append(s.charAt(0));
+        s = s.substring(1);
+      }
+    }
+    return (result.toString());
+  }
+
+  /** Decodes all percentage characters in the string*/
+  public static String decodePercentage(String s) {
+    StringBuilder result = new StringBuilder();
+    int[] eatLength = new int[1];
+    while (s.length() != 0) {
+      char c = eatPercentage(s, eatLength);
+      if (eatLength[0] > 1) {
+        result.append(c);
+        s = s.substring(eatLength[0]);
+      } else {
+        result.append(s.charAt(0));
+        s = s.substring(1);
+      }
+    }
+    return (result.toString());
+  }
+
+  /** Fabian: This method cannot decode numeric hexadecimal ampersand codes. What is its purpose? TODO*/
+  public static String decodeAmpersand_UNKNOWN(String s) {
+    if (s == null) {
+      return null;
+    }
+    StringBuffer sb = new StringBuffer(s.length());
+    while (s != null && s.length() != 0) {
+      int i = s.indexOf("&");
+      if (i == -1) {
+        sb.append(s);
+        s = null;
+      } else {
+        boolean space = false;
+        boolean end = false;
+        sb.append(s.substring(0, i));
+        s = s.substring(i);
+        int j1 = s.indexOf(";");
+        int j2 = s.indexOf(" ");
+        int j = -1;
+        if (j1 == -1 || j2 == -1) {
+          if (j1 == -1 && j2 == -1) {
+            end = true;
+            j = s.length();
+          } else if (j1 == -1) {
+            j = j2;
+          } else if (j2 == -1) {
+            j = j1;
+          }
+        } else if (j1 < j2) {
+          j = j1;
+        } else if (j1 > j2) {
+          j = j2;
+          space = true;
+        }
+        String a = s.substring(1, j);
+        if (ampersandMap.get(a) != null) {
+          sb.append(ampersandMap.get(a));
+          if (space) {
+            sb.append(' ');
+          }
+        } else if (a.startsWith("#")) {
+          try {
+            sb.append(((char) Integer.parseInt(a.substring(1))));
+          } catch (Exception e) {
+            sb.append(a);
+          }
+          if (space) {
+            sb.append(' ');
+          }
+        } else {
+          if (end) {
+            sb.append(s.substring(0, j));
+          } else {
+            sb.append(s.substring(0, j + 1));
+          }
+        }
+        if (end) {
+          s = s.substring(j);
+        } else {
+          s = s.substring(j + 1);
+        }
+      }
+    }
+    return sb.toString();
+  }
+
+  public static String decodeAmpersand(String s, PositionTracker posTracker) {
+    if (s == null) {
+      return null;
+    }
+    int pos = 0;
+    int difference;
+    StringBuffer sb = new StringBuffer(s.length());
+    while (s != null && s.length() != 0) {
+      int i = s.indexOf("&");
+      if (i == -1) {
+        sb.append(s);
+        s = null;
+      } else {
+        boolean space = false;
+        boolean end = false;
+        sb.append(s.substring(0, i));
+        s = s.substring(i);
+        pos += i;
+        int j1 = s.indexOf(";");
+        int j2 = s.indexOf(" ");
+        int j = -1;
+        if (j1 == -1 || j2 == -1) {
+          if (j1 == -1 && j2 == -1) {
+            end = true;
+            j = s.length();
+          } else if (j1 == -1) {
+            j = j2;
+          } else if (j2 == -1) {
+            j = j1;
+          }
+        } else if (j1 < j2) {
+          j = j1;
+        } else if (j1 > j2) {
+          j = j2;
+          space = true;
+        }
+        pos += (j + 1);
+        String a = s.substring(1, j);
+        if (ampersandMap.get(a) != null) {
+          sb.append(ampersandMap.get(a));
+          difference = 1 - (j + 1);
+          if (space) {
+            sb.append(' ');
+            difference++;
+          }
+          posTracker.addPositionChange(pos, difference);
+        } else {
+          if (end) {
+            sb.append(s.substring(0, j));
+          } else {
+            sb.append(s.substring(0, j + 1));
+          }
+        }
+        if (end) {
+          s = s.substring(j);
+        } else {
+          s = s.substring(j + 1);
+        }
+      }
+    }
+    posTracker.closeRun();
+    return sb.toString();
+  }
+
+  /** Decodes all ampersand sequences in the string*/
+  public static String decodeAmpersand(String s) {
+    if(s==null || s.indexOf('&')==-1) return(s);
+    StringBuilder result = new StringBuilder();
+    int[] eatLength = new int[1];// add this in order to multithread safe
+    while (s.length() != 0) {
+      char c = eatAmpersand(s, eatLength);
+      if (eatLength[0] > 1) {
+        result.append(c);
+        s = s.substring(eatLength[0]);
+      } else {
+        result.append(s.charAt(0));
+        s = s.substring(1);
+      }
+    }
+    return (result.toString());
+  }
+
+  /** Decodes all backslash characters in the string */
+  public static String decodeBackslash(String s) {
+	  if(s==null || s.indexOf('\\')==-1) return(s);
+    StringBuilder result = new StringBuilder();
+    int[] eatLength = new int[1];
+    while (s.length() != 0) {
+      char c = eatBackslash(s, eatLength);
+      if (eatLength[0] > 1) {
+        result.append(c);
+        s = s.substring(eatLength[0]);
+      } else {
+        result.append(s.charAt(0));
+        s = s.substring(1);
+      }
+    }
+    return (result.toString());
+  }
+
+  /** Used for encoding selected characters*/
+  public static interface Legal {
+	  public boolean isLegal(char c);
+  }
+  
+  /** Encodes with backslash all illegal characters*/
+  public static String encodeBackslash(CharSequence s, Legal legal) {
+	StringBuilder b=new StringBuilder((int)(s.length()*1.5));
+	for(int i=0;i<s.length();i++) {
+		if(legal.isLegal(s.charAt(i))) {
+			b.append(s.charAt(i));
+		} else {
+			if(charToBackslash.containsKey(s.charAt(i))) {
+				b.append(charToBackslash.get(s.charAt(i)));
+				continue;
+			}
+			b.append("\\u");
+		    String hex = Integer.toHexString(s.charAt(i));
+		    for(int j=0;j<4-hex.length();j++)
+		      b.append('0');
+		    b.append(hex);
+		}
+	}
+	return(b.toString());
+  }
+  
+  /** Eats a backslash sequence from a String */
+  public static char eatBackslash(String a, int[] n) {
+    if (!a.startsWith("\\")) {
+      n[0] = 0;
+      return ((char) 0);
+    }
+    // Unicodes BS u XXXX
+    if (a.startsWith("\\u")) {
+      try {
+        n[0] = 6;
+        return ((char) Integer.parseInt(a.substring(2, 6), 16));
+      } catch (Exception e) {
+        n[0] = -1;
+        return ((char) 0);
+      }
+    }
+    // Unicodes BS uu XXXX
+    if (a.startsWith("\\uu")) {
+      try {
+        n[0] = 7;
+        return ((char) Integer.parseInt(a.substring(3, 7), 16));
+      } catch (Exception e) {
+        n[0] = -1;
+        return ((char) 0);
+      }
+    }
+    // Classical escape sequences
+    if (a.startsWith("\\b")) {
+      n[0] = 2;
+      return ((char) 8);
+    }
+    if (a.startsWith("\\t")) {
+      n[0] = 2;
+      return ((char) 9);
+    }
+    if (a.startsWith("\\n")) {
+      n[0] = 2;
+      return ((char) 10);
+    }
+    if (a.startsWith("\\f")) {
+      n[0] = 2;
+      return ((char) 12);
+    }
+    if (a.startsWith("\\r")) {
+      n[0] = 2;
+      return ((char) 13);
+    }
+    if (a.startsWith("\\\\")) {
+      n[0] = 2;
+      return ('\\');
+    }
+    if (a.startsWith("\\\"")) {
+      n[0] = 2;
+      return ('"');
+    }
+    if (a.startsWith("\\'")) {
+      n[0] = 2;
+      return ('\'');
+    }
+    // Octal codes
+    n[0] = 1;
+    while (n[0] < a.length() && a.charAt(n[0]) >= '0' && a.charAt(n[0]) <= '8')
+      n[0]++;
+    if (n[0] == 1) {
+      n[0] = 0;
+      return ((char) 0);
+    }
+    try {
+      return ((char) Integer.parseInt(a.substring(1, n[0]), 8));
+    } catch (Exception e) {
+    }
+    n[0] = -1;
+    return ((char) 0);
+  }
+
+  /** Replaces all codes in a String by the 16 bit Unicode characters */
+  public static String decode(String s) {
+    StringBuilder b = new StringBuilder();
+    int[] eatLength = new int[1];
+    while (s.length() > 0) {
+      char c = eatPercentage(s, eatLength);
+      if (eatLength[0] <= 0) {
+        c = eatAmpersand(s, eatLength);
+        if (eatLength[0] <= 0) {
+          c = eatBackslash(s, eatLength);
+          if (eatLength[0] <= 0) {
+            c = eatUtf8(s, eatLength);
+            if (eatLength[0] <= 0) {
+              c = s.charAt(0);
+              eatLength[0] = 1;
+            }
+          }
+        }
+      }
+      b.append(c);
+      s = s.substring(eatLength[0]);
+    }
+    return (b.toString());
+  }
+
+  /** Encodes a character to UTF8 (if necessary)*/
+  public static String encodeUTF8(int c) {
+    if (c <= 0x7F) return ("" + (char) c);
+    if (c <= 0x7FF) return ("" + (char) (0xC0 + ((c >> 6) & 0x1F)) + (char) (0x80 + (c & 0x3F)));
+    if (c <= 0xFFFF) return ("" + (char) (0xE0 + ((c >> 12) & 0x0F)) + (char) (0x80 + ((c >> 6) & 0x3F)) + (char) (0x80 + (c & 0x3F)));
+    return ("" + c);
+  }
+
+  /** Encodes a character to a backslash code (if necessary)*/
+  public static String encodeBackslash(char c) {
+    if (isAlphanumeric(c) || c == ' ') return ("" + c);
+    String hex = Integer.toHexString(c);
+    while (hex.length() < 4)
+      hex = "0" + hex;
+    return ("\\u" + hex);
+  }
+
+  /** Encodes a character to a backslash code (if not alphanumeric)*/
+  public static String encodeBackslashToAlphanumeric(char c) {
+    if (isAlphanumeric(c) || c == '_') return ("" + c);
+    String hex = Integer.toHexString(c);
+    while (hex.length() < 4)
+      hex = "0" + hex;
+    return ("\\u" + hex);
+  }
+
+  /** Encodes a character to a backslash code (if not ASCII)*/
+  public static String encodeBackslashToASCII(char c) {
+    if (c >= 32 && c < 128 && c != '\\' && c != '"') return ("" + c);
+    String hex = Integer.toHexString(c);
+    while (hex.length() < 4)
+      hex = "0" + hex;
+    return ("\\u" + hex);
+  }
+
+  /** Encodes a character to an HTML-Ampersand code (if necessary)*/
+  public static String encodeAmpersand(char c) {
+    String s;
+    if (null != (s = charToAmpersand.get(c))) return (s);
+    if (c < 128 && c >= 32) return ("" + c);
+    else return ("&#" + ((int) c) + ";");
+  }
+
+  /** Encodes a character to an HTML-Ampersand code (if necessary)*/
+  public static String encodeAmpersandToAlphanumeric(char c) {
+    if (isAlphanumeric(c) || c == '_') return ("" + c);
+    return ("&#" + ((int) c) + ";");
+  }
+
+  /** Encodes a character to an Percentage code (if necessary).
+   * If the character is greater than 0x80, the character is converted to
+   * a UTF8-sequence and this sequence is encoded as percentage codes. */
+  public static String encodePercentage(char c) {
+    if (isAlphanumeric(c)) return ("" + c);
+    if (c < 16) return ("%0" + Integer.toHexString(c).toUpperCase());
+    if (c < 128) return ("%" + Integer.toHexString(c).toUpperCase());
+    String s = encodeUTF8(c);
+    String result = "";
+    for (int i = 0; i < s.length(); i++) {
+      result += "%" + Integer.toHexString(s.charAt(i)).toUpperCase();
+    }
+    return (result);
+  }
+
+  /**
+   * Encodes a String with reserved XML characters into a valid xml string for attributes.  
+   * @param str
+   * @return 
+   */
+  public static String encodeXmlAttribute(String str) {
+    if (str == null) return null;
+    int len = str.length();
+    if (len == 0) return str;
+    StringBuffer encoded = new StringBuffer();
+    for (int i = 0; i < len; i++) {
+      char c = str.charAt(i);
+      if (c == '<') encoded.append("&lt;");
+      else if (c == '\"') encoded.append("&quot;");
+      else if (c == '>') encoded.append("&gt;");
+      else if (c == '\'') encoded.append("&apos;");
+      else if (c == '&') encoded.append("&amp;");
+      else encoded.append(c);
+    }
+    return encoded.toString();
+  }
+
+  /** Tells whether a char is in a range*/
+  public static boolean in(char c, char a, char b) {
+    return (c >= a && c <= b);
+  }
+
+  /** Tells whether a char is in a string*/
+  public static boolean in(char c, String s) {
+    return (s.indexOf(c) != -1);
+  }
+
+  /** Tells whether a char is alphanumeric in the sense of URIs*/
+  public static boolean isAlphanumeric(char c) {
+    return (in(c, 'a', 'z') || in(c, 'A', 'Z') || in(c, '0', '9'));
+  }
+
+  /** Tells whether a char is reserved in the sense of URIs*/
+  public static boolean isReserved(char c) {
+    return (isSubDelim(c) || isGenDelim(c));
+  }
+
+  /** Tells whether a char is unreserved in the sense of URIs (not the same as !reserved)*/
+  public static boolean isUnreserved(char c) {
+    return (isAlphanumeric(c) || in(c, "-._~"));
+  }
+
+  /** Tells whether a string is escaped in the sense of URIs*/
+  public static boolean isEscaped(String s) {
+    return (s.matches("%[0-9A-Fa-f]{2}"));
+  }
+
+  /** Tells whether a char is a sub-delimiter in the sense of URIs*/
+  public static boolean isSubDelim(char c) {
+    return (in(c, "!$&'()*+,="));
+  }
+
+  /** Tells whether a char is a general delimiter in the sense of URIs*/
+  public static boolean isGenDelim(char c) {
+    return (in(c, ":/?#[]@"));
+  }
+
+  /** Tells whether a char is a valid path component in the sense of URIs*/
+  public static boolean isPchar(char c) {
+    return (isUnreserved(c) || isSubDelim(c) || in(c, "@"));
+  }
+
+  /** Encodes a char to percentage code, if it is not a path character in the sense of URIs*/
+  public static String encodeURIPathComponent(char c) {
+    if (isPchar(c)) return ("" + c);
+    else return (Char.encodePercentage(c));
+  }
+
+  /** Encodes a char to percentage code, if it is not a path character in the sense of URIs*/
+  public static String encodeURIPathComponent(String s) {
+    StringBuilder result = new StringBuilder();
+    for (int i = 0; i < s.length(); i++) {
+      result.append(Char.encodeURIPathComponent(s.charAt(i)));
+    }
+    return (result.toString());
+  }
+
+  /** Encodes a char to percentage code, if it is not a path character in the sense of XMLs*/
+  public static String encodeURIPathComponentXML(String s) {
+    StringBuilder result = new StringBuilder();
+    for (int i = 0; i < s.length(); i++) {
+      if (s.charAt(i) == '&') result.append(Char.encodePercentage(s.charAt(i)));
+      else if (s.charAt(i) == '"') result.append(Char.encodePercentage(s.charAt(i)));
+      else result.append(Char.encodeURIPathComponent(s.charAt(i)));
+    }
+    return (result.toString());
+  }
+
+  /** Decodes a URI path component*/
+  public static String decodeURIPathComponent(String s) {
+    return (Char.decodePercentage(s));
+  }
+
+  /** Encodes a String to UTF8 */
+  public static String encodeUTF8(String c) {
+    StringBuilder r = new StringBuilder();
+    for (int i = 0; i < c.length(); i++) {
+      r.append(encodeUTF8(c.charAt(i)));
+    }
+    return (r.toString());
+  }
+
+  /** Replaces non-normal characters in a String by Backslash codes */
+  public static String encodeBackslash(String c) {
+    StringBuilder r = new StringBuilder();
+    for (int i = 0; i < c.length(); i++) {
+      r.append(encodeBackslash(c.charAt(i)));
+    }
+    return (r.toString());
+  }
+
+  /** Replaces non-normal characters in a String by Backslash codes (if not alphanumeric)*/
+  public static String encodeBackslashToAlphanumeric(String c) {
+    StringBuilder r = new StringBuilder();
+    for (int i = 0; i < c.length(); i++) {
+      r.append(encodeBackslashToAlphanumeric(c.charAt(i)));
+    }
+    return (r.toString());
+  }
+
+  /** Replaces non-normal characters in a String by Backslash codes (if not ASCII)*/
+  public static String encodeBackslashToASCII(String c) {
+    StringBuilder r = new StringBuilder();
+    for (int i = 0; i < c.length(); i++) {
+      r.append(encodeBackslashToASCII(c.charAt(i)));
+    }
+    return (r.toString());
+  }
+
+  /** Replaces non-normal characters in a String by HTML Ampersand codes */
+  public static String encodeAmpersand(String c) {
+    StringBuilder r = new StringBuilder();
+    for (int i = 0; i < c.length(); i++) {
+      r.append(encodeAmpersand(c.charAt(i)));
+    }
+    return (r.toString());
+  }
+
+  /** Replaces non-normal characters in a String by HTML Ampersand codes */
+  public static String encodeAmpersandToAlphanumeric(String c) {
+    StringBuilder r = new StringBuilder();
+    for (int i = 0; i < c.length(); i++) {
+      r.append(encodeAmpersandToAlphanumeric(c.charAt(i)));
+    }
+    return (r.toString());
+  }
+
+  /** Replaces non-normal characters in a String by Percentage codes.
+   * If a character is greater than 0x80, the character is converted to
+   * a UTF8-sequence and this sequence is encoded as percentage codes. */
+  public static String encodePercentage(String c) {
+    StringBuilder r = new StringBuilder();
+    for (int i = 0; i < c.length(); i++) {
+      r.append(encodePercentage(c.charAt(i)));
+    }
+    return (r.toString());
+  }
+
+  /** Decodes all codes in a String and normalizes all chars */
+  public static String decodeAndNormalize(String s) {
+    return (normalize(decode(s)));
+  }
+
+  /** Normalizes all chars in a String to characters 0x20-0x7F */
+  public static String normalize(String s) {
+    StringBuilder b = new StringBuilder();
+    for (int i = 0; i < s.length(); i++)
+      b.append(normalize(s.charAt(i)));
+    return (b.toString());
+  }
+
+  /** Returns the last character of a String or 0*/
+  public static char last(CharSequence s) {
+    return (s.length() == 0 ? (char) 0 : s.charAt(s.length() - 1));
+  }
+
+  /** Returns the String without the last character */
+  public static String cutLast(String s) {
+    return (s.length() == 0 ? "" : s.substring(0, s.length() - 1));
+  }
+
+  /** Cuts the last character */
+  public static StringBuilder cutLast(StringBuilder s) {
+    s.setLength(s.length() - 1);
+    return (s);
+  }
+
+  /** Returns an HTML-String of the String */
+  public static String toHTML(String s) {
+    return (Char.encodeAmpersand(s).replace("&#10;", "<BR>"));
+  }
+
+  /** Returns the chars of a String in hex */
+  public static String hexAll(String s) {
+    StringBuilder result = new StringBuilder();
+    for (int i = 0; i < s.length(); i++) {
+      result.append(Integer.toHexString(s.charAt(i)).toUpperCase()).append(' ');
+    }
+    return (result.toString());
+  }
+
+  /** Replaces special characters in the string by hex codes (cannot be undone)*/
+  public static String encodeHex(String s) {
+    StringBuilder result = new StringBuilder();
+    for (int i = 0; i < s.length(); i++) {
+      char c = s.charAt(i);
+      if (isAlphanumeric(c)) result.append(c);
+      else result.append(Integer.toHexString(s.charAt(i)).toUpperCase());
+    }
+    return (result.toString());
+  }
+
+  /** Upcases the first character in a String*/
+  public static String upCaseFirst(String s) {
+    if (s == null || s.length() == 0) return (s);
+    return (Character.toUpperCase(s.charAt(0)) + s.substring(1));
+  }
+
+  /** Lowcases the first character in a String*/
+  public static String lowCaseFirst(String s) {
+    if (s == null || s.length() == 0) return (s);
+    return (Character.toLowerCase(s.charAt(0)) + s.substring(1));
+  }
+
+  /** Returns a string of the given length, fills with spaces if necessary */
+  public static CharSequence truncate(CharSequence s, int len) {
+    if (s.length() == len) return (s);
+    if (s.length() > len) return (s.subSequence(0, len));
+    StringBuilder result = new StringBuilder(s);
+    while (result.length() < len)
+      result.append(' ');
+    return (result);
+  }
+
+  /** Capitalizes words and lowercases the rest*/
+  public static String capitalize(String s) {
+    StringBuilder result = new StringBuilder();
+    for (int i = 0; i < s.length(); i++) {
+      char c = s.charAt(i);
+      if (i == 0 || i > 0 && !Character.isLetterOrDigit(s.charAt(i - 1))) c = Character.toUpperCase(c);
+      else c = Character.toLowerCase(c);
+      result.append(c);
+    }
+    return (result.toString());
+  }
+
+  /** TRUE if the Charsequence ends with the string */
+  public static boolean endsWith(CharSequence s, String end) {
+    return (s.length() >= end.length() && s.subSequence(s.length() - end.length(), s.length()).equals(end));
+  }
+
+  /** Test routine */
+  public static void main(String argv[]) throws Exception {
+    System.out.println("Enter a string with HTML ampersand codes, umlauts and/or UTF-8 codes and hit ENTER.");
+    System.out.println("Press CTRL+C to abort");
+    BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+    while (true) {
+      String s = in.readLine();
+      System.out.println("Decoded: " + (s = decode(s)));
+      System.out.println("Normalized: " + normalize(s));
+      System.out.println("As UTF8: " + encodeUTF8(s));
+      System.out.println("As percentage: " + encodePercentage(s));
+      System.out.println("As backslash: " + encodeBackslash(s));
+      System.out.println("As ampersand: " + encodeAmpersand(s));
+      System.out.println("As URI component: " + encodeURIPathComponent(s));
+    }
+  }
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/PlingStemmer.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/PlingStemmer.java
new file mode 100644
index 0000000..d4dc2fb
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/PlingStemmer.java
@@ -0,0 +1,925 @@
+package org.grails.datastore.gorm.neo4j.parsers;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.Map;
+import java.util.Set;
+
+import org.grails.datastore.gorm.neo4j.datatypes.FinalMap;
+import org.grails.datastore.gorm.neo4j.datatypes.FinalSet;
+
+/** 
+This class is part of the Java Tools (see http://mpii.de/yago-naga/javatools).
+It is licensed under the Creative Commons Attribution License 
+(see http://creativecommons.org/licenses/by/3.0) by 
+the YAGO-NAGA team (see http://mpii.de/yago-naga).
+  
+
+  
+ 
+
+  The PlingStemmer stems an English noun (plural or singular) to its singular
+  form. It deals with "firemen"->"fireman", it knows Greek stuff like
+  "appendices"->"appendix" and yes, it was a lot of work to compile these exceptions.
+  Examples:
+  <PRE>
+      System.out.println(PlingStemmer.stem("boy"));
+      ----> boy
+      System.out.println(PlingStemmer.stem("boys"));
+      ----> boy
+      System.out.println(PlingStemmer.stem("biophysics"));
+      ---->  biophysics
+      System.out.println(PlingStemmer.stem("automata"));
+      ----> automaton
+      System.out.println(PlingStemmer.stem("genus"));
+      ----> genus
+      System.out.println(PlingStemmer.stem("emus"));
+      ----> emu
+  </PRE><P>
+
+  There are a number of word forms that can either be plural or singular.
+  Examples include "physics" (the science or the plural of "physic" (the
+  medicine)), "quarters" (the housing or the plural of "quarter" (1/4))
+  or "people" (the singular of "peoples" or the plural of "person"). In
+  these cases, the stemmer assumes the word is a plural form and returns
+  the singular form. The methods isPlural, isSingular and isPluralAndSingular
+  can be used to differentiate the cases.<P>
+
+  It cannot be guaranteed that the stemmer correctly stems a plural word
+  or correctly ignores a singular word -- let alone that it treats an
+  ambiguous word form in the way expected by the user.<P>
+  
+  The PlingStemmer uses material from <A HREF=http://wordnet.princeton.edu/>WordNet</A>.<P>
+  It requires the class FinalSet from the <A HREF=http://www.mpii.mpg.de/~suchanek/downloads/javatools>
+  Java Tools</A>.
+*/
+public class PlingStemmer {
+
+  /** Tells whether a word form is plural. This method just checks whether the
+   * stem method alters the word */
+  public static boolean isPlural(String s) {
+    return(!s.equals(stem(s)));
+  }
+
+  /** Tells whether a word form is singular. Note that a word can be both plural and singular */
+  public static boolean isSingular(String s) {
+    return(singAndPlur.contains(s.toLowerCase()) || !isPlural(s));
+  }  
+
+  /** Tells whether a word form is the singular form of one word and at
+   * the same time the plural form of another.*/
+  public static boolean isSingularAndPlural(String s) {
+    return(singAndPlur.contains(s.toLowerCase()));
+  }  
+  
+  /** Cuts a suffix from a string (that is the number of chars given by the suffix) */
+  public static String cut(String s, String suffix) {
+    return(s.substring(0,s.length()-suffix.length()));
+  }
+
+  /** Returns true if a word is probably not Latin */
+  public static boolean noLatin(String s) {
+    return(s.indexOf('h')>0 || s.indexOf('j')>0 || s.indexOf('k')>0 ||
+           s.indexOf('w')>0 || s.indexOf('y')>0 || s.indexOf('z')>0 ||
+           s.indexOf("ou")>0 || s.indexOf("sh")>0 || s.indexOf("ch")>0 ||
+           s.endsWith("aus"));
+  }
+
+  /** Returns true if a word is probably Greek */
+  private static boolean greek(String s) {
+    return(s.indexOf("ph")>0 || s.indexOf('y')>0 && s.endsWith("nges"));
+  }
+
+  /** Stems an English noun */
+  public static String stem(String s) {
+    String stem = s;
+
+     // Handle irregular ones
+     String irreg=irregular.get(s);
+     if(irreg!=null) return(stem=irreg);
+
+     // -on to -a
+     if(categoryON_A.contains(s)) return(stem=cut(s,"a")+"on");
+
+     // -um to -a
+     if(categoryUM_A.contains(s)) return(stem=cut(s,"a")+"um");
+
+     // -x to -ices
+     if(categoryIX_ICES.contains(s)) return(stem=cut(s,"ices")+"ix");
+
+     // -o to -i
+     if(categoryO_I.contains(s)) return(stem=cut(s,"i")+"o");
+
+     // -se to ses
+     if(categorySE_SES.contains(s)) return(stem=cut(s,"s"));
+
+     // -is to -es
+     if(categoryIS_ES.contains(s) || s.endsWith("theses")) return(stem=cut(s,"es")+"is");
+
+     // -us to -i
+     if(categoryUS_I.contains(s)) return(stem=cut(s,"i")+"us");
+     //Wrong plural
+     if(s.endsWith("uses") && (categoryUS_I.contains(cut(s,"uses")+"i") ||
+                               s.equals("genuses") || s.equals("corpuses"))) return(stem=cut(s,"es"));
+
+     // -ex to -ices
+     if(categoryEX_ICES.contains(s)) return(stem=cut(s,"ices")+"ex");
+
+     // Words that do not inflect in the plural
+     if(s.endsWith("ois") || s.endsWith("itis") || category00.contains(s) || categoryICS.contains(s)) return(stem=s);
+
+     // -en to -ina
+     // No other common words end in -ina
+     if(s.endsWith("ina")) return(stem=cut(s,"en"));
+
+     // -a to -ae
+     // No other common words end in -ae
+     if(s.endsWith("ae")) return(stem=cut(s,"e"));
+
+     // -a to -ata
+     // No other common words end in -ata
+     if(s.endsWith("ata")) return(stem=cut(s,"ta"));
+
+     // trix to -trices
+     // No common word ends with -trice(s)
+     if(s.endsWith("trices")) return(stem=cut(s,"trices")+"trix");
+
+     // -us to -us
+     //No other common word ends in -us, except for false plurals of French words
+     //Catch words that are not latin or known to end in -u
+     if(s.endsWith("us") && !s.endsWith("eaus") && !s.endsWith("ieus") && !noLatin(s)
+        && !categoryU_US.contains(s)) return(stem=s);
+
+     // -tooth to -teeth
+     // -goose to -geese
+     // -foot to -feet
+     // -zoon to -zoa
+     //No other common words end with the indicated suffixes
+     if(s.endsWith("teeth")) return(stem=cut(s,"teeth")+"tooth");
+     if(s.endsWith("geese")) return(stem=cut(s,"geese")+"goose");
+     if(s.endsWith("feet")) return(stem=cut(s,"feet")+"foot");
+     if(s.endsWith("zoa")) return(stem=cut(s,"zoa")+"zoon");
+
+     // -eau to -eaux
+     //No other common words end in eaux
+     if(s.endsWith("eaux")) return(stem=cut(s,"x"));
+
+     // -ieu to -ieux
+     //No other common words end in ieux
+     if(s.endsWith("ieux")) return(stem=cut(s,"x"));
+
+     // -nx to -nges
+     // Pay attention not to kill words ending in -nge with plural -nges
+     // Take only Greek words (works fine, only a handfull of exceptions)
+     if(s.endsWith("nges") && greek(s)) return(stem=cut(s,"nges")+"nx");
+
+     // -[sc]h to -[sc]hes
+     //No other common word ends with "shes", "ches" or "she(s)"
+     //Quite a lot end with "che(s)", filter them out
+     if(s.endsWith("shes") || s.endsWith("ches") && !categoryCHE_CHES.contains(s)) return(stem=cut(s,"es"));
+
+     // -ss to -sses
+     // No other common singular word ends with "sses"
+     // Filter out those ending in "sse(s)"
+     if(s.endsWith("sses") && !categorySSE_SSES.contains(s) && !s.endsWith("mousses")) return(stem=cut(s,"es"));
+
+     // -x to -xes
+     // No other common word ends with "xe(s)" except for "axe"
+     if(s.endsWith("xes") && !s.equals("axes")) return(stem=cut(s,"es"));
+
+     // -[nlw]ife to -[nlw]ives
+     //No other common word ends with "[nlw]ive(s)" except for olive
+     if(s.endsWith("nives") || s.endsWith("lives") && !s.endsWith("olives") ||
+        s.endsWith("wives")) return(stem=cut(s,"ves")+"fe");
+
+     // -[aeo]lf to -ves  exceptions: valve, solve
+     // -[^d]eaf to -ves  exceptions: heave, weave
+     // -arf to -ves      no exception
+     if(s.endsWith("alves") && !s.endsWith("valves") ||
+        s.endsWith("olves") && !s.endsWith("solves") ||
+        s.endsWith("eaves") && !s.endsWith("heaves") && !s.endsWith("weaves") ||
+        s.endsWith("arves") ) return(stem=cut(s,"ves")+"f");
+
+     // -y to -ies
+     // -ies is very uncommon as a singular suffix
+     // but -ie is quite common, filter them out
+     if(s.endsWith("ies") && !categoryIE_IES.contains(s)) return(stem=cut(s,"ies")+"y");
+
+     // -o to -oes
+     // Some words end with -oe, so don't kill the "e"
+     if(s.endsWith("oes") && !categoryOE_OES.contains(s)) return(stem=cut(s,"es"));
+
+     // -s to -ses
+     // -z to -zes
+     // no words end with "-ses" or "-zes" in singular
+     if(s.endsWith("ses") || s.endsWith("zes") ) return(stem=cut(s,"es"));
+
+     // - to -s
+     if(s.endsWith("s") && !s.endsWith("ss") && !s.endsWith("is")) return(stem=cut(s,"s"));
+
+     return stem;
+  }
+
+  /** Words that end in "-se" in their plural forms (like "nurse" etc.)*/
+  public static Set<String> categorySE_SES=new FinalSet<String>(
+   "nurses",
+   "cruises",
+   "premises",
+   "houses",
+   "courses",
+   "cases"
+  );
+
+  /** Words that do not have a distinct plural form (like "atlas" etc.)*/
+  public static Set<String> category00=new FinalSet<String>(
+   "alias",
+   "asbestos",
+   "atlas",
+   "barracks",
+   "bathos",
+   "bias",
+   "breeches",
+   "britches",
+   "canvas",
+   "chaos",
+   "clippers",
+   "contretemps",
+   "corps",
+   "cosmos",
+   "crossroads",
+   "diabetes",
+   "ethos",
+   "gallows",
+   "gas",
+   "graffiti",
+   "headquarters",
+   "herpes",
+   "high-jinks",
+   "innings",
+   "jackanapes",
+   "lens",
+   "means",
+   "measles",
+   "mews",
+   "mumps",
+   "news",
+   "pathos",
+   "pincers",
+   "pliers",   
+   "proceedings",
+   "rabies",
+   "rhinoceros",
+   "sassafras",
+   "scissors",
+   "series",
+   "shears",
+   "species",
+   "tuna"
+  );
+
+  /** Words that change from "-um" to "-a" (like "curriculum" etc.), listed in their plural forms*/
+  public static Set<String> categoryUM_A=new FinalSet<String>(
+    "addenda",
+    "agenda",
+    "aquaria",
+    "bacteria",
+    "candelabra",
+    "compendia",
+    "consortia",
+    "crania",
+    "curricula",
+    "data",
+    "desiderata",
+    "dicta",
+    "emporia",
+    "enconia",
+    "errata",
+    "extrema",
+    "gymnasia",
+    "honoraria",
+    "interregna",
+    "lustra",
+    "maxima",
+    "media",
+    "memoranda",
+    "millenia",
+    "minima",
+    "momenta",
+    "optima",
+    "ova",
+    "phyla",
+    "quanta",
+    "rostra",
+    "spectra",
+    "specula",
+    "stadia",
+    "strata",
+    "symposia",
+    "trapezia",
+    "ultimata",
+    "vacua",
+    "vela"
+  );
+
+  /** Words that change from "-on" to "-a" (like "phenomenon" etc.), listed in their plural forms*/
+  public static Set<String> categoryON_A=new FinalSet<String>(
+    "aphelia",
+    "asyndeta",
+    "automata",
+    "criteria",
+    "hyperbata",
+    "noumena",
+    "organa",
+    "perihelia",
+    "phenomena",
+    "prolegomena"
+  );
+
+  /** Words that change from "-o" to "-i" (like "libretto" etc.), listed in their plural forms*/
+  public static Set<String> categoryO_I=new FinalSet<String>(
+   "alti",
+   "bassi",
+   "canti",
+   "contralti",
+   "crescendi",
+   "libretti",
+   "soli",
+   "soprani",
+   "tempi",
+   "virtuosi"
+  );
+
+  /** Words that change from "-us" to "-i" (like "fungus" etc.), listed in their plural forms*/
+  public static Set<String> categoryUS_I=new FinalSet<String>(
+   "alumni",
+   "bacilli",
+   "cacti",
+   "foci",
+   "fungi",
+   "genii",
+   "hippopotami",
+   "incubi",
+   "nimbi",
+   "nuclei",
+   "nucleoli",
+   "octopi",
+   "radii",
+   "stimuli",
+   "styli",
+   "succubi",
+   "syllabi",
+   "termini",
+   "tori",
+   "umbilici",
+   "uteri"
+  );
+
+  /** Words that change from "-ix" to "-ices" (like "appendix" etc.), listed in their plural forms*/
+  public static Set<String> categoryIX_ICES=new FinalSet<String>(
+    "appendices",
+    "cervices"
+  );
+
+  /** Words that change from "-is" to "-es" (like "axis" etc.), listed in their plural forms*/
+  public static Set<String> categoryIS_ES=new FinalSet<String>(
+    // plus everybody ending in theses
+    "analyses",
+    "axes",
+    "bases",
+    "crises",
+    "diagnoses",
+    "ellipses",
+    "emphases",
+    "neuroses",
+    "oases",
+    "paralyses",
+    "synopses"
+  );
+
+  /** Words that change from "-oe" to "-oes" (like "toe" etc.), listed in their plural forms*/
+  public static Set<String> categoryOE_OES=new FinalSet<String>(
+    "aloes",
+    "backhoes",
+    "beroes",
+    "canoes",
+    "chigoes",
+    "cohoes",
+    "does",
+    "felloes",
+    "floes",
+    "foes",
+    "gumshoes",
+    "hammertoes",
+    "hoes",
+    "hoopoes",
+    "horseshoes",
+    "leucothoes",
+    "mahoes",
+    "mistletoes",
+    "oboes",
+    "overshoes",
+    "pahoehoes",
+    "pekoes",
+    "roes",
+    "shoes",
+    "sloes",
+    "snowshoes",
+    "throes",
+    "tic-tac-toes",
+    "tick-tack-toes",
+    "ticktacktoes",
+    "tiptoes",
+    "tit-tat-toes",
+    "toes",
+    "toetoes",
+    "tuckahoes",
+    "woes"
+  );
+
+  /** Words that change from "-ex" to "-ices" (like "index" etc.), listed in their plural forms*/
+  public static Set<String> categoryEX_ICES=new FinalSet<String>(
+    "apices",
+    "codices",
+    "cortices",
+    "indices",
+    "latices",
+    "murices",
+    "pontifices",
+    "silices",
+    "simplices",
+    "vertices",
+    "vortices"
+  );
+
+  /** Words that change from "-u" to "-us" (like "emu" etc.), listed in their plural forms*/
+  public static Set<String> categoryU_US=new FinalSet<String>(
+   "apercus",
+   "barbus",
+   "cornus",
+   "ecrus",
+   "emus",
+   "fondus",
+   "gnus",
+   "iglus",
+   "mus",
+   "nandus",
+   "napus",
+   "poilus",
+   "quipus",
+   "snafus",
+   "tabus",
+   "tamandus",
+   "tatus",
+   "timucus",
+   "tiramisus",
+   "tofus",
+   "tutus"
+  );
+
+  /** Words that change from "-sse" to "-sses" (like "finesse" etc.), listed in their plural forms*/
+  public static Set<String> categorySSE_SSES=new FinalSet<String>(
+    //plus those ending in mousse
+    "bouillabaisses",
+    "coulisses",
+    "crevasses",
+    "crosses",
+    "cuisses",
+    "demitasses",
+    "ecrevisses",
+    "fesses",
+    "finesses",
+    "fosses",
+    "impasses",
+    "lacrosses",
+    "largesses",
+    "masses",
+    "noblesses",
+    "palliasses",
+    "pelisses",
+    "politesses",
+    "posses",
+    "tasses",
+    "wrasses"
+  );
+
+  /** Words that change from "-che" to "-ches" (like "brioche" etc.), listed in their plural forms*/
+  public static Set<String> categoryCHE_CHES=new FinalSet<String>(
+    "adrenarches",
+    "attaches",
+    "avalanches",
+    "barouches",
+    "brioches",
+    "caches",
+    "caleches",
+    "caroches",
+    "cartouches",
+    "cliches",
+    "cloches",
+    "creches",
+    "demarches",
+    "douches",
+    "gouaches",
+    "guilloches",
+    "headaches",
+    "heartaches",
+    "huaraches",
+    "menarches",
+    "microfiches",
+    "moustaches",
+    "mustaches",
+    "niches",
+    "panaches",
+    "panoches",
+    "pastiches",
+    "penuches",
+    "pinches",
+    "postiches",
+    "psyches",
+    "quiches",
+    "schottisches",
+    "seiches",
+    "soutaches",
+    "synecdoches",
+    "thelarches",
+    "troches"
+  );
+
+  /** Words that end with "-ics" and do not exist as nouns without the 's' (like "aerobics" etc.)*/
+  public static Set<String> categoryICS=new FinalSet<String>(
+    "aerobatics",
+    "aerobics",
+    "aerodynamics",
+    "aeromechanics",
+    "aeronautics",
+    "alphanumerics",
+    "animatronics",
+    "apologetics",
+    "architectonics",
+    "astrodynamics",
+    "astronautics",
+    "astrophysics",
+    "athletics",
+    "atmospherics",
+    "autogenics",
+    "avionics",
+    "ballistics",
+    "bibliotics",
+    "bioethics",
+    "biometrics",
+    "bionics",
+    "bionomics",
+    "biophysics",
+    "biosystematics",
+    "cacogenics",
+    "calisthenics",
+    "callisthenics",
+    "catoptrics",
+    "civics",
+    "cladistics",
+    "cryogenics",
+    "cryonics",
+    "cryptanalytics",
+    "cybernetics",
+    "cytoarchitectonics",
+    "cytogenetics",
+    "diagnostics",
+    "dietetics",
+    "dramatics",
+    "dysgenics",
+    "econometrics",
+    "economics",
+    "electromagnetics",
+    "electronics",
+    "electrostatics",
+    "endodontics",
+    "enterics",
+    "ergonomics",
+    "eugenics",
+    "eurhythmics",
+    "eurythmics",
+    "exodontics",
+    "fibreoptics",
+    "futuristics",
+    "genetics",
+    "genomics",
+    "geographics",
+    "geophysics",
+    "geopolitics",
+    "geriatrics",
+    "glyptics",
+    "graphics",
+    "gymnastics",
+    "hermeneutics",
+    "histrionics",
+    "homiletics",
+    "hydraulics",
+    "hydrodynamics",
+    "hydrokinetics",
+    "hydroponics",
+    "hydrostatics",
+    "hygienics",
+    "informatics",
+    "kinematics",
+    "kinesthetics",
+    "kinetics",
+    "lexicostatistics",
+    "linguistics",
+    "lithoglyptics",
+    "liturgics",
+    "logistics",
+    "macrobiotics",
+    "macroeconomics",
+    "magnetics",
+    "magnetohydrodynamics",
+    "mathematics",
+    "metamathematics",
+    "metaphysics",
+    "microeconomics",
+    "microelectronics",
+    "mnemonics",
+    "morphophonemics",
+    "neuroethics",
+    "neurolinguistics",
+    "nucleonics",
+    "numismatics",
+    "obstetrics",
+    "onomastics",
+    "orthodontics",
+    "orthopaedics",
+    "orthopedics",
+    "orthoptics",
+    "paediatrics",
+    "patristics",
+    "patristics",
+    "pedagogics",
+    "pediatrics",
+    "periodontics",
+    "pharmaceutics",
+    "pharmacogenetics",
+    "pharmacokinetics",
+    "phonemics",
+    "phonetics",
+    "phonics",
+    "photomechanics",
+    "physiatrics",
+    "pneumatics",
+    "poetics",
+    "politics",
+    "pragmatics",
+    "prosthetics",
+    "prosthodontics",
+    "proteomics",
+    "proxemics",
+    "psycholinguistics",
+    "psychometrics",
+    "psychonomics",
+    "psychophysics",
+    "psychotherapeutics",
+    "robotics",
+    "semantics",
+    "semiotics",
+    "semitropics",
+    "sociolinguistics",
+    "stemmatics",
+    "strategics",
+    "subtropics",
+    "systematics",
+    "tectonics",
+    "telerobotics",
+    "therapeutics",
+    "thermionics",
+    "thermodynamics",
+    "thermostatics"
+  );
+
+  /** Words that change from "-ie" to "-ies" (like "auntie" etc.), listed in their plural forms*/
+  public static Set<String> categoryIE_IES=new FinalSet<String>(
+    "aeries",
+    "anomies",
+    "aunties",
+    "baddies",
+    "beanies",
+    "birdies",
+    "boccies",
+    "bogies",
+    "bolshies",
+    "bombies",
+    "bonhomies",
+    "bonxies",
+    "booboisies",
+    "boogies",
+    "boogie-woogies",
+    "bookies",
+    "booties",
+    "bosies",
+    "bourgeoisies",
+    "brasseries",
+    "brassies",
+    "brownies",
+    "budgies",
+    "byrnies",
+    "caddies",
+    "calories",
+    "camaraderies",
+    "capercaillies",
+    "capercailzies",
+    "cassies",
+    "catties",
+    "causeries",
+    "charcuteries",
+    "chinoiseries",
+    "collies",
+    "commies",
+    "cookies",
+    "coolies",
+    "coonties",
+    "cooties",
+    "corries",
+    "coteries",
+    "cowpies",
+    "cowries",
+    "cozies",
+    "crappies",
+    "crossties",
+    "curies",
+    "dachsies",
+    "darkies",
+    "dassies",
+    "dearies",
+    "dickies",
+    "dies",
+    "dixies",
+    "doggies",
+    "dogies",
+    "dominies",
+    "dovekies",
+    "eyries",
+    "faeries",
+    "falsies",
+    "floozies",
+    "folies",
+    "foodies",
+    "freebies",
+    "gaucheries",
+    "gendarmeries",
+    "genies",
+    "ghillies",
+    "gillies",
+    "goalies",
+    "goonies",
+    "grannies",
+    "grotesqueries",
+    "groupies",
+    "hankies",
+    "hippies",
+    "hoagies",
+    "honkies",
+    "hymies",
+    "indies",
+    "junkies",
+    "kelpies",
+    "kilocalories",
+    "knobkerries",
+    "koppies",
+    "kylies",
+    "laddies",
+    "lassies",
+    "lies",
+    "lingeries",
+    "magpies",
+    "magpies",
+    "marqueteries",
+    "mashies",
+    "mealies",
+    "meanies",
+    "menageries",
+    "millicuries",
+    "mollies",
+    "facts1",
+    "moxies",
+    "neckties",
+    "newbies",
+    "nighties",
+    "nookies",
+    "oldies",
+    "organdies",
+    "panties",
+    "parqueteries",
+    "passementeries",
+    "patisseries",
+    "pies",
+    "pinkies",
+    "pixies",
+    "porkpies",
+    "potpies",
+    "prairies",
+    "preemies",
+    "premies",
+    "punkies",
+    "pyxies",
+    "quickies",
+    "ramies",
+    "reveries",
+    "rookies",
+    "rotisseries",
+    "scrapies",
+    "sharpies",
+    "smoothies",
+    "softies",
+    "stoolies",
+    "stymies",
+    "swaggies",
+    "sweeties",
+    "talkies",
+    "techies",
+    "ties",
+    "tooshies",
+    "toughies",
+    "townies",
+    "veggies",
+    "walkie-talkies",
+    "wedgies",
+    "weenies",
+    "weirdies",
+    "yardies",
+    "yuppies",
+    "zombies"
+  );
+
+  /** Maps irregular Germanic English plural nouns to their singular form */
+  public static Map<String,String> irregular=new FinalMap<String,String>(
+    "beefs","beef",
+    "beeves","beef",
+    "brethren","brother",
+    "busses","bus",
+    "cattle","cattlebeast",
+    "children","child",
+    "corpora","corpus",
+    "ephemerides","ephemeris",
+    "firemen","fireman",
+    "genera","genus",
+    "genies","genie",
+    "genii","genie",
+    "kine","cow",
+    "lice","louse",
+    "men","man",
+    "mice","mouse",
+    "mongooses","mongoose",
+    "monies","money",
+    "mythoi","mythos",
+    "octopodes","octopus",
+    "octopuses","octopus",
+    "oxen","ox",
+    "people","person",
+    "soliloquies","soliloquy",
+    "throes","throes",
+    "trilbys","trilby",
+    "women","woman"
+  );
+
+  /** Contains word forms that can either be plural or singular */
+  public static Set<String> singAndPlur=new FinalSet<String>(
+        "acoustics",
+        "aestetics",
+        "aquatics",
+        "basics",
+        "ceramics",
+        "classics",
+        "cosmetics",
+        "dermatoglyphics",
+        "dialectics",
+        "dynamics",
+        "esthetics",
+        "ethics",
+        "harmonics",
+        "heroics",
+        "isometrics",
+        "mechanics",
+        "metrics",
+        "statistics",
+        "optic",
+        "people",
+        "physics",
+        "polemics",
+        "premises",
+        "propaedeutics",
+        "pyrotechnics",
+        "quadratics",
+        "quarters",
+        "statistics",
+        "tactics",
+        "tropics"
+        );
+  
+  /** Test routine */
+  public static void main(String[] argv) throws Exception {    
+    System.out.println("Enter an English word in plural form and press ENTER");
+    BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
+    while(true) {
+      String w=in.readLine();
+      if(w.length()==0) break;
+      if(isPlural(w)) System.out.println("This word is plural");
+      if(isSingular(w)) System.out.println("This word is singular");
+      System.out.println("Stemmed to singular: "+stem(w));
+    }
+  }
+}
diff --git a/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/PositionTracker.java b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/PositionTracker.java
new file mode 100644
index 0000000..e91c4fb
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/main/java/org/grails/datastore/gorm/neo4j/parsers/PositionTracker.java
@@ -0,0 +1,288 @@
+package org.grails.datastore.gorm.neo4j.parsers;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * This class is part of the Java Tools (see
+ * http://mpii.de/yago-naga/javatools). It is licensed under the Creative
+ * Commons Attribution License (see http://creativecommons.org/licenses/by/3.0)
+ * by the YAGO-NAGA team (see http://mpii.de/yago-naga).
+ * 
+ * This class implements position change trackers that keep track of position
+ * changes within a String, e.g. caused through normalization etc.
+ * This allows for instance, given a position int the normalized string
+ * to get the corresponding position in the original non-normalized string 
+ * 
+ *
+ * 
+ * backward position tracker - 
+ * tracking several replacement/text changes allowing to trace a position in the modified 
+ * text back to the corresp. position in the original text 
+ * for the other direction see ForwardPositionTracker 
+ * 
+ * @author smetzger */
+public class PositionTracker {
+	
+	
+	private SortedMap<Integer,Integer>positionMap;
+	private SortedMap<Integer,Integer>positionChanges;
+	private SortedMap<Integer,Integer>old2NewMap;
+	private int accumulatedModifier=0;
+	  
+	public PositionTracker(){
+		positionMap=new TreeMap<Integer,Integer>();
+		positionChanges=new TreeMap<Integer,Integer>();
+		old2NewMap=new TreeMap<Integer,Integer>();		     
+	}
+	
+	  
+	public void addPositionChange(int pos, int modifier){
+	      if(modifier!=0){	    	  
+          int oldModifier=0;         
+	    	  old2NewMap.put(pos, modifier);
+          accumulatedModifier+=modifier;
+          if(positionChanges.containsKey(pos+accumulatedModifier))
+            oldModifier=positionChanges.get(pos+accumulatedModifier);
+	    	  positionChanges.put(pos+accumulatedModifier,modifier*-1+oldModifier);	    	  
+	      }		  
+	}
+
+	  
+	  
+	/** Closes the current changing run by Merging new position changes into the existing position change map
+   *  after each round (one round=consecutive changes along the text) you need to call closeRun() before submitting more position changes from a new round,
+   *  i.e. whenever you passed the string to be modified once call closeRun() before starting to run over the string again with more replacements
+	 * Do this every time you ran once over the text making changes to be tracked*/ 
+	public void closeRun() {
+		if(positionChanges.isEmpty())
+		  return;
+	  		
+		  
+		SortedMap<Integer,Integer> temp=positionChanges;
+		 
+		//adapt old positions to new mapping
+		while(!positionMap.isEmpty()){
+		  Integer key=positionMap.firstKey();
+	  	  Collection<Integer> modifiers=old2NewMap.headMap(key+1).values();
+	  	  Integer newposition=key;    	
+	  	  for(Iterator<Integer> it=modifiers.iterator(); it.hasNext(); newposition+=it.next()){}
+	  	  Integer value=positionMap.get(key);
+	  	  if(positionChanges.containsKey(newposition))
+	  		  value+=positionChanges.get(newposition);
+	  	  positionChanges.put(newposition, value);
+	  	  positionMap.remove(key);
+		}
+
+		positionChanges=positionMap;
+		positionMap=temp;
+		old2NewMap.clear();
+		accumulatedModifier=0;
+		return;
+	}
+	  
+	  
+	  
+	  
+	/** Merges new position changes (given with the inversed old2new mapping) into the existing position change map*/ 
+/*	private void addPositionMappings(SortedMap<Integer,Integer> newPosChanges, 
+	   		SortedMap<Integer,Integer> old2NewMap) {
+	  
+		
+		TreeMap<Integer,Integer> newMap=new TreeMap<Integer,Integer>();
+		 
+		//adapt old positions to new mapping
+		while(!positionMap.isEmpty()){
+		  Integer key=positionMap.firstKey();
+	  	  Collection<Integer> modifiers=old2NewMap.headMap(key+1).values();
+	  	  Integer newposition=key;    	
+	  	  for(Iterator<Integer> it=modifiers.iterator(); it.hasNext(); newposition+=it.next()){}
+	  	  Integer value=positionMap.get(key);
+	  	  if(newMap.containsKey(newposition))
+	  		  value+=newMap.get(newposition);
+	  	  newMap.put(newposition, value);
+	  	  positionMap.remove(key);
+		}
+		while(!newPosChanges.isEmpty()){
+		  Integer key=newPosChanges.firstKey();
+		  Integer value=newPosChanges.get(key);
+		  if(newMap.containsKey(key))
+		     value+=newMap.get(key);
+		  newMap.put(key, value);
+		  newPosChanges.remove(key);						
+		}
+		positionMap=newMap;
+		old2NewMap.clear();
+		return;
+	}
+	  */
+	  
+	public Integer translatePosition(Integer pos) {
+		SortedMap<Integer,Integer> headMap=positionMap.headMap(pos+1);
+		  Integer modifier=0;    	
+		  for(Iterator<Integer> it=headMap.values().iterator(); it.hasNext(); modifier+=it.next()){}
+/*		  if(headMap.size()>1){      TODO: Possible Optimization if we assume positions are asked in ascending order
+			  headMap.clear();
+			  posMap.put(pos, modifier);
+		  }*/ 
+		  return pos+modifier;		  
+	}
+  
+
+    
+
+  
+  
+  
+  
+  
+  
+  
+  /** forward position change tracking - keeping track of several rounds of text modifications allowing to trace a position in the original
+   *  text along the modifications to the corresp. position in the modified text 
+   *  after each round (one round=consecutive changes along the text) you need to call closeRun() before submitting more position changes from a new round,
+   *  i.e. whenever you passed the string to be modified once call closeRun() before starting to run over the string again with more replacements
+   *  REMARK: NOT TESTED WITH MORE THAN ONE ROUND! may be ERRORNOUS with multiple rounds -> use with care (works with a single round though)
+   * @author smetzger
+   *
+   */
+  public static class ForwardPositionTracker {
+    
+    
+    private SortedMap<Integer,Integer>positionMap;
+    private SortedMap<Integer,Integer>positionChanges;
+    //private SortedMap<Integer,Integer>new2OldMap;
+    private PositionTracker new2OldTracker=null;
+  //  private int accumulatedModifier=0;
+      
+    public ForwardPositionTracker(){
+      positionMap=new TreeMap<Integer,Integer>();
+      positionChanges=new TreeMap<Integer,Integer>();
+     // new2OldMap=new TreeMap<Integer,Integer>();
+      new2OldTracker=new PositionTracker();
+     
+    }
+    
+      
+    public void addPositionChange(int pos, int modifier){
+          if(modifier!=0){                                         
+            positionChanges.put(pos,modifier);
+  //          accumulatedModifier+=modifier;
+            /*if(new2OldMap.containsKey(pos+accumulatedModifier))
+              oldModifier=new2OldMap.get(pos+accumulatedModifier);
+            new2OldMap.put(pos+accumulatedModifier, -1*modifier+oldModifier);                        
+          }     */
+            new2OldTracker.addPositionChange(pos, modifier);
+          }
+    }
+    
+
+
+
+
+      
+      
+    /** Closes the current changing run by Merging new position changes into the existing position change map
+     * Do this every time you ran once over the text making changes to be tracked*/ 
+    public void closeRun() {
+      if(positionChanges.isEmpty())
+        return;
+
+      
+      for(Map.Entry<Integer, Integer> change:positionChanges.entrySet()){
+        Integer positionInOrigStream=new2OldTracker.translatePosition(change.getKey());
+        if(positionMap.containsKey(positionInOrigStream))
+          positionMap.put(positionInOrigStream, change.getValue()+positionMap.get(positionInOrigStream));
+        else
+          positionMap.put(positionInOrigStream, change.getValue());
+      }
+       
+      positionChanges.clear();
+//      accumulatedModifier=0;
+      new2OldTracker.closeRun();
+        
+      return;
+    }
+      
+    
+      
+    /** tells whether a position in the original stream has been cut away by some change operation, 
+     *  such that translating it usually would make not to much sense
+     *  @return true, iff the given position has been cut away, false otherwise (i.e. false if it should be mappable)
+     *  TODO: current version ONLY WORKS SECURELY WHEN THERE IS ONLY ONE POSITION CHANGE RUN WITHOUT OVERLAPPING CHANGES!
+     *  as soon as there are more than one change runs, or changes that overlap, we would need to check all following changes instead of only the next one */
+    public boolean hasBeenCutAway(Integer pos){
+        SortedMap<Integer,Integer> tailMap=positionMap.tailMap(pos+1);
+        if(tailMap.isEmpty())
+          return false;
+        Integer key=tailMap.firstKey();
+        Integer modifier=tailMap.get(key);
+        if(modifier<0 && key+modifier<=pos )
+          return true;
+        else 
+          return false;
+        /* this does not work for the general case (had it the wrong way aroung), but can be used to implement it
+        Integer key=null;
+        Iterator<Integer> it=tailMap.keySet().iterator();
+        while(it.hasNext()){
+          key=it.next();
+          Integer mod=tailMap.get(key);
+          if(mod<0 && key-mod>=pos)
+            return true;
+        }  
+        return false;*/
+      }
+      
+    public Integer translatePosition(Integer pos) {
+      SortedMap<Integer,Integer> headMap=positionMap.headMap(pos+1);
+        Integer modifier=0;     
+        for(Iterator<Integer> it=headMap.values().iterator(); it.hasNext(); modifier+=it.next()){}
+  /*      if(headMap.size()>1){      Optimization if we assume positions are asked in ascending order
+          headMap.clear();
+          posMap.put(pos, modifier);
+        }*/ 
+        return pos+modifier;      
+    }
+    
+    /** also handles positions inside text parts that have been cut out properly 
+     * 
+     *  TODO: current version ONLY WORKS SECURELY WHEN THERE IS ONLY ONE POSITION CHANGE RUN WITHOUT OVERLAPPING CHANGES!
+     *  as soon as there are more than one change runs, or changes that overlap, we would need to check all following changes instead of only the next one */
+    public Integer translatePositionExactly(Integer pos) {
+
+      SortedMap<Integer,Integer> tailMap=positionMap.tailMap(pos+1);
+      if(tailMap.isEmpty())
+        return translatePosition(pos);
+      else{
+        Integer key=tailMap.firstKey();
+        Integer modifier=tailMap.get(key);
+        return translatePosition(Math.min(pos,key+modifier));
+      }
+      
+/*        
+ *        That version does it the wrong way around
+ *        SortedMap<Integer,Integer> headMap=positionMap.headMap(pos+1);
+          Integer modifier=0;     
+          Integer key=null, value=null;
+          Iterator<Integer> it=headMap.keySet().iterator();
+          while(it.hasNext()){
+            key=it.next();
+        	  value=headMap.get(key);
+        	  if(value<0)
+        		  modifier+=Math.max(key-pos, value);
+          }*/
+    /*      if(headMap.size()>1){      Optimization if we assume positions are asked in ascending order
+            headMap.clear();
+            posMap.put(pos, modifier);
+          }
+          return pos+modifier;    */ 
+            
+      }
+
+  }
+  
+  
+}
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/CascadingDeleteSpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/CascadingDeleteSpec.groovy
index efbbb87..681af0e 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/CascadingDeleteSpec.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/CascadingDeleteSpec.groovy
@@ -3,7 +3,6 @@
 import grails.gorm.DetachedCriteria
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
-import spock.lang.Ignore
 
 class CascadingDeleteSpec extends GormDatastoreSpec {
 
@@ -72,7 +71,7 @@
 
         then:
             def criteria = new DetachedCriteria(Club).build {}
-        criteria.deleteAll()
+            criteria.deleteAll()
 
         then:
             Club.count() == 0
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/LabelStrategySpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/LabelStrategySpec.groovy
index 22b73ab..12e3433 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/LabelStrategySpec.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/LabelStrategySpec.groovy
@@ -1,11 +1,13 @@
 package grails.gorm.tests
 
+import grails.gorm.dirty.checking.DirtyCheck
 import grails.persistence.Entity
 import org.grails.datastore.gorm.Setup
 import org.grails.datastore.gorm.neo4j.GraphPersistentEntity
 import org.grails.datastore.mapping.core.Session
 import org.neo4j.graphdb.DynamicLabel
 import org.neo4j.helpers.collection.IteratorUtil
+import spock.lang.Issue
 
 /**
  * test for various strategies to define Neo4j labels on domain classes and instances
@@ -23,8 +25,12 @@
     }
 
     public class LocalSetup extends Setup {
+        @Override
         static Session setup(classes) {
             skipIndexSetup = false
+            extendedValidatorSetup = { mappingContext, grailsApplication ->
+                setupValidator(mappingContext, grailsApplication, InstanceDependentLabels.simpleName)
+            }
             Setup.setup(classes)
         }
     }
@@ -65,7 +71,13 @@
         labels.every {
             Setup.graphDb.schema().getIndexes(DynamicLabel.label(it))*.propertyKeys == [['__id__']]
         }
-    }
+
+        when:
+        def d = StaticLabels.findByName("dummy")
+
+        then:
+        d!=null
+        d.id == s.id}
 
     def "should dynamic label mapping work"() {
         when:
@@ -73,6 +85,13 @@
 
         then:
         verifyLabelsForId(s.id, [s.class.name])
+
+        when:
+        def d = DynLabel.findByName("dummy")
+
+        then:
+        d!=null
+        d.id == s.id
     }
 
     def "should mixed labels mapping work"() {
@@ -80,15 +99,26 @@
         def s = new MixedLabels(name:'dummy').save(flush:true)
 
         then:
-        verifyLabelsForId(s.id, ["MyLabel", s.class.name])
-    }
+        verifyLabelsForId(s.id, ["MixedLabel", s.class.name])
 
-    def "should instance dependent labels mapping work"() {
         when:
-        def s = new InstanceDependentLabels(name:'Sam', profession: 'Fireman').save(flush:true)
+        def d = MixedLabels.findByName("dummy")
 
         then:
-        verifyLabelsForId(s.id, ["MyLabel", "${s.name}"])
+        d!=null
+        d.id == s.id
+    }
+
+    @Issue("https://jira.grails.org/browse/GPNEO4J-17")
+    def "should instance dependent labels mapping work"() {
+
+        when:
+        def s = new InstanceDependentLabels(name:'Sam', profession: 'Fireman')
+        s.save(flush:true)
+
+        then:
+        s.hasErrors() == false
+        verifyLabelsForId(s.id, ["InstanceDependentLabels", "${s.profession}"])
 
         and:
         Setup.graphDb.schema().getIndexes(DynamicLabel.label("MyLabel"))*.propertyKeys == [['__id__']]
@@ -98,6 +128,24 @@
 
         and: "there are no indexes on null"
         Setup.graphDb.schema().getIndexes().every { it.label.name() != 'null'}
+
+        when: "create Sam again, now as policeman"
+        def d = new InstanceDependentLabels(name:'Sam', profession: 'Policeman')
+        d.save(flush:true)
+
+        then: "we've violated unique constraint"
+        d.hasErrors() == true
+        d.errors.allErrors[0].code == "unique"
+        d.errors
+
+        when: "unmarshall Sam instance"
+        def sam = InstanceDependentLabels.findByName("Sam")
+
+        then:
+        sam != null
+        sam.profession == "Fireman"
+        s.id == sam.id
+
     }
 
     private def verifyLabelsForId(id, labelz) {
@@ -107,6 +155,7 @@
     }
 }
 
+@DirtyCheck
 @Entity
 class Default {
     Long id
@@ -114,17 +163,7 @@
     String name
 }
 
-@Entity
-class StaticLabel {
-    Long id
-    Long version
-    String name
-
-    static mapping = {
-        labels "MyLabel"
-    }
-}
-
+@DirtyCheck
 @Entity
 class StaticLabels {
     Long id
@@ -137,6 +176,19 @@
 
 }
 
+@DirtyCheck
+@Entity
+class StaticLabel {
+    Long id
+    Long version
+    String name
+
+    static mapping = {
+        labels "MyLabel"
+    }
+}
+
+@DirtyCheck
 @Entity
 class DynLabel {
     Long id
@@ -148,6 +200,7 @@
     }
 }
 
+@DirtyCheck
 @Entity
 class MixedLabels {
     Long id
@@ -155,11 +208,11 @@
     String name
 
     static mapping = {
-        labels "MyLabel", { GraphPersistentEntity pe -> "`${pe.javaClass.name}`" }
+        labels "MixedLabel", { GraphPersistentEntity pe -> "`${pe.javaClass.name}`" }
     }
 }
 
-
+@DirtyCheck
 @Entity
 class InstanceDependentLabels {
     Long id
@@ -171,8 +224,8 @@
         name unique:true
     }
     static mapping = {
-        labels "MyLabel", { GraphPersistentEntity pe, instance ->  // 2 arguments: instance dependent label
-            "`${instance.name}`"
+        labels { GraphPersistentEntity pe, instance ->  // 2 arguments: instance dependent label
+            "`${instance.profession}`"
         }
     }
 }
\ No newline at end of file
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/ManyToManySpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/ManyToManySpec.groovy
index fdc9f6e..b44d836 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/ManyToManySpec.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/ManyToManySpec.groovy
@@ -2,8 +2,10 @@
 
 import grails.gorm.dirty.checking.DirtyCheck
 import grails.persistence.Entity
+import org.neo4j.helpers.collection.IteratorUtil
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
+import spock.lang.Issue
 
 class ManyToManySpec extends GormDatastoreSpec {
 
@@ -11,7 +13,7 @@
 
     @Override
     List getDomainClasses() {
-        [Role, User, MBook, MBookworm]
+        [Role, User, MBook, MBookworm, BidirectionalFriends]
     }
 
     /*def setupSpec() {
@@ -204,6 +206,34 @@
 
     }
 
+    @Issue("GPNEO4J-20")
+    def "should version not increase when adding relationships"() {
+        setup:
+        def felix = new BidirectionalFriends(name: 'felix').save(flush: true)
+        session.clear()
+
+        when: "adding 100 people being friend with felix"
+        (0..<100).each {
+            new BidirectionalFriends(name: "buddy$it", friends: [felix]).save()
+        }
+        session.flush()
+        session.clear()
+        def fetchedFelix = BidirectionalFriends.findByName("felix")
+
+        then:
+        fetchedFelix.version == felix.version
+
+//        and: "inverse side has correct number of friends"
+//        fetchedFelix.friends.size() == 100 // TODO: investigate why this domain class is not bidirectional
+
+        when: "we have 100 relationships"
+        def result = session.nativeInterface.execute("MATCH (:BidirectionalFriends {name:{1}})-[:FRIENDS]-(o) return count(o) as c", ["felix"])
+
+        then:
+        IteratorUtil.single(result)["c"] == 100
+
+    }
+
 }
 
 @DirtyCheck
@@ -299,3 +329,15 @@
         return "Bookworm: [name: ${this.name}, favoriteBook: ${this.favoriteBook?.name}]"
     }
 }
+
+@DirtyCheck
+@Entity
+class BidirectionalFriends {
+    Long id
+    Long version
+    String name
+    Set friends
+
+    static hasMany = [ friends: BidirectionalFriends ]
+    static mappedBy = [ friends: "friends" ]
+}
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/MiscSpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/MiscSpec.groovy
index b0c2377..5dd0bb3 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/MiscSpec.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/MiscSpec.groovy
@@ -1,5 +1,6 @@
 package grails.gorm.tests
 
+import grails.gorm.dirty.checking.DirtyCheck
 import grails.persistence.Entity
 import groovy.beans.Bindable
 import groovyx.gpars.GParsPool
@@ -389,6 +390,33 @@
         c.save(flush: true)
     }
 
+    def "changing one2many is consistent"() {
+        setup:
+        def argentina = new Team(name: 'Argentina').save()
+        def germany = new Team(name: 'Germany').save()
+        session.flush()
+        session.clear()
+
+        when: "by error we put Manual Neuer to Argentina"
+        def manuel = new Player(name: 'Manuel Neuer', team: argentina).save(flush:true)
+
+        then:
+        Team.findByName('Argentina').players.size()==1
+
+        when:
+        session.flush()
+        session.clear()
+        manuel = Player.findByName('Manuel Neuer')
+        manuel.team = germany
+        manuel.save()
+
+        session.flush()
+        session.clear()
+
+        then:
+        Team.findByName('Germany').players.size()==1
+        Team.findByName('Argentina').players.size()==0
+    }
 }
 
 @Entity
@@ -405,12 +433,15 @@
 
 @Bindable
 @Entity
+@DirtyCheck
 class Team implements Serializable {
     Long id
     Long version
     String name
     Club club
     byte[] binaryData
+    Set players
+    static hasMany = [players: Player]
 
     static belongsTo = Club
 }
@@ -428,4 +459,13 @@
                            throws ObjectStreamException {
         return get(id)
     }
+}
+
+@Entity
+@DirtyCheck
+class Player {
+    Long id
+    Long version
+    String name
+    Team team
 }
\ No newline at end of file
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/Neo4jEntityPersisterSpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/Neo4jEntityPersisterSpec.groovy
new file mode 100644
index 0000000..5aae270
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/Neo4jEntityPersisterSpec.groovy
@@ -0,0 +1,31 @@
+package grails.gorm.tests
+
+import org.grails.datastore.gorm.neo4j.Neo4jEntityPersister
+import spock.lang.Specification
+
+/**
+ * @author Stefan Armbruster
+ */
+class Neo4jEntityPersisterSpec extends Specification {
+
+    def "verify singular detection"() {
+        setup:
+        def cut = new Neo4jEntityPersister(null, null, null, null)
+
+        expect:
+        cut.isSingular(term) == result
+
+        where:
+        term       | result
+        "word"     | true
+        "words"    | false
+        "friend"   | true
+        "friends"  | false
+        "buddy"    | true
+        "buddies"  | false
+        "child"    | true
+        "children" | false
+        "person"   | true
+        //"people"   | false
+    }
+}
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/NonDeclaredPropertiesSpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/NonDeclaredPropertiesSpec.groovy
index 88ebcfd..25ef5a9 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/NonDeclaredPropertiesSpec.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/NonDeclaredPropertiesSpec.groovy
@@ -1,10 +1,10 @@
 package grails.gorm.tests
 
 import org.grails.datastore.gorm.neo4j.Neo4jGormEnhancer
+import org.neo4j.helpers.collection.IteratorUtil
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
-import spock.lang.Ignore
-import spock.lang.IgnoreRest
+import spock.lang.Issue
 
 class NonDeclaredPropertiesSpec extends GormDatastoreSpec {
 
@@ -141,8 +141,52 @@
 
         then:
         person.notDeclaredProperty == null
+    }
 
+    @Issue("GPNEO4J-25")
+    def "dynamic properties point to domain classes instance should be relationships"() {
+        setup:
+        def cosima = new Pet(name: 'Cosima')
+        def lara = new Pet(name: 'Lara')
+        cosima.buddy = lara
+        cosima.buddies = lara  // NB plural version
 
+        cosima.save()
+        session.flush()
+        session.clear()
+
+        when:
+        def result = session.nativeInterface.execute("MATCH (n:Pet {__id__:{1}})-[:buddy]->(l) return l", [cosima.id])
+
+        then:
+        IteratorUtil.count(result) == 1
+
+        and: "reading dynamic rels works"
+        Pet.findByName("Cosima").buddy.name == "Lara"
+
+        and: "using plural named properties returns an array"
+        Pet.findByName("Cosima").buddies*.name == ["Lara"]
+    }
+
+    def "dynamic properties pointing to arrays of domain classes should be a relationship"() {
+        setup:
+        def cosima = new Pet(name: 'Cosima')
+        def lara = new Pet(name: 'Lara')
+        def samira = new Pet(name: 'Samira')
+        cosima.buddies = [lara, samira]
+
+        cosima.save()
+        session.flush()
+        session.clear()
+
+        when:
+        def result = session.nativeInterface.execute("MATCH (n:Pet {__id__:{1}})-[:buddies]->(l) return l", [cosima.id])
+
+        then:
+        IteratorUtil.count(result) == 2
+
+        and: "reading dynamic rels works"
+        Pet.findByName("Cosima").buddies*.name == ["Lara", "Samira"]
     }
 
 }
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/UpdateWithProxyPresentSpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/UpdateWithProxyPresentSpec.groovy
new file mode 100644
index 0000000..9eafe32
--- /dev/null
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/grails/gorm/tests/UpdateWithProxyPresentSpec.groovy
@@ -0,0 +1,18 @@
+package grails.gorm.tests
+
+import spock.lang.Ignore
+import spock.lang.Specification
+
+@Ignore("TODO: Neo4J association proxy support is broken after GPNEO4J-25 changes")
+class UpdateWithProxyPresentSpec extends Specification {
+
+    void "Test update entity with association proxies"() {
+        expect: 
+        1==0
+    }
+
+    void "Test update unidirectional oneToMany with proxy"() {
+        expect: 
+        1==0
+    }
+}
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/Setup.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
index 0d4b0d6..3b7a272 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/Setup.groovy
@@ -1,13 +1,13 @@
 package org.grails.datastore.gorm
 
-import grails.gorm.tests.Role
+import grails.core.DefaultGrailsApplication
+import grails.core.GrailsApplication
 import org.apache.tomcat.jdbc.pool.DataSource
 import org.apache.tomcat.jdbc.pool.PoolProperties
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator
 import org.grails.datastore.gorm.events.AutoTimestampEventListener
 import org.grails.datastore.gorm.events.DomainEventListener
 import org.grails.datastore.gorm.neo4j.DumpGraphOnSessionFlushListener
+import org.grails.datastore.gorm.neo4j.HashcodeEqualsAwareProxyFactory
 import org.grails.datastore.gorm.neo4j.Neo4jDatastore
 import org.grails.datastore.gorm.neo4j.Neo4jGormEnhancer
 import org.grails.datastore.gorm.neo4j.Neo4jMappingContext
@@ -17,6 +17,7 @@
 import org.grails.datastore.mapping.model.MappingContext
 import org.grails.datastore.mapping.model.PersistentEntity
 import org.grails.datastore.mapping.transactions.DatastoreTransactionManager
+import org.grails.validation.GrailsDomainClassValidator
 import org.neo4j.graphdb.GraphDatabaseService
 import org.neo4j.kernel.GraphDatabaseAPI
 import org.neo4j.kernel.impl.transaction.TxManager
@@ -41,6 +42,7 @@
     static DataSource dataSource
     static WebServer webServer
     static skipIndexSetup = true
+    static Closure extendedValidatorSetup = null
 
     static destroy() {
         dataSource.close()
@@ -99,40 +101,21 @@
                 new JdbcCypherEngine(dataSource)
         )
         datastore.skipIndexSetup = skipIndexSetup
-        //datastore.mappingContext.proxyFactory = new GroovyProxyFactory()
+        datastore.mappingContext.proxyFactory = new HashcodeEqualsAwareProxyFactory()
 
+
+//        ConstrainedProperty.registerNewConstraint(UniqueConstraint.UNIQUE_CONSTRAINT, UniqueConstraint)
         for (Class cls in classes) {
             mappingContext.addPersistentEntity(cls)
         }
 
-        PersistentEntity entity = mappingContext.persistentEntities.find { PersistentEntity e -> e.name.contains("TestEntity")}
+        def grailsApplication = new DefaultGrailsApplication(classes as Class[], Setup.getClassLoader())
+        grailsApplication.mainContext = ctx
+        grailsApplication.initialise()
 
-        mappingContext.addEntityValidator(entity, [
-            supports: { Class c -> true },
-            validate: { o, Errors errors ->
-                if (!StringUtils.hasText(o.name)) {
-                    errors.rejectValue("name", "name.is.blank")
-                }
-            }
-        ] as Validator)
-
-        entity = mappingContext.persistentEntities.find { PersistentEntity e -> e.name.contains("Role")}
-        if (entity) {
-
-            def grailsApplication = new DefaultGrailsApplication([Role] as Class[], Setup.getClassLoader())
-            grailsApplication.mainContext = ctx
-            grailsApplication.initialise()
-
-            def validator = new GrailsDomainClassValidator(
-                grailsApplication: grailsApplication,
-                domainClass: grailsApplication.getDomainClass(entity.name)
-            )
-
-            datastore.mappingContext.addEntityValidator(entity, validator)
-        }
+        setupValidators(mappingContext, grailsApplication)
 
         def enhancer = new Neo4jGormEnhancer(datastore, new DatastoreTransactionManager(datastore: datastore))
-//        def enhancer = new GormEnhancer(datastore, new DatastoreTransactionManager(datastore: datastore))
         enhancer.enhance()
 
         datastore.afterPropertiesSet()
@@ -147,14 +130,43 @@
         ctx.addApplicationListener new DomainEventListener(datastore)
         ctx.addApplicationListener new AutoTimestampEventListener(datastore)
 
-//      // enable for debugging
-//        if (graphDb) {
-//            ctx.addApplicationListener new DumpGraphOnSessionFlushListener(graphDb)
-//        }
+      // enable for debugging
+        if (graphDb) {
+            ctx.addApplicationListener new DumpGraphOnSessionFlushListener(graphDb)
+        }
 
         datastore.connect()
     }
 
+    static void setupValidators(MappingContext mappingContext, GrailsApplication grailsApplication) {
+
+        setupValidator(mappingContext, grailsApplication, "TestEntity", [
+                    supports: { Class c -> true },
+                    validate: { o, Errors errors ->
+                        if (!StringUtils.hasText(o.name)) {
+                            errors.rejectValue("name", "name.is.blank")
+                        }
+                    }
+                ] as Validator)
+
+        setupValidator(mappingContext, grailsApplication, "Role")
+
+        if (extendedValidatorSetup) {
+            extendedValidatorSetup(mappingContext, grailsApplication)
+        }
+    }
+
+    static void setupValidator(MappingContext mappingContext, GrailsApplication grailsApplication, String entityName, Validator validator = null) {
+        PersistentEntity entity = mappingContext.persistentEntities.find { PersistentEntity e -> e.javaClass.simpleName == entityName }
+        if (entity) {
+            mappingContext.addEntityValidator(entity, validator ?:
+                    new GrailsDomainClassValidator(
+                            grailsApplication: grailsApplication,
+                            domainClass: grailsApplication.getDomainClass(entity.javaClass.name)
+                    ) )
+        }
+    }
+
     private static void waitForIndexesBeingOnline(GraphDatabaseService graphDb) {
         if (graphDb && (skipIndexSetup==false)) {
             def tx = graphDb.beginTx()
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/Neo4jSuite.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/Neo4jSuite.groovy
index 48c4a29..ddb7d2b 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/Neo4jSuite.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/Neo4jSuite.groovy
@@ -56,7 +56,8 @@
 //ApiExtensionsSpec,
 //RelationshipUtilsSpec,
 //CascadingDeleteSpec,
-//NonDeclaredPropertiesSpec
+//NonDeclaredPropertiesSpec,
+//LabelStrategySpec,
 
 ])
 class Neo4jSuite {
diff --git a/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurerSpec.groovy b/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurerSpec.groovy
index c4b24d3..810b7cb 100644
--- a/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurerSpec.groovy
+++ b/grails-datastore-gorm-neo4j/src/test/groovy/org/grails/datastore/gorm/neo4j/plugin/support/Neo4jSpringConfigurerSpec.groovy
@@ -1,12 +1,11 @@
 package org.grails.datastore.gorm.neo4j.plugin.support
 
+import grails.core.DefaultGrailsApplication
+import grails.core.GrailsApplication
 import grails.gorm.tests.Person
+import grails.plugins.DefaultGrailsPluginManager
 import grails.spring.BeanBuilder
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.plugins.DefaultGrailsPluginManager
-
+import org.grails.core.artefact.DomainClassArtefactHandler
 import spock.lang.Specification
 
 /**
diff --git a/grails-datastore-gorm-plugin-support/build.gradle b/grails-datastore-gorm-plugin-support/build.gradle
index 8518ca1..8c2c1fa 100644
--- a/grails-datastore-gorm-plugin-support/build.gradle
+++ b/grails-datastore-gorm-plugin-support/build.gradle
@@ -17,6 +17,7 @@
         exclude group:'oro',module:'oro'
         exclude group:'asm',module:'asm'
         exclude group:'cglib',module:'cglib'
+        exclude group:'cglib', module:'cglib-nodep'
         exclude group:'xalan',module:'serializer'
         exclude group:'org.springframework',module:'spring-aspects'
         exclude group:'org.springframework',module:'spring-beans'
diff --git a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/AggregatePersistenceContextInterceptor.java b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/AggregatePersistenceContextInterceptor.java
index 815308a..f291e85 100644
--- a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/AggregatePersistenceContextInterceptor.java
+++ b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/AggregatePersistenceContextInterceptor.java
@@ -15,9 +15,10 @@
  */
 package org.grails.datastore.gorm.plugin.support;
 
+import grails.persistence.support.PersistenceContextInterceptor;
+
 import java.util.List;
 
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor;
 
 /**
  * @author Graeme Rocher
diff --git a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/OnChangeHandler.groovy b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/OnChangeHandler.groovy
index bac2bd4..9b18f58 100644
--- a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/OnChangeHandler.groovy
+++ b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/OnChangeHandler.groovy
@@ -14,13 +14,14 @@
  */
 package org.grails.datastore.gorm.plugin.support
 
+import grails.core.GrailsServiceClass
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.core.artefact.ServiceArtefactHandler
+import org.grails.spring.TypeSpecifyableTransactionProxyFactoryBean
+import org.grails.transaction.GroovyAwareNamedTransactionAttributeSource
+
 import java.lang.reflect.Method
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsServiceClass
-import org.codehaus.groovy.grails.commons.ServiceArtefactHandler
-import org.codehaus.groovy.grails.commons.spring.TypeSpecifyableTransactionProxyFactoryBean
-import org.codehaus.groovy.grails.orm.support.GroovyAwareNamedTransactionAttributeSource
 import org.grails.datastore.mapping.core.Datastore
 import org.springframework.context.ApplicationContext
 import org.springframework.core.annotation.AnnotationUtils
@@ -66,7 +67,7 @@
                 return
             }
 
-            def beans = plugin.beans {
+            plugin.beans {
                 def scope = serviceClass.getPropertyValue("scope")
                 def props = ["*": "PROPAGATION_REQUIRED"] as Properties
                 "${serviceClass.propertyName}"(TypeSpecifyableTransactionProxyFactoryBean, serviceClass.clazz) { bean ->
@@ -83,7 +84,6 @@
                     delegate.transactionManager = ref("${datastoreType.toLowerCase()}TransactionManager")
                 }
             }
-            beans.registerBeans(event.ctx)
         }
     }
 
diff --git a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregator.groovy b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregator.groovy
index d804279..03ce794 100644
--- a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregator.groovy
+++ b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregator.groovy
@@ -62,7 +62,7 @@
         registry.getBeanDefinitionNames().findAll { String beanName -> beanName ==~ persistenceInterceptorBeanNamePattern }
     }
 
-    protected ManagedList moveInterceptorBeansToManagedList(BeanDefinitionRegistry registry, Collection persistenceInterceptorBeanNames) {
+    protected ManagedList moveInterceptorBeansToManagedList(BeanDefinitionRegistry registry, Collection<String> persistenceInterceptorBeanNames) {
         ManagedList list = new ManagedList()
         persistenceInterceptorBeanNames.each { String beanName ->
             list.add registry.getBeanDefinition(beanName)
diff --git a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/SpringConfigurer.groovy b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/SpringConfigurer.groovy
index 36df01e..d22fad1 100644
--- a/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/SpringConfigurer.groovy
+++ b/grails-datastore-gorm-plugin-support/src/main/groovy/org/grails/datastore/gorm/plugin/support/SpringConfigurer.groovy
@@ -15,11 +15,12 @@
 
 package org.grails.datastore.gorm.plugin.support
 
+import grails.core.GrailsDomainClassProperty
+import grails.core.GrailsServiceClass
+import org.grails.validation.GrailsDomainClassValidator
+
 import java.lang.reflect.Method
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
-import org.codehaus.groovy.grails.commons.GrailsServiceClass
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator
 import org.grails.datastore.gorm.support.DatastorePersistenceContextInterceptor
 import org.grails.datastore.mapping.reflect.ClassPropertyFetcher
 import org.grails.datastore.mapping.transactions.DatastoreTransactionManager
diff --git a/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/DynamicMethodsConfigurerSpec.groovy b/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/DynamicMethodsConfigurerSpec.groovy
index 11d254a..9949e57 100644
--- a/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/DynamicMethodsConfigurerSpec.groovy
+++ b/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/DynamicMethodsConfigurerSpec.groovy
@@ -2,8 +2,8 @@
 
 import grails.persistence.Entity
 import grails.validation.ValidationException
+import grails.validation.ConstrainedProperty
 import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
 import org.grails.datastore.mapping.core.Datastore
 import org.grails.datastore.mapping.simple.SimpleMapDatastore
 import org.grails.datastore.mapping.transactions.DatastoreTransactionManager
diff --git a/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregatorSpec.groovy b/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregatorSpec.groovy
index a9b8ab3..639fecc 100644
--- a/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregatorSpec.groovy
+++ b/grails-datastore-gorm-plugin-support/src/test/groovy/org/grails/datastore/gorm/plugin/support/PersistenceContextInterceptorAggregatorSpec.groovy
@@ -15,9 +15,9 @@
 
 package org.grails.datastore.gorm.plugin.support
 
+import grails.persistence.support.PersistenceContextInterceptor
 import grails.spring.BeanBuilder
 
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor
 import org.springframework.context.ApplicationContext
 
 import spock.lang.Specification
diff --git a/grails-datastore-gorm-redis/build.gradle b/grails-datastore-gorm-redis/build.gradle
index 0ee03be..bdea4fb 100644
--- a/grails-datastore-gorm-redis/build.gradle
+++ b/grails-datastore-gorm-redis/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.1.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 dependencies {
 
diff --git a/grails-datastore-gorm-redis/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy b/grails-datastore-gorm-redis/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
index ef7165b..93ba059 100644
--- a/grails-datastore-gorm-redis/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
+++ b/grails-datastore-gorm-redis/src/test/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
@@ -1,9 +1,9 @@
 package grails.gorm.tests
 
 import grails.persistence.Entity
+import grails.validation.ConstrainedProperty
 import groovy.transform.NotYetImplemented
-import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
+import org.grails.core.support.GrailsDomainConfigurationUtil
 import org.grails.datastore.gorm.validation.constraints.UniqueConstraint
 import org.grails.datastore.mapping.model.MappingContext
 import org.grails.datastore.mapping.model.PersistentEntity
diff --git a/grails-datastore-gorm-rest-client/build.gradle b/grails-datastore-gorm-rest-client/build.gradle
index fbd7c79..c19f9b0 100644
--- a/grails-datastore-gorm-rest-client/build.gradle
+++ b/grails-datastore-gorm-rest-client/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 dependencies {
     compile 'javax.servlet:javax.servlet-api:3.0.1'
     runtime "org.springframework:spring-webmvc:$springVersion"
diff --git a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/RestClientGormInstanceApi.groovy b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/RestClientGormInstanceApi.groovy
index ddef3d7..c965c92 100644
--- a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/RestClientGormInstanceApi.groovy
+++ b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/RestClientGormInstanceApi.groovy
@@ -17,13 +17,13 @@
 
 import org.grails.datastore.gorm.GormInstanceApi
 import org.grails.datastore.mapping.core.Datastore
-import org.codehaus.groovy.grails.plugins.converters.api.ConvertersApi
 import org.grails.datastore.mapping.rest.client.RestClientSession
 import groovy.transform.CompileStatic
 import grails.plugins.rest.client.RequestCustomizer
 import org.grails.datastore.mapping.core.Session
 import org.grails.datastore.mapping.core.SessionCallback
 import groovy.transform.TypeCheckingMode
+import org.grails.plugins.converters.api.ConvertersApi
 
 /**
  * Extensions to the instance API for REST
diff --git a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/RestClientDatastore.groovy b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/RestClientDatastore.groovy
index 4bd125a..d0f6bf8 100644
--- a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/RestClientDatastore.groovy
+++ b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/RestClientDatastore.groovy
@@ -18,8 +18,6 @@
 import grails.plugins.rest.client.async.AsyncRestBuilder
 import grails.rest.render.RendererRegistry
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.binding.bindingsource.DataBindingSourceRegistry
-import org.codehaus.groovy.grails.web.binding.bindingsource.DefaultDataBindingSourceRegistry
 import org.grails.datastore.mapping.cache.TPCacheAdapterRepository
 import org.grails.datastore.mapping.core.AbstractDatastore
 import org.grails.datastore.mapping.core.Session
@@ -28,6 +26,8 @@
 import org.grails.datastore.mapping.rest.client.config.RestClientMappingContext
 import org.grails.datastore.mapping.rest.client.http.converters.PersistentEntityHttpConverter
 import org.grails.plugins.web.rest.render.DefaultRendererRegistry
+import org.grails.web.databinding.bindingsource.DataBindingSourceRegistry
+import org.grails.web.databinding.bindingsource.DefaultDataBindingSourceRegistry
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.context.ConfigurableApplicationContext
 import org.springframework.web.client.RestTemplate
@@ -55,11 +55,11 @@
     String baseUrl = DEFAULT_BASE_URL
 
 
-    Map<PersistentEntity, AsyncRestBuilder> asyncRestClients = new ConcurrentHashMap<>().withDefault { PersistentEntity entity ->
+    Map<PersistentEntity, AsyncRestBuilder> asyncRestClients = new ConcurrentHashMap<PersistentEntity, AsyncRestBuilder>().withDefault { PersistentEntity entity ->
         new AsyncRestBuilder(syncRestClients.get(entity))
     }
 
-    Map<PersistentEntity, RestBuilder> syncRestClients = new ConcurrentHashMap<>().withDefault { PersistentEntity entity ->
+    Map<PersistentEntity, RestBuilder> syncRestClients = new ConcurrentHashMap<PersistentEntity, RestBuilder>().withDefault { PersistentEntity entity ->
         final template = new RestTemplate(((Endpoint) entity.mapping.mappedForm).httpRequestFactory)
         final converters = template.getMessageConverters()
         converters.add(new PersistentEntityHttpConverter<Object>(entity, rendererRegistry, bindingSourceRegistry))
diff --git a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/engine/RestClientEntityPersister.groovy b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/engine/RestClientEntityPersister.groovy
index 01ff64f..27fc49b 100644
--- a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/engine/RestClientEntityPersister.groovy
+++ b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/engine/RestClientEntityPersister.groovy
@@ -16,14 +16,15 @@
 
 import grails.async.Promise
 import grails.async.PromiseList
+import grails.core.GrailsDomainClassProperty
+import grails.databinding.DataBindingSource
 import grails.plugins.rest.client.RestBuilder
 import grails.plugins.rest.client.RestResponse
 import grails.plugins.rest.client.async.AsyncRestBuilder
 import grails.util.GrailsNameUtils
+import grails.web.databinding.DataBindingUtils
+import grails.web.mime.MimeType
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.binding.DataBindingUtils
-import org.codehaus.groovy.grails.web.mime.MimeType
-import org.grails.databinding.DataBindingSource
 import org.grails.datastore.mapping.core.Session
 import org.grails.datastore.mapping.core.SessionImplementor
 import org.grails.datastore.mapping.dirty.checking.DirtyCheckable
@@ -43,7 +44,6 @@
 import org.grails.datastore.mapping.core.impl.PendingInsertAdapter
 import org.grails.datastore.mapping.rest.client.RestClientException
 import org.grails.datastore.mapping.rest.client.RestClientSession
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty
 import org.grails.datastore.mapping.rest.client.query.RequestParameterRestClientQuery
 
 /**
diff --git a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityHttpConverter.groovy b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityHttpConverter.groovy
index a40625c..cbd8e7d 100644
--- a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityHttpConverter.groovy
+++ b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityHttpConverter.groovy
@@ -16,12 +16,12 @@
 
 import grails.rest.render.RendererRegistry
 import grails.util.GrailsNameUtils
+import grails.web.databinding.DataBindingUtils
+import grails.web.mime.MimeType
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.binding.DataBindingUtils
-import org.codehaus.groovy.grails.web.binding.bindingsource.DataBindingSourceRegistry
-import org.codehaus.groovy.grails.web.mime.MimeType
 import org.grails.datastore.mapping.model.PersistentEntity
 import org.grails.datastore.mapping.rest.client.config.Endpoint
+import org.grails.web.databinding.bindingsource.DataBindingSourceRegistry
 import org.springframework.http.HttpInputMessage
 import org.springframework.http.HttpMethod
 import org.springframework.http.HttpOutputMessage
diff --git a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityListHttpConverter.groovy b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityListHttpConverter.groovy
index 4040e7d..982553f 100644
--- a/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityListHttpConverter.groovy
+++ b/grails-datastore-gorm-rest-client/src/main/groovy/org/grails/datastore/mapping/rest/client/http/converters/PersistentEntityListHttpConverter.groovy
@@ -15,11 +15,11 @@
 package org.grails.datastore.mapping.rest.client.http.converters
 
 import grails.rest.render.RendererRegistry
+import grails.web.databinding.DataBindingUtils
+import grails.web.mime.MimeType
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.binding.DataBindingUtils
-import org.codehaus.groovy.grails.web.binding.bindingsource.DataBindingSourceRegistry
-import org.codehaus.groovy.grails.web.mime.MimeType
 import org.grails.datastore.mapping.model.PersistentEntity
+import org.grails.web.databinding.bindingsource.DataBindingSourceRegistry
 import org.springframework.http.HttpInputMessage
 import org.springframework.http.HttpOutputMessage
 import org.springframework.http.MediaType
diff --git a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/RestClientDatastoreSpec.groovy b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/RestClientDatastoreSpec.groovy
index d535097..64ccdab 100644
--- a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/RestClientDatastoreSpec.groovy
+++ b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/RestClientDatastoreSpec.groovy
@@ -1,9 +1,6 @@
 package org.grails.datastore.gorm.rest.client
 
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationHolder
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationInitializer
-
+import grails.core.DefaultGrailsApplication
 import org.grails.datastore.gorm.events.AutoTimestampEventListener
 import org.grails.datastore.gorm.events.DomainEventListener
 import org.grails.datastore.gorm.plugin.support.DynamicMethodsConfigurer
@@ -12,6 +9,8 @@
 import org.grails.datastore.mapping.rest.client.RestClientDatastore
 import org.grails.datastore.mapping.rest.client.RestClientSession
 import org.grails.datastore.mapping.transactions.DatastoreTransactionManager
+import org.grails.web.converters.configuration.ConvertersConfigurationHolder
+import org.grails.web.converters.configuration.ConvertersConfigurationInitializer
 import org.springframework.context.support.GenericApplicationContext
 import spock.lang.Shared
 import spock.lang.Specification
@@ -28,7 +27,7 @@
     void setupSpec() {
         final application = new DefaultGrailsApplication(getDomainClasses() as Class[], new GroovyClassLoader())
         application.initialise()
-        new ConvertersConfigurationInitializer().initialize(application)
+        new ConvertersConfigurationInitializer(grailsApplication: application).initialize()
 
         def applicationContext = new GenericApplicationContext()
         applicationContext.refresh()
diff --git a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/CrudJsonSpec.groovy b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/CrudJsonSpec.groovy
index bdfdfc0..9a4717b 100644
--- a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/CrudJsonSpec.groovy
+++ b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/CrudJsonSpec.groovy
@@ -1,10 +1,7 @@
 package org.grails.datastore.gorm.rest.client.json
 
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationHolder
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationInitializer
-import org.codehaus.groovy.grails.web.servlet.HttpHeaders
+import grails.web.http.HttpHeaders
 import org.springframework.http.HttpMethod
 import org.springframework.http.MediaType
 import org.springframework.test.web.client.MockRestServiceServer
diff --git a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/DirtyCheckingSpec.groovy b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/DirtyCheckingSpec.groovy
index 6906e28..2ef3ef3 100644
--- a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/DirtyCheckingSpec.groovy
+++ b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/json/DirtyCheckingSpec.groovy
@@ -2,7 +2,7 @@
 
 import grails.gorm.dirty.checking.DirtyCheck
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.web.servlet.HttpHeaders
+import grails.web.http.HttpHeaders
 import org.grails.datastore.gorm.rest.client.RestClientDatastoreSpec
 import org.grails.datastore.mapping.dirty.checking.DirtyCheckable
 import org.springframework.http.HttpMethod
diff --git a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/xml/CrudXmlSpec.groovy b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/xml/CrudXmlSpec.groovy
index c3bb399..1ab4029 100644
--- a/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/xml/CrudXmlSpec.groovy
+++ b/grails-datastore-gorm-rest-client/src/test/groovy/org/grails/datastore/gorm/rest/client/xml/CrudXmlSpec.groovy
@@ -1,7 +1,7 @@
 package org.grails.datastore.gorm.rest.client.xml
 
 import grails.persistence.Entity
-import org.codehaus.groovy.grails.web.servlet.HttpHeaders
+import grails.web.http.HttpHeaders
 import org.grails.datastore.gorm.rest.client.RestClientDatastoreSpec
 import org.springframework.http.HttpMethod
 import org.springframework.http.HttpStatus
diff --git a/grails-datastore-gorm-riak/build.gradle b/grails-datastore-gorm-riak/build.gradle
index 53bc22a..eec4214 100644
--- a/grails-datastore-gorm-riak/build.gradle
+++ b/grails-datastore-gorm-riak/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 configurations {
     grails
diff --git a/grails-datastore-gorm-simpledb/build.gradle b/grails-datastore-gorm-simpledb/build.gradle
index bec152f..fb7df6b 100644
--- a/grails-datastore-gorm-simpledb/build.gradle
+++ b/grails-datastore-gorm-simpledb/build.gradle
@@ -1,4 +1,4 @@
-version = "0.6.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 configurations {
     grails
diff --git a/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/EnumSpec.groovy b/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/EnumSpec.groovy
index d3aedc9..d3d40cf 100644
--- a/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/EnumSpec.groovy
+++ b/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/EnumSpec.groovy
@@ -3,6 +3,7 @@
 import grails.persistence.Entity
 
 import org.grails.datastore.mapping.core.Session
+import spock.lang.IgnoreRest
 import spock.lang.Issue
 
 class EnumSpec extends GormDatastoreSpec {
diff --git a/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy b/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
index 2c7f6f2..81137cd 100644
--- a/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
+++ b/grails-datastore-gorm-tck/src/main/groovy/grails/gorm/tests/UniqueConstraintSpec.groovy
@@ -1,9 +1,8 @@
 package grails.gorm.tests
 
 import grails.persistence.Entity
-
-import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
+import grails.validation.ConstrainedProperty
+import org.grails.core.support.GrailsDomainConfigurationUtil
 import org.grails.datastore.gorm.validation.constraints.UniqueConstraint
 import org.grails.datastore.mapping.model.MappingContext
 import org.grails.datastore.mapping.model.PersistentEntity
diff --git a/grails-datastore-gorm-tck/src/main/groovy/grails/persistence/Entity.java b/grails-datastore-gorm-tck/src/main/groovy/grails/persistence/Entity.java
deleted file mode 100644
index 725fbaf..0000000
--- a/grails-datastore-gorm-tck/src/main/groovy/grails/persistence/Entity.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package grails.persistence;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * @author Graeme Rocher
- * @since 1.1
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Entity {
-}
diff --git a/grails-datastore-gorm-test/src/main/groovy/grails/datastore/test/DatastoreUnitTestMixin.groovy b/grails-datastore-gorm-test/src/main/groovy/grails/datastore/test/DatastoreUnitTestMixin.groovy
index 36c024e..e476432 100644
--- a/grails-datastore-gorm-test/src/main/groovy/grails/datastore/test/DatastoreUnitTestMixin.groovy
+++ b/grails-datastore-gorm-test/src/main/groovy/grails/datastore/test/DatastoreUnitTestMixin.groovy
@@ -14,13 +14,10 @@
  */
 package grails.datastore.test
 
-import grails.test.MockUtils
-
-import org.codehaus.groovy.grails.commons.DefaultGrailsDomainClass
-import org.codehaus.groovy.grails.plugins.DefaultGrailsPluginManager
-import org.codehaus.groovy.grails.plugins.GrailsPluginManager
-import org.codehaus.groovy.grails.plugins.PluginManagerHolder
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator
+import grails.plugins.DefaultGrailsPluginManager
+import grails.plugins.GrailsPluginManager
+import grails.util.Holders
+import org.grails.core.DefaultGrailsDomainClass
 import org.grails.datastore.gorm.GormEnhancer
 import org.grails.datastore.gorm.events.AutoTimestampEventListener
 import org.grails.datastore.gorm.events.DomainEventListener
@@ -29,6 +26,7 @@
 import org.grails.datastore.mapping.simple.SimpleMapDatastore
 import org.grails.datastore.mapping.transactions.DatastoreTransactionManager
 import org.grails.datastore.mapping.transactions.SessionHolder
+import org.grails.validation.GrailsDomainClassValidator
 import org.springframework.context.ConfigurableApplicationContext
 import org.springframework.context.support.GenericApplicationContext
 import org.springframework.transaction.PlatformTransactionManager
@@ -92,14 +90,13 @@
             }
         }
 
-        if (!(PluginManagerHolder.pluginManager instanceof DefaultGrailsPluginManager)) {
-            PluginManagerHolder.pluginManager = mockPluginManager
+        if (!(Holders.pluginManager instanceof DefaultGrailsPluginManager)) {
+            Holders.pluginManager = mockPluginManager
         }
 
         def entity = datastore.mappingContext.addPersistentEntity(domainClass)
         def enhancer = new TestGormEnhancer(datastore, transactionManager)
         enhancer.enhance entity
-        MockUtils.prepareForConstraintsTests(entity.javaClass)
         def dc = new DefaultGrailsDomainClass(entity.javaClass)
         datastore.mappingContext.addEntityValidator(entity, new GrailsDomainClassValidator(domainClass:dc))
         instances.each {
@@ -115,8 +112,8 @@
 
     def disconnect() {
         session?.disconnect()
-        if (PluginManagerHolder.pluginManager?.is(mockPluginManager)) {
-            PluginManagerHolder.pluginManager = null
+        if (Holders.pluginManager?.is(mockPluginManager)) {
+            Holders.pluginManager = null
         }
 
         datastore.clearData()
diff --git a/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/SaveWithFailOnErrorDefaultSpec.groovy b/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/SaveWithFailOnErrorDefaultSpec.groovy
index 65ffcd3..e2e34ed 100644
--- a/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/SaveWithFailOnErrorDefaultSpec.groovy
+++ b/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/SaveWithFailOnErrorDefaultSpec.groovy
@@ -1,9 +1,9 @@
 package org.grails.datastore.gorm
 
 import grails.gorm.tests.GormDatastoreSpec
+import grails.validation.ConstrainedProperty
 import grails.validation.ValidationException
-import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
+import org.grails.core.support.GrailsDomainConfigurationUtil
 import org.grails.datastore.mapping.annotation.Entity
 import org.springframework.validation.Errors
 import org.springframework.validation.Validator
diff --git a/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/UniqueConstraintGroupSpec.groovy b/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/UniqueConstraintGroupSpec.groovy
index d2bfef1..e271809 100644
--- a/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/UniqueConstraintGroupSpec.groovy
+++ b/grails-datastore-gorm-test/src/test/groovy/org/grails/datastore/gorm/UniqueConstraintGroupSpec.groovy
@@ -2,9 +2,8 @@
 
 import grails.gorm.tests.GormDatastoreSpec
 import grails.persistence.Entity
-
-import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
+import grails.validation.ConstrainedProperty
+import org.grails.core.support.GrailsDomainConfigurationUtil
 import org.springframework.validation.Errors
 import org.springframework.validation.Validator
 
diff --git a/grails-datastore-gorm/build.gradle b/grails-datastore-gorm/build.gradle
index 29de9ef..472028b 100644
--- a/grails-datastore-gorm/build.gradle
+++ b/grails-datastore-gorm/build.gradle
@@ -4,6 +4,9 @@
 dependencies {
 
     compile project(":grails-datastore-core")
+    compile("org.grails:grails-validation:$grailsVersion") {
+        exclude group:'org.grails',module:'grails-core'
+    }
     compile("org.grails:grails-core:$grailsVersion") {
         exclude group:'aopalliance',module:'aopalliance'
         exclude group:'commons-logging',module:'commons-logging'
@@ -18,6 +21,7 @@
         exclude group:'oro',module:'oro'
         exclude group:'asm',module:'asm'
         exclude group:'cglib',module:'cglib'
+        exclude group:'cglib', module:'cglib-nodep'
         exclude group:'xalan',module:'serializer'
         exclude group:'org.springframework',module:'spring-aspects'
         exclude group:'org.springframework',module:'spring-beans'
diff --git a/grails-datastore-gorm/src/main/groovy/grails/gorm/CriteriaBuilder.java b/grails-datastore-gorm/src/main/groovy/grails/gorm/CriteriaBuilder.java
index 4c6d2d7..2dd93a5 100644
--- a/grails-datastore-gorm/src/main/groovy/grails/gorm/CriteriaBuilder.java
+++ b/grails-datastore-gorm/src/main/groovy/grails/gorm/CriteriaBuilder.java
@@ -44,7 +44,7 @@
 import org.springframework.util.Assert;
 
 /**
- * Criteria builder implementation that operates against Spring datastore abstraction.
+ * Criteria builder implementation that operates against DataStore abstraction.
  *
  * @author Graeme Rocher
  * @since 1.0
@@ -244,7 +244,7 @@
      * @return The result list
      */
     public List list(Closure callable) {
-        initializeQuery();
+        ensureQueryIsInitialized();
         invokeClosureNode(callable);
 
         return query.list();
@@ -259,7 +259,7 @@
      * @return A single result
      */
     public Object get(Closure callable) {
-        initializeQuery();
+        ensureQueryIsInitialized();
         invokeClosureNode(callable);
 
         uniqueResult = true;
@@ -273,7 +273,7 @@
      * @return The result list
      */
     public List listDistinct(Closure callable) {
-        initializeQuery();
+        ensureQueryIsInitialized();
         invokeClosureNode(callable);
 
         query.projections().distinct();
@@ -281,7 +281,7 @@
     }
 
     public List list(Map paginateParams, Closure callable) {
-        initializeQuery();
+        ensureQueryIsInitialized();
 
         paginationEnabledList = true;
         orderEntries = new ArrayList<Query.Order>();
@@ -300,7 +300,7 @@
      * @return The result count
      */
     public Number count(Closure callable) {
-        initializeQuery();
+        ensureQueryIsInitialized();
         invokeClosureNode(callable);
         uniqueResult = true;
         query.projections().count();
@@ -316,9 +316,9 @@
     public Object invokeMethod(String name, Object obj) {
         Object[] args = obj.getClass().isArray() ? (Object[])obj : new Object[]{obj};
 
+        ensureQueryIsInitialized();
         if (isCriteriaConstructionMethod(name, args)) {
 
-            initializeQuery();
 
             uniqueResult = false;
 
@@ -1085,9 +1085,13 @@
         }
     }
 
-    private void initializeQuery() {
-        query = session.createQuery(targetClass);
-        queryMetaClass = GroovySystem.getMetaClassRegistry().getMetaClass(query.getClass());
+    private void ensureQueryIsInitialized() {
+    	if(query == null) {
+    		query = session.createQuery(targetClass);
+    	}
+    	if(queryMetaClass == null) {
+    		queryMetaClass = GroovySystem.getMetaClassRegistry().getMetaClass(query.getClass());
+    	}
     }
 
     private boolean isCriteriaConstructionMethod(String name, Object[] args) {
@@ -1136,7 +1140,7 @@
         }
         else {
             if (query == null) {
-                initializeQuery();
+                ensureQueryIsInitialized();
             }
             query.add(c);
         }
diff --git a/grails-datastore-gorm/src/main/groovy/grails/gorm/dirty/checking/DirtyCheck.groovy b/grails-datastore-gorm/src/main/groovy/grails/gorm/dirty/checking/DirtyCheck.groovy
index 60b6a66..11ca8d3 100644
--- a/grails-datastore-gorm/src/main/groovy/grails/gorm/dirty/checking/DirtyCheck.groovy
+++ b/grails-datastore-gorm/src/main/groovy/grails/gorm/dirty/checking/DirtyCheck.groovy
@@ -29,7 +29,7 @@
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target([ElementType.TYPE])
-@GroovyASTTransformationClass("org.codehaus.groovy.grails.compiler.gorm.DirtyCheckTransformation")
+@GroovyASTTransformationClass("org.grails.compiler.gorm.DirtyCheckTransformation")
 public @interface DirtyCheck {
 
 }
\ No newline at end of file
diff --git a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/DirtyCheckTransformation.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/DirtyCheckTransformation.groovy
similarity index 96%
rename from grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/DirtyCheckTransformation.groovy
rename to grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/DirtyCheckTransformation.groovy
index 67fdbfc..a4d3c44 100644
--- a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/DirtyCheckTransformation.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/DirtyCheckTransformation.groovy
@@ -1,4 +1,4 @@
-package org.codehaus.groovy.grails.compiler.gorm
+package org.grails.compiler.gorm
 
 import grails.gorm.dirty.checking.DirtyCheck
 import groovy.transform.CompileStatic
diff --git a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/DirtyCheckingTransformer.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/DirtyCheckingTransformer.groovy
similarity index 97%
rename from grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/DirtyCheckingTransformer.groovy
rename to grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/DirtyCheckingTransformer.groovy
index 4faf94d..41d7fde 100644
--- a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/DirtyCheckingTransformer.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/DirtyCheckingTransformer.groovy
@@ -1,6 +1,7 @@
-package org.codehaus.groovy.grails.compiler.gorm
+package org.grails.compiler.gorm
 
 import grails.artefact.Artefact
+import grails.util.GrailsClassUtils
 import groovy.transform.CompileStatic
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.ClassNode
@@ -28,15 +29,14 @@
 import org.codehaus.groovy.ast.tools.GenericsUtils
 import org.codehaus.groovy.classgen.GeneratorContext
 import org.codehaus.groovy.control.SourceUnit
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsClassUtils
-import org.codehaus.groovy.grails.commons.GrailsDomainConfigurationUtil
 import org.codehaus.groovy.grails.compiler.injection.AstTransformer
-import org.codehaus.groovy.grails.compiler.injection.GrailsArtefactClassInjector
+import grails.compiler.ast.GrailsArtefactClassInjector
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.core.support.GrailsDomainConfigurationUtil
 
-import static org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils.*
-import org.codehaus.groovy.grails.compiler.injection.GrailsDomainClassInjector
-import org.codehaus.groovy.grails.io.support.GrailsResourceUtils
+import static org.grails.compiler.injection.GrailsASTUtils.*
+import grails.compiler.ast.GrailsDomainClassInjector
+import org.grails.io.support.GrailsResourceUtils
 import org.codehaus.groovy.syntax.Token
 import org.codehaus.groovy.syntax.Types
 import org.grails.datastore.mapping.dirty.checking.DirtyCheckable
diff --git a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformer.java b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/GormTransformer.java
similarity index 82%
rename from grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformer.java
rename to grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/GormTransformer.java
index 75e6c42..d1a317c 100644
--- a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/GormTransformer.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/GormTransformer.java
@@ -13,8 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.codehaus.groovy.grails.compiler.gorm;
+package org.grails.compiler.gorm;
 
+import grails.compiler.ast.AstTransformer;
 import grails.persistence.Entity;
 import grails.persistence.PersistenceMethod;
 
@@ -31,14 +32,12 @@
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.metaclass.CreateDynamicMethod;
-import org.codehaus.groovy.grails.compiler.injection.AbstractGrailsArtefactTransformer;
-import org.codehaus.groovy.grails.compiler.injection.AstTransformer;
-import org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils;
-import org.codehaus.groovy.grails.io.support.GrailsResourceUtils;
+import org.grails.compiler.injection.AbstractGrailsArtefactTransformer;
+import org.grails.compiler.injection.GrailsASTUtils;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.grails.datastore.gorm.GormInstanceApi;
 import org.grails.datastore.gorm.GormStaticApi;
+import org.grails.io.support.GrailsResourceUtils;
 
 /**
  * Transforms GORM entities making the GORM API available to Java.
@@ -51,7 +50,8 @@
 
     public static final String NEW_INSTANCE_METHOD = "newInstance";
 
-    private static final Set<String> EXCLUDES = new HashSet<String>(Arrays.asList("create", "setTransactionManager"));
+    public static final String CREATE_METHOD_NAME = "create";
+    private static final Set<String> EXCLUDES = new HashSet<String>(Arrays.asList(CREATE_METHOD_NAME, "setTransactionManager"));
     private static final Set<String> INCLUDES = new HashSet<String>(Arrays.asList("getAll", "getCount", "getValidationSkipMap", "getValidationErrorsMap", "getAsync"));
     private static final Set<String> TRANSFORMED_CLASSES = new HashSet<String>();
 
@@ -100,10 +100,10 @@
 
         final BlockStatement methodBody = new BlockStatement();
         methodBody.addStatement(new ExpressionStatement(new MethodCallExpression(new ClassExpression(classNode), NEW_INSTANCE_METHOD,ZERO_ARGS)));
-        MethodNode methodNode = classNode.getDeclaredMethod(CreateDynamicMethod.METHOD_NAME, ZERO_PARAMETERS);
+        MethodNode methodNode = classNode.getDeclaredMethod(CREATE_METHOD_NAME, ZERO_PARAMETERS);
         classNode = GrailsASTUtils.nonGeneric(classNode);
         if (methodNode == null) {
-            classNode.addMethod(new MethodNode(CreateDynamicMethod.METHOD_NAME, PUBLIC_STATIC_MODIFIER, classNode, ZERO_PARAMETERS,null, methodBody));
+            classNode.addMethod(new MethodNode(CREATE_METHOD_NAME, PUBLIC_STATIC_MODIFIER, classNode, ZERO_PARAMETERS,null, methodBody));
         }
     }
 
diff --git a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformer.java b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/GormValidationTransformer.java
similarity index 81%
rename from grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformer.java
rename to grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/GormValidationTransformer.java
index a125b91..72b5f41 100644
--- a/grails-datastore-gorm/src/main/groovy/org/codehaus/groovy/grails/compiler/gorm/GormValidationTransformer.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/compiler/gorm/GormValidationTransformer.java
@@ -13,23 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.codehaus.groovy.grails.compiler.gorm;
+package org.grails.compiler.gorm;
 
 import java.net.URL;
 import java.util.Arrays;
 
+import grails.compiler.ast.AstTransformer;
+import grails.core.GrailsDomainClassProperty;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.PropertyNode;
 import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.compiler.injection.ASTErrorsHelper;
-import org.codehaus.groovy.grails.compiler.injection.ASTValidationErrorsHelper;
-import org.codehaus.groovy.grails.compiler.injection.AbstractGrailsArtefactTransformer;
-import org.codehaus.groovy.grails.compiler.injection.AstTransformer;
-import org.codehaus.groovy.grails.io.support.GrailsResourceUtils;
+import org.grails.compiler.injection.ASTErrorsHelper;
+import org.grails.compiler.injection.ASTValidationErrorsHelper;
+import org.grails.compiler.injection.AbstractGrailsArtefactTransformer;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.grails.datastore.gorm.GormValidationApi;
+import org.grails.io.support.GrailsResourceUtils;
 
 /**
  * Makes the validate methods statically available via an AST transformation.
@@ -38,7 +38,7 @@
  * @since 2.0
  */
 @AstTransformer
-public class GormValidationTransformer extends AbstractGrailsArtefactTransformer{
+public class GormValidationTransformer extends AbstractGrailsArtefactTransformer {
     public static final String HAS_ERRORS_METHOD = "hasErrors";
     private static final java.util.List<String> EXCLUDES = Arrays.asList(
        "setErrors", "getErrors", HAS_ERRORS_METHOD,
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy
index ac679b8..05177ea 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormEnhancer.groovy
@@ -14,13 +14,13 @@
  */
 package org.grails.datastore.gorm
 
+import grails.util.GrailsMetaClassUtils
 import grails.util.GrailsNameUtils
+import grails.validation.ConstrainedProperty
 
 import java.lang.reflect.Method
 import java.lang.reflect.Modifier
 
-import org.codehaus.groovy.grails.commons.GrailsMetaClassUtils
-import org.codehaus.groovy.grails.validation.ConstrainedProperty
 import org.codehaus.groovy.reflection.CachedMethod
 import org.codehaus.groovy.runtime.metaclass.ClosureStaticMetaMethod
 import org.codehaus.groovy.runtime.metaclass.MethodSelectionException
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormStaticApi.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormStaticApi.groovy
index 6efea51..1dcc2e2 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormStaticApi.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormStaticApi.groovy
@@ -425,8 +425,8 @@
      *
      * @return The list of all entities
      */
-    List<D> findAll() {
-        list()
+    List<D> findAll(Map params = Collections.emptyMap()) {
+        list(params)
     }
 
     /**
@@ -864,13 +864,12 @@
         (Map<D, Boolean>)AbstractDatastore.getValidationSkipMap()
     }
 
-    // TODO: In the first version no support will exist for String-based queries
     List<D> executeQuery(String query) {
-        unsupported("executeQuery")
+        executeQuery(query, Collections.emptyMap(), Collections.emptyMap())
     }
 
     List<D> executeQuery(String query, Map args) {
-        unsupported("executeQuery")
+        executeQuery(query, args, args)
     }
 
     List<D> executeQuery(String query, Map params, Map args) {
@@ -878,7 +877,11 @@
     }
 
     List<D> executeQuery(String query, Collection params) {
-        unsupported("executeQuery")
+        executeQuery(query, params, Collections.emptyMap())
+    }
+
+    List<D> executeQuery(String query, Object...params) {
+        executeQuery(query, params.toList(), Collections.emptyMap())
     }
 
     List<D> executeQuery(String query, Collection params, Map args) {
@@ -886,11 +889,11 @@
     }
 
     Integer executeUpdate(String query) {
-        unsupported("executeUpdate")
+        executeUpdate(query, Collections.emptyMap(), Collections.emptyMap())
     }
 
     Integer executeUpdate(String query, Map args) {
-        unsupported("executeUpdate")
+        executeUpdate(query, args, args)
     }
 
     Integer executeUpdate(String query, Map params, Map args) {
@@ -898,7 +901,11 @@
     }
 
     Integer executeUpdate(String query, Collection params) {
-        unsupported("executeUpdate")
+        executeUpdate(query, params, Collections.emptyMap())
+    }
+
+    Integer executeUpdate(String query, Object...params) {
+        executeUpdate(query, params.toList(), Collections.emptyMap())
     }
 
     Integer executeUpdate(String query, Collection params, Map args) {
@@ -906,11 +913,11 @@
     }
 
     D find(String query) {
-        unsupported("find")
+        find(query, Collections.emptyMap())
     }
 
     D find(String query, Map args) {
-        unsupported("find")
+        find(query, args, args)
     }
 
     D find(String query, Map params, Map args) {
@@ -918,7 +925,11 @@
     }
 
     D find(String query, Collection params) {
-        unsupported("find")
+        find(query, params, Collections.emptyMap())
+    }
+
+    D find(String query, Object[] params) {
+        find(query, params.toList(), Collections.emptyMap())
     }
 
     D find(String query, Collection params, Map args) {
@@ -926,11 +937,11 @@
     }
 
     List<D> findAll(String query) {
-        unsupported("findAll")
+        findAll(query, Collections.emptyMap(), Collections.emptyMap())
     }
 
-    List<D> findAll(String query, Map args) {
-        unsupported("findAll")
+    List<D> findAll(String query, Map params) {
+        findAll(query, params, params)
     }
 
     List<D> findAll(String query, Map params, Map args) {
@@ -938,7 +949,11 @@
     }
 
     List<D> findAll(String query, Collection params) {
-        unsupported("find")
+        findAll(query, params, Collections.emptyMap())
+    }
+
+    List<D> findAll(String query, Object[] params) {
+        findAll(query, params.toList(), Collections.emptyMap())
     }
 
     List<D> findAll(String query, Collection params, Map args) {
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormValidationApi.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormValidationApi.groovy
index 6f2f340..d3666ed 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormValidationApi.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/GormValidationApi.groovy
@@ -14,7 +14,7 @@
  */
 package org.grails.datastore.gorm
 
-import org.codehaus.groovy.grails.validation.CascadingValidator
+import grails.validation.CascadingValidator
 import org.grails.datastore.gorm.support.BeforeValidateHelper
 import org.grails.datastore.mapping.core.Datastore
 import org.grails.datastore.mapping.engine.event.ValidationEvent
@@ -145,17 +145,6 @@
         doValidate instance, (Map)null, (List)null
     }
 
-    /**
-     * Validates an instance. Note: This signature is purely here for compatibility the
-     * evict parameter does nothing and the method should be regarded as deprecated
-     *
-     * @param instance The instance to validate
-     * @return True if the instance is valid
-     */
-    @Deprecated
-    boolean validate(D instance, boolean evict) {
-        doValidate instance, (Map)null, (List)null
-    }
 
     /**
      * Obtains the errors for an instance
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/StaticQueryMethods.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/StaticQueryMethods.groovy
new file mode 100644
index 0000000..50c8393
--- /dev/null
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/StaticQueryMethods.groovy
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.grails.datastore.gorm
+
+import groovy.transform.CompileStatic
+/**
+ * 
+ * @author Jeff Brown
+ * @since 4.0
+ */
+@CompileStatic
+trait StaticQueryMethods<D> {
+    // methods removed for now...
+}
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/StaticQueryMethodsTraitInjector.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/StaticQueryMethodsTraitInjector.groovy
new file mode 100644
index 0000000..3f49c88
--- /dev/null
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/StaticQueryMethodsTraitInjector.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.grails.datastore.gorm
+
+import grails.compiler.traits.TraitInjector
+import groovy.transform.CompileStatic
+
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.io.support.GrailsResourceUtils
+
+/**
+ * 
+ * @author Jeff Brown
+ * @since 4.0
+ *
+ */
+@CompileStatic
+class StaticQueryMethodsTraitInjector implements TraitInjector {
+    
+    Class getTrait() {
+        StaticQueryMethods
+    }
+
+    @Override
+    boolean shouldInject(URL url) {
+        GrailsResourceUtils.isDomainClass(url)
+    }
+
+    @Override
+    String[] getArtefactTypes() {
+        [DomainClassArtefactHandler.TYPE] as String[]
+    }
+}
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/AsyncQuery.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/AsyncQuery.groovy
index 701ed91..c5e074d 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/AsyncQuery.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/AsyncQuery.groovy
@@ -15,8 +15,8 @@
 package org.grails.datastore.gorm.async
 
 import grails.async.DelegateAsync
-import org.grails.async.decorator.PromiseDecorator
-import org.grails.async.decorator.PromiseDecoratorProvider
+import grails.async.decorator.PromiseDecorator
+import grails.async.decorator.PromiseDecoratorProvider
 import org.grails.datastore.gorm.query.GormOperations
 
 /**
@@ -25,7 +25,7 @@
  * @author Graeme Rocher
  * @since 2.3
  */
-class AsyncQuery<E> implements PromiseDecoratorProvider{
+class AsyncQuery<E> implements PromiseDecoratorProvider {
 
     @DelegateAsync GormOperations<E> gormOperations
 
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/GormAsyncStaticApi.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/GormAsyncStaticApi.groovy
index 1e02cbb..c990a64 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/GormAsyncStaticApi.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/async/GormAsyncStaticApi.groovy
@@ -16,9 +16,9 @@
 
 import grails.async.Promise
 import grails.async.Promises
+import grails.async.decorator.PromiseDecorator
+import grails.async.decorator.PromiseDecoratorProvider
 import groovy.transform.CompileStatic
-import org.grails.async.decorator.PromiseDecorator
-import org.grails.async.decorator.PromiseDecoratorProvider
 import org.grails.datastore.gorm.GormStaticApi
 
 /**
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bean/factory/AbstractMappingContextFactoryBean.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bean/factory/AbstractMappingContextFactoryBean.groovy
index dcfc02f..099c4fa 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bean/factory/AbstractMappingContextFactoryBean.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bean/factory/AbstractMappingContextFactoryBean.groovy
@@ -14,11 +14,11 @@
  */
 package org.grails.datastore.gorm.bean.factory
 
+import grails.core.GrailsApplication
+import grails.core.GrailsDomainClass
+import grails.core.support.GrailsApplicationAware
 import org.apache.commons.logging.Log
 import org.apache.commons.logging.LogFactory
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.commons.GrailsDomainClass
-import org.codehaus.groovy.grails.plugins.support.aware.GrailsApplicationAware
 import org.grails.datastore.gorm.proxy.GroovyProxyFactory
 import org.grails.datastore.mapping.model.MappingContext
 import org.grails.datastore.mapping.model.PersistentEntity
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bootstrap/AbstractDatastoreInitializer.groovy b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bootstrap/AbstractDatastoreInitializer.groovy
index 9a81a65..429349a 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bootstrap/AbstractDatastoreInitializer.groovy
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/bootstrap/AbstractDatastoreInitializer.groovy
@@ -1,14 +1,17 @@
 package org.grails.datastore.gorm.bootstrap
 
+import grails.config.Config
+import grails.core.DefaultGrailsApplication
+import grails.core.GrailsApplication
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler
-import org.codehaus.groovy.grails.commons.GrailsApplication
-import org.codehaus.groovy.grails.compiler.gorm.GormTransformer
-import org.codehaus.groovy.grails.validation.GrailsDomainClassValidator
+import org.grails.compiler.gorm.GormTransformer
+import org.grails.config.PropertySourcesConfig
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.validation.GrailsDomainClassValidator
 import org.springframework.beans.factory.config.MethodInvokingFactoryBean
 import org.springframework.beans.factory.support.BeanDefinitionRegistry
 import org.springframework.context.ResourceLoaderAware
+import org.springframework.core.env.MutablePropertySources
 import org.springframework.core.io.Resource
 import org.springframework.core.io.ResourceLoader
 import org.springframework.core.io.support.PathMatchingResourcePatternResolver
@@ -29,8 +32,9 @@
     ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver()
     Collection<Class> persistentClasses = []
     Collection<String> packages = []
-    Properties configuration = new Properties()
-    ConfigObject configurationObject = new ConfigObject()
+    Map configuration = new LinkedHashMap()
+    Config configurationObject = new PropertySourcesConfig()
+    boolean registerApplicationIfNotPresent = true
 
     protected ClassLoader classLoader = Thread.currentThread().contextClassLoader
 
@@ -53,12 +57,18 @@
         this(persistentClasses.toList())
     }
 
-    AbstractDatastoreInitializer(Properties configuration, Collection<Class> persistentClasses) {
+    AbstractDatastoreInitializer(Map configuration, Collection<Class> persistentClasses) {
         this.configuration = configuration
         this.persistentClasses = persistentClasses
+        if(configuration instanceof Config) {
+            this.configurationObject = (Config)configuration
+        }
+        else {
+            this.configurationObject.merge((Map<String,Object>)configuration)
+        }
     }
 
-    AbstractDatastoreInitializer(Properties configuration, Class... persistentClasses) {
+    AbstractDatastoreInitializer(Map configuration, Class... persistentClasses) {
         this(configuration, persistentClasses.toList())
     }
 
@@ -113,7 +123,7 @@
      */
     @CompileStatic
     void configureForBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) {
-        this.configurationObject = new ConfigSlurper().parse(configuration)
+
         scanForPersistentClasses()
 
         ExpandoMetaClass.enableGlobally()
@@ -135,7 +145,7 @@
             context.'annotation-config'()
 
 
-            if(!registry.containsBeanDefinition(GrailsApplication.APPLICATION_ID)) {
+            if(!registry.containsBeanDefinition(GrailsApplication.APPLICATION_ID) && registerApplicationIfNotPresent) {
                 grailsApplication(DefaultGrailsApplication, persistentClasses as Class[], Thread.currentThread().contextClassLoader) { bean ->
                     bean.initMethod = 'initialise'
                 }
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassMappingContext.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassMappingContext.java
index febd49a..2411338 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassMappingContext.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassMappingContext.java
@@ -15,10 +15,10 @@
 
 package org.grails.datastore.gorm.config;
 
-import org.codehaus.groovy.grails.commons.DomainClassArtefactHandler;
-import org.codehaus.groovy.grails.commons.GrailsApplication;
-import org.codehaus.groovy.grails.commons.GrailsClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
+import grails.core.GrailsApplication;
+import grails.core.GrailsClass;
+import grails.core.GrailsDomainClass;
+import org.grails.core.artefact.DomainClassArtefactHandler;
 import org.grails.datastore.mapping.model.AbstractMappingContext;
 import org.grails.datastore.mapping.model.MappingConfigurationStrategy;
 import org.grails.datastore.mapping.model.MappingFactory;
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentEntity.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentEntity.java
index ca36bf8..de144cc 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentEntity.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentEntity.java
@@ -20,8 +20,8 @@
 import java.util.List;
 import java.util.Map;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClass;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClass;
+import grails.core.GrailsDomainClassProperty;
 import org.grails.datastore.mapping.model.ClassMapping;
 import org.grails.datastore.mapping.model.MappingContext;
 import org.grails.datastore.mapping.model.PersistentEntity;
@@ -275,9 +275,9 @@
             association.setReferencedPropertyName(referencedPropertyName);
         }
         else {
-            GrailsDomainClassProperty otherSide = grailsDomainClassProperty.getOtherSide();
-            if(otherSide != null) {
-                association.setReferencedPropertyName(otherSide.getName());
+        GrailsDomainClassProperty otherSide = grailsDomainClassProperty.getOtherSide();
+        if(otherSide != null) {
+            association.setReferencedPropertyName(otherSide.getName());
             }
         }
     }
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentProperty.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentProperty.java
index fe9d65e..4f73e74 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentProperty.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/config/GrailsDomainClassPersistentProperty.java
@@ -15,7 +15,7 @@
 
 package org.grails.datastore.gorm.config;
 
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
+import grails.core.GrailsDomainClassProperty;
 import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.model.PersistentProperty;
 import org.grails.datastore.mapping.model.PropertyMapping;
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/AbstractFindByFinder.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/AbstractFindByFinder.java
index 36da346..882dcc9 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/AbstractFindByFinder.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/AbstractFindByFinder.java
@@ -27,14 +27,7 @@
     }
 
     protected Object invokeQuery(Query q) {
-        q.max(1);
-
-        List<?> results = q.list();
-        if (results.isEmpty()) {
-            return null;
-        }
-
-        return results.get(0);
+        return q.singleResult();
     }
 
     public boolean firstExpressionIsRequiredBoolean() {
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/DynamicFinder.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/DynamicFinder.java
index 3d48e5c..e8efa09 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/DynamicFinder.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/DynamicFinder.java
@@ -15,15 +15,12 @@
 package org.grails.datastore.gorm.finders;
 
 import grails.gorm.DetachedCriteria;
+import grails.util.GrailsClassUtils;
 import groovy.lang.Closure;
 import groovy.lang.MissingMethodException;
 
 import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
+import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -60,6 +57,11 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public abstract class DynamicFinder extends AbstractFinder implements QueryBuildingFinder {
 
+
+    public static final String ARGUMENT_FETCH_SIZE = "fetchSize";
+    public static final String ARGUMENT_TIMEOUT = "timeout";
+    public static final String ARGUMENT_READ_ONLY = "readOnly";
+    public static final String ARGUMENT_FLUSH_MODE = "flushMode";
     public static final String ARGUMENT_MAX = "max";
     public static final String ARGUMENT_OFFSET = "offset";
     public static final String ARGUMENT_ORDER = "order";
@@ -71,6 +73,8 @@
     public static final String ARGUMENT_CACHE = "cache";
     public static final String ARGUMENT_LOCK = "lock";
 
+
+
     protected Pattern pattern;
     private Pattern[] operatorPatterns;
     private String[] operators;
@@ -384,8 +388,13 @@
             }
         }
 
-        final String sort = (String)argMap.get(ARGUMENT_SORT);
-        final String order = ORDER_DESC.equalsIgnoreCase(orderParam) ? ORDER_DESC : ORDER_ASC;
+        if(argMap.containsKey(ARGUMENT_CACHE)) {
+            q.cache(GrailsClassUtils.getBooleanFromMap(ARGUMENT_CACHE, argMap));
+        }
+        if(argMap.containsKey(ARGUMENT_LOCK)) {
+            q.lock(GrailsClassUtils.getBooleanFromMap(ARGUMENT_LOCK, argMap));
+        }
+
         final int max = maxParam == null ? -1 : maxParam;
         final int offset = offsetParam == null ? -1 : offsetParam;
         if (max > -1) {
@@ -394,19 +403,52 @@
         if (offset > -1) {
             q.offset(offset);
         }
-        if (sort != null) {
-            if (ORDER_DESC.equalsIgnoreCase(order)) {
-                q.order(Query.Order.desc(sort));
+        Object sortObject = argMap.get(ARGUMENT_SORT);
+        boolean ignoreCase = !argMap.containsKey(ARGUMENT_IGNORE_CASE) || GrailsClassUtils.getBooleanFromMap(ARGUMENT_IGNORE_CASE, argMap);
+
+        if (sortObject != null) {
+            if(sortObject instanceof CharSequence) {
+                final String sort = sortObject.toString();
+                final String order = ORDER_DESC.equalsIgnoreCase(orderParam) ? ORDER_DESC : ORDER_ASC;
+                addSimpleSort(q, sort, order, ignoreCase);
             }
-            else {
-                q.order(Query.Order.asc(sort));
+            else if(sortObject instanceof Map) {
+                Map sortMap = (Map)sortObject;
+                applySortForMap(q, sortMap, ignoreCase);
+
             }
         }
+
         if (q instanceof QueryArgumentsAware) {
             ((QueryArgumentsAware)q).setArguments(argMap);
         }
     }
 
+
+    private static void addSimpleSort(Query q, String sort, String order, boolean ignoreCase) {
+        Query.Order o;
+        if (ORDER_DESC.equalsIgnoreCase(order)) {
+            o = Query.Order.desc(sort);
+        }
+        else {
+            o = Query.Order.asc(sort);
+        }
+
+        if(ignoreCase) o = o.ignoreCase();
+
+        q.order(o);
+    }
+
+    public static void applySortForMap(Query q, Map sortMap, boolean ignoreCase) {
+        for (Object key : sortMap.keySet()) {
+            Object value = sortMap.get(key);
+            String sort = key.toString();
+            String order = value != null ? value.toString() : ORDER_ASC;
+
+            addSimpleSort(q, sort, order, ignoreCase);
+        }
+    }
+
     /**
      * Retrieves the fetch mode for the specified instance; otherwise returns the default FetchMode.
      *
@@ -426,6 +468,7 @@
 
     protected void configureQueryWithArguments(Class clazz, Query query, Object[] arguments) {
         if (arguments.length == 0 || !(arguments[0] instanceof Map)) {
+            populateArgumentsForCriteria(clazz, query, Collections.emptyMap());
             return;
         }
 
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/MethodExpression.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/MethodExpression.java
index 1c0cc53..5318054 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/MethodExpression.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/finders/MethodExpression.java
@@ -16,10 +16,7 @@
 
 import groovy.lang.Range;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
 
 import org.grails.datastore.mapping.model.PersistentEntity;
 import org.grails.datastore.mapping.model.PersistentProperty;
@@ -184,9 +181,12 @@
 
         @Override
         public void setArguments(Object[] arguments) {
-            Assert.isTrue(arguments.length > 0 && arguments[0] instanceof Collection,
+            Assert.isTrue(arguments.length > 0,
                 "Only a collection of elements is supported in an 'in' query");
 
+            Object arg = arguments[0];
+            Assert.isTrue( (arg instanceof Collection) || arg == null, "Only a collection of elements is supported in an 'in' query");
+
             super.setArguments(arguments);
         }
 
@@ -204,12 +204,18 @@
             if (prop != null) {
                 Class<?> type = prop.getType();
                 Collection<?> collection = (Collection<?>) arguments[0];
-                List<Object> converted = new ArrayList<Object>(collection.size());
-                for (Object o : collection) {
-                    if (o != null && !type.isAssignableFrom(o.getClass())) {
-                        o = conversionService.convert(o, type);
+                List<Object> converted;
+                if(collection == null) {
+                    converted = Collections.emptyList();
+                }
+                else {
+                    converted = new ArrayList<Object>(collection.size());
+                    for (Object o : collection) {
+                        if (o != null && !type.isAssignableFrom(o.getClass())) {
+                            o = conversionService.convert(o, type);
+                        }
+                        converted.add(o);
                     }
-                    converted.add(o);
                 }
                 arguments[0] = converted;
             }
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/query/transform/DetachedCriteriaTransformer.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/query/transform/DetachedCriteriaTransformer.java
index 8bcc3e7..3f3ea46 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/query/transform/DetachedCriteriaTransformer.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/query/transform/DetachedCriteriaTransformer.java
@@ -14,8 +14,10 @@
  */
 package org.grails.datastore.gorm.query.transform;
 
+import grails.core.GrailsDomainClassProperty;
 import grails.gorm.DetachedCriteria;
 import grails.persistence.Entity;
+import grails.util.GrailsClassUtils;
 import grails.util.GrailsNameUtils;
 
 import java.io.File;
@@ -66,9 +68,7 @@
 import org.codehaus.groovy.ast.stmt.*;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.control.messages.LocatedMessage;
-import org.codehaus.groovy.grails.commons.GrailsClassUtils;
-import org.codehaus.groovy.grails.commons.GrailsDomainClassProperty;
-import org.codehaus.groovy.grails.compiler.injection.GrailsASTUtils;
+import org.grails.compiler.injection.GrailsASTUtils;
 import org.codehaus.groovy.syntax.Token;
 import org.grails.datastore.mapping.query.Query;
 import org.grails.datastore.mapping.query.criteria.FunctionCallingCriterion;
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/DatastorePersistenceContextInterceptor.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/DatastorePersistenceContextInterceptor.java
index 6076d71..bd06382 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/DatastorePersistenceContextInterceptor.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/DatastorePersistenceContextInterceptor.java
@@ -16,9 +16,9 @@
 
 import javax.persistence.FlushModeType;
 
+import grails.persistence.support.PersistenceContextInterceptor;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.codehaus.groovy.grails.support.PersistenceContextInterceptor;
 import org.grails.datastore.mapping.core.Datastore;
 import org.grails.datastore.mapping.core.DatastoreUtils;
 import org.grails.datastore.mapping.core.Session;
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/EventTriggerCaller.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/EventTriggerCaller.java
index 156bcf5..a2fe37e 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/EventTriggerCaller.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/support/EventTriggerCaller.java
@@ -51,13 +51,7 @@
     }
 
     private static EventTriggerCaller resolveMetaMethodCaller(String eventMethodName, MetaClass metaClass) {
-        MetaMethod metaMethod = null;
-        for(MetaMethod mm : metaClass.getMetaMethods()) {
-            if(eventMethodName.equals(mm.getName())) {
-                metaMethod = mm;
-                break;
-            }
-        }
+        MetaMethod metaMethod = metaClass.getMetaMethod(eventMethodName, EMPTY_ARRAY);
         if (metaMethod != null) {
             return new MetaMethodCaller(metaMethod);
         }
diff --git a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/validation/CascadingValidator.java b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/validation/CascadingValidator.java
index 735ce82..a0474ff 100644
--- a/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/validation/CascadingValidator.java
+++ b/grails-datastore-gorm/src/main/groovy/org/grails/datastore/gorm/validation/CascadingValidator.java
@@ -21,7 +21,7 @@
  * Extends the default Spring Validator interface and provides an additional method that specifies whether
  * validation should cascade into associations.
  */
-public interface CascadingValidator extends Validator, org.codehaus.groovy.grails.validation.CascadingValidator {
+public interface CascadingValidator extends Validator, grails.validation.CascadingValidator {
 
     /**
      * An extended version of the validate(errors,obj) method that takes an additional argument specifying whether
diff --git a/grails-datastore-gorm/src/main/resources/META-INF/grails.factories b/grails-datastore-gorm/src/main/resources/META-INF/grails.factories
new file mode 100644
index 0000000..a27221e
--- /dev/null
+++ b/grails-datastore-gorm/src/main/resources/META-INF/grails.factories
@@ -0,0 +1 @@
+grails.compiler.traits.TraitInjector=org.grails.datastore.gorm.StaticQueryMethodsTraitInjector
diff --git a/grails-datastore-gorm/src/test/groovy/org/grails/datastore/gorm/StaticQueryMethodsTraitSpec.groovy b/grails-datastore-gorm/src/test/groovy/org/grails/datastore/gorm/StaticQueryMethodsTraitSpec.groovy
new file mode 100644
index 0000000..6949eaf
--- /dev/null
+++ b/grails-datastore-gorm/src/test/groovy/org/grails/datastore/gorm/StaticQueryMethodsTraitSpec.groovy
@@ -0,0 +1,39 @@
+package org.grails.datastore.gorm
+
+import grails.artefact.Artefact
+import grails.persistence.Entity
+import spock.lang.Specification
+
+class StaticQueryMethodsTraitSpec extends Specification {
+
+    void "test that a class marked with @Artefact('Domain') is enhanced with StaticQueryMethods"() {
+        expect:
+        StaticQueryMethods.isAssignableFrom QueryMethodArtefactDomain
+    }
+    
+    void "test that a class marked with @Entity is enhanced with StaticQueryMethods"() {
+        expect:
+        StaticQueryMethods.isAssignableFrom QueryMethodEntityDomain
+    }
+    
+    void 'test that generic return values are respected'() {
+        when:
+        def method = QueryMethodArtefactDomain.methods.find { method ->
+            def rt = method.getParameterTypes()
+            rt && rt[0] == Closure && method.name == 'find'
+        }
+        
+        then:
+        method.returnType == QueryMethodArtefactDomain
+    }
+}
+
+@Artefact('Domain')
+class QueryMethodArtefactDomain {
+    String name
+}
+
+@Entity
+class QueryMethodEntityDomain {
+    String name
+}
diff --git a/grails-datastore-gorm/src/test/groovy/org/grails/datastore/gorm/timestamp/AggregateTimestampProviderSpec.groovy b/grails-datastore-gorm/src/test/groovy/org/grails/datastore/gorm/timestamp/AggregateTimestampProviderSpec.groovy
index 3c5fe52..1fbc7bb 100644
--- a/grails-datastore-gorm/src/test/groovy/org/grails/datastore/gorm/timestamp/AggregateTimestampProviderSpec.groovy
+++ b/grails-datastore-gorm/src/test/groovy/org/grails/datastore/gorm/timestamp/AggregateTimestampProviderSpec.groovy
@@ -2,7 +2,7 @@
 
 import grails.spring.BeanBuilder
 
-import org.codehaus.groovy.grails.commons.InstanceFactoryBean
+import org.grails.spring.beans.factory.InstanceFactoryBean
 
 import spock.lang.Specification
 
diff --git a/grails-datastore-jcr/src/test/groovy/grails/persistence/Entity.java b/grails-datastore-jcr/src/test/groovy/grails/persistence/Entity.java
deleted file mode 100644
index c7e431b..0000000
--- a/grails-datastore-jcr/src/test/groovy/grails/persistence/Entity.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package grails.persistence;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * @author Graeme Rocher
- * @since 1.1
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target({ElementType.TYPE})
-public @interface Entity {
-}
\ No newline at end of file
diff --git a/grails-datastore-jpa/build.gradle b/grails-datastore-jpa/build.gradle
index 61606b0..5e68a90 100644
--- a/grails-datastore-jpa/build.gradle
+++ b/grails-datastore-jpa/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 configurations {
     grails
diff --git a/grails-datastore-rest-client/build.gradle b/grails-datastore-rest-client/build.gradle
index 3b483f4..5376c11 100644
--- a/grails-datastore-rest-client/build.gradle
+++ b/grails-datastore-rest-client/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.2.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 dependencies {
     compile 'javax.servlet:javax.servlet-api:3.0.1'
 //    compile("org.grails:grails-plugin-codecs:$grailsVersion") {
@@ -17,6 +17,8 @@
 //        exclude group:'org.grails', module:'grails-plugin-controllers'
 //        exclude group:'org.grails', module:'grails-web'
 //    }
+
+    compile("org.grails:grails-async:$grailsVersion")
     compile("org.grails:grails-core:$grailsVersion") {
         exclude group:'commons-collections', module:'commons-collections'
         exclude group:'com.googlecode.concurrentlinkedhashmap', module:'concurrentlinkedhashmap-lru'
@@ -33,6 +35,7 @@
         exclude group:'asm', module:'asm'
         exclude group:'aopalliance', module:'aopalliance'
         exclude group:'cglib', module:'cglib'
+        exclude group:'cglib', module:'cglib-nodep'
         exclude group:'commons-validator', module:'commons-validator'
         exclude group:'org.hibernate.javax.persistence', module:'hibernate-jpa-2.0-api'
     }
diff --git a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RequestCustomizer.groovy b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RequestCustomizer.groovy
index 4b7dac4..f4b9541 100644
--- a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RequestCustomizer.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RequestCustomizer.groovy
@@ -21,7 +21,7 @@
 import groovy.util.slurpersupport.GPathResult
 import groovy.xml.StreamingMarkupBuilder
 import org.apache.commons.codec.binary.Base64
-import org.codehaus.groovy.grails.web.json.JSONElement
+import org.grails.web.json.JSONElement
 import org.springframework.core.io.FileSystemResource
 import org.springframework.core.io.InputStreamResource
 import org.springframework.core.io.UrlResource
@@ -31,7 +31,7 @@
 import org.springframework.util.LinkedMultiValueMap
 import org.springframework.util.MultiValueMap
 
-import static org.codehaus.groovy.grails.web.servlet.HttpHeaders.*
+import static grails.web.http.HttpHeaders.*
 
 /**
  * Core of the DSL for building REST requests
@@ -171,7 +171,7 @@
      * @return The customizer
      */
     RequestCustomizer header(String name, String value) {
-        headers[name] = value
+        headers.add name, value
         return this
     }
 
diff --git a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestBuilder.groovy b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestBuilder.groovy
index 05101cf..756aca2 100644
--- a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestBuilder.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestBuilder.groovy
@@ -14,31 +14,32 @@
  */
 package grails.plugins.rest.client
 
+import static org.springframework.http.HttpMethod.*
+
+import java.net.Proxy
+
 import grails.converters.JSON
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationHolder
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationInitializer
-import org.codehaus.groovy.grails.web.converters.configuration.DefaultConverterConfiguration
+
 import org.grails.datastore.gorm.rest.client.json.GsonHttpMessageConverter
 import org.grails.datastore.gorm.rest.client.json.JsonHttpMessageConverter
 import org.grails.datastore.gorm.rest.client.utils.GrailsConverterHttpMessageConverter
 import org.grails.datastore.gorm.rest.client.utils.NullSafeStringHttpMessageConverter
 import org.grails.datastore.gorm.rest.client.utils.WritableHttpMessageConverter
 import org.grails.datastore.gorm.rest.client.xml.GPathXmlHttpMessageConverter
+import org.grails.web.converters.configuration.ConvertersConfigurationHolder
+import org.grails.web.converters.configuration.ConvertersConfigurationInitializer
+import org.grails.web.converters.configuration.DefaultConverterConfiguration
 import org.springframework.http.HttpMethod
 import org.springframework.http.ResponseEntity
 import org.springframework.http.client.SimpleClientHttpRequestFactory
 import org.springframework.http.converter.HttpMessageConverter
 import org.springframework.http.converter.StringHttpMessageConverter
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
-import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter
 import org.springframework.util.ClassUtils
 import org.springframework.web.client.HttpStatusCodeException
 import org.springframework.web.client.RestTemplate
 
-import static org.springframework.http.HttpMethod.*
-
 /**
  * Main API entry to the synchronous version of the REST low-level client API
  *
@@ -54,7 +55,7 @@
 
         if(ConvertersConfigurationHolder.getConverterConfiguration(JSON) instanceof DefaultConverterConfiguration) {
             // init manually
-            new ConvertersConfigurationInitializer().initialize(new DefaultGrailsApplication())
+            new ConvertersConfigurationInitializer().initialize()
         }
 
         Proxy proxyFromSystemProperties = getProxyForSystemProperties()
@@ -288,10 +289,6 @@
         if(mappingJackson2HttpMessageConverter) {
             messageConverters.remove(mappingJackson2HttpMessageConverter)
         }
-        final mappingJacksonHttpMessageConverter = messageConverters.find { HttpMessageConverter httpMessageConverter -> httpMessageConverter instanceof MappingJacksonHttpMessageConverter }
-        if(mappingJacksonHttpMessageConverter) {
-            messageConverters.remove(mappingJacksonHttpMessageConverter)
-        }
         if(ClassUtils.isPresent("com.google.gson.Gson", getClass().getClassLoader())) {
             messageConverters.add(new GsonHttpMessageConverter())
         }
diff --git a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestResponse.groovy b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestResponse.groovy
index d21b4cb..5d3f5db 100644
--- a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestResponse.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/RestResponse.groovy
@@ -20,7 +20,7 @@
 import groovy.transform.TypeCheckingMode
 import groovy.util.slurpersupport.GPathResult
 import groovy.xml.StreamingMarkupBuilder
-import org.codehaus.groovy.grails.web.json.JSONElement
+import org.grails.web.json.JSONElement
 import org.springframework.http.ResponseEntity
 import org.springframework.web.client.HttpStatusCodeException
 
diff --git a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/async/templated/AsyncJsonResourcesClient.groovy b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/async/templated/AsyncJsonResourcesClient.groovy
index 01ed517..012adc3 100644
--- a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/async/templated/AsyncJsonResourcesClient.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/async/templated/AsyncJsonResourcesClient.groovy
@@ -19,7 +19,7 @@
 import grails.plugins.rest.client.async.AsyncRestBuilder
 import grails.plugins.rest.client.templated.JsonResourcesClient
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.json.JSONElement
+import org.grails.web.json.JSONElement
 import org.springframework.http.MediaType
 
 /**
diff --git a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/JsonResourcesClient.groovy b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/JsonResourcesClient.groovy
index 7164e69..bf02c34 100644
--- a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/JsonResourcesClient.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/JsonResourcesClient.groovy
@@ -18,9 +18,9 @@
 import grails.plugins.rest.client.RestBuilder
 import grails.plugins.rest.client.RestResponse
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.converters.ConverterUtil
-import org.codehaus.groovy.grails.web.json.JSONElement
 import org.codehaus.groovy.runtime.typehandling.GroovyCastException
+import org.grails.web.converters.ConverterUtil
+import org.grails.web.json.JSONElement
 
 /**
  * A simple client for interacting with a REST web service exposed by a Grails application
diff --git a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/XmlResourcesClient.groovy b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/XmlResourcesClient.groovy
index f6937bd..22e7c80 100644
--- a/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/XmlResourcesClient.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/grails/plugins/rest/client/templated/XmlResourcesClient.groovy
@@ -18,8 +18,8 @@
 import grails.plugins.rest.client.RestBuilder
 import groovy.transform.CompileStatic
 import groovy.util.slurpersupport.GPathResult
-import org.codehaus.groovy.grails.web.converters.ConverterUtil
 import org.codehaus.groovy.runtime.typehandling.GroovyCastException
+import org.grails.web.converters.ConverterUtil
 
 /**
  *
diff --git a/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/json/JsonHttpMessageConverter.groovy b/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/json/JsonHttpMessageConverter.groovy
index ac9d319..94d3a7c 100644
--- a/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/json/JsonHttpMessageConverter.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/json/JsonHttpMessageConverter.groovy
@@ -16,7 +16,7 @@
 
 import grails.converters.JSON
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.json.JSONElement
+import org.grails.web.json.JSONElement
 import org.springframework.http.HttpInputMessage
 import org.springframework.http.HttpOutputMessage
 import org.springframework.http.MediaType
diff --git a/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/utils/GrailsConverterHttpMessageConverter.groovy b/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/utils/GrailsConverterHttpMessageConverter.groovy
index ce52b15..cad6a45 100644
--- a/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/utils/GrailsConverterHttpMessageConverter.groovy
+++ b/grails-datastore-rest-client/src/main/groovy/org/grails/datastore/gorm/rest/client/utils/GrailsConverterHttpMessageConverter.groovy
@@ -15,7 +15,7 @@
 package org.grails.datastore.gorm.rest.client.utils
 
 import groovy.transform.CompileStatic
-import org.codehaus.groovy.grails.web.converters.Converter
+import org.grails.web.converters.Converter
 import org.springframework.http.HttpInputMessage
 import org.springframework.http.HttpOutputMessage
 import org.springframework.http.MediaType
diff --git a/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/AsyncRestBuilderSpec.groovy b/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/AsyncRestBuilderSpec.groovy
index e086486..950121f 100644
--- a/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/AsyncRestBuilderSpec.groovy
+++ b/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/AsyncRestBuilderSpec.groovy
@@ -4,12 +4,10 @@
 import grails.converters.JSON
 import grails.plugins.rest.client.async.AsyncRestBuilder
 import grails.web.JSONBuilder
+import grails.web.http.HttpHeaders
 import groovy.util.slurpersupport.GPathResult
-import org.codehaus.groovy.grails.commons.DefaultGrailsApplication
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationHolder
-import org.codehaus.groovy.grails.web.converters.configuration.ConvertersConfigurationInitializer
-import org.codehaus.groovy.grails.web.json.JSONArray
-import org.codehaus.groovy.grails.web.json.JSONObject
+import org.grails.web.json.JSONArray
+import org.grails.web.json.JSONObject
 import spock.lang.Issue
 import spock.lang.Specification
 
@@ -21,7 +19,6 @@
 import org.springframework.http.HttpMethod
 
 import static org.springframework.test.web.client.match.MockRestRequestMatchers.header
-import org.codehaus.groovy.grails.web.servlet.HttpHeaders
 
 import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess
 import org.springframework.http.MediaType
diff --git a/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/RestBuilderSpec.groovy b/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/RestBuilderSpec.groovy
index 7651cd4..a7fac30 100644
--- a/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/RestBuilderSpec.groovy
+++ b/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/RestBuilderSpec.groovy
@@ -2,10 +2,10 @@
 
 import grails.converters.JSON
 import grails.web.JSONBuilder
+import grails.web.http.HttpHeaders
 import groovy.util.slurpersupport.GPathResult
-import org.codehaus.groovy.grails.web.json.JSONArray
-import org.codehaus.groovy.grails.web.json.JSONObject
-import org.codehaus.groovy.grails.web.servlet.HttpHeaders
+import org.grails.web.json.JSONArray
+import org.grails.web.json.JSONObject
 import org.springframework.http.HttpMethod
 import org.springframework.http.HttpStatus
 import org.springframework.http.MediaType
diff --git a/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/templated/JsonResourcesClientSpec.groovy b/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/templated/JsonResourcesClientSpec.groovy
index 622008a..a574a94 100644
--- a/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/templated/JsonResourcesClientSpec.groovy
+++ b/grails-datastore-rest-client/src/test/groovy/grails/plugins/rest/client/templated/JsonResourcesClientSpec.groovy
@@ -1,7 +1,7 @@
 package grails.plugins.rest.client.templated
 
 import grails.plugins.rest.client.RestBuilder
-import org.codehaus.groovy.grails.web.json.JSONObject
+import org.grails.web.json.JSONObject
 import org.springframework.http.HttpMethod
 import org.springframework.http.HttpStatus
 import org.springframework.http.MediaType
@@ -87,6 +87,7 @@
 
     }
 
+    @spock.lang.Ignore
     void "Test that the post method correctly sends JSON to the appropriate URL"() {
         setup:
             RestBuilder restBuilder = new RestBuilder()
diff --git a/grails-datastore-riak/build.gradle b/grails-datastore-riak/build.gradle
index 7b4bda7..d0c097e 100644
--- a/grails-datastore-riak/build.gradle
+++ b/grails-datastore-riak/build.gradle
@@ -1,4 +1,4 @@
-version = "1.0.0.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 dependencies {
     compile project(":grails-datastore-core"),
diff --git a/grails-datastore-simpledb/build.gradle b/grails-datastore-simpledb/build.gradle
index 262f04f..22d3b64 100644
--- a/grails-datastore-simpledb/build.gradle
+++ b/grails-datastore-simpledb/build.gradle
@@ -1,4 +1,4 @@
-version = "0.6.BUILD-SNAPSHOT"
+//version = "4.0.0.BUILD-SNAPSHOT"
 
 dependencies {
     compile project(":grails-datastore-core")
diff --git a/grails-plugins/hibernate/build.gradle b/grails-plugins/hibernate/build.gradle
new file mode 100644
index 0000000..6518038
--- /dev/null
+++ b/grails-plugins/hibernate/build.gradle
@@ -0,0 +1,44 @@
+
+group = "org.grails.plugins"
+version = "4.3.5.5.BUILD-SNAPSHOT"
+
+apply from:'https://raw.githubusercontent.com/grails/grails-boot/master/gradle/maven-central-build.gradle'
+
+configurations {
+    provided
+}
+
+dependencies {
+
+
+    provided("org.grails:grails-core:$grailsVersion")
+    compile 'org.codehaus.groovy:groovy:2.3.7'
+
+    compile project(":grails-datastore-gorm-hibernate4"), {
+        exclude group:'org.springframework', module:'spring-context'
+        exclude group:'org.springframework', module:'spring-core'
+        exclude group:'org.springframework', module:'spring-beans'
+        exclude group:'org.springframework', module:'spring-tx'
+        exclude group:'org.grails', module:'grails-bootstrap'
+        exclude group:'org.codehaus.groovy', module:'groovy-all'
+        exclude group:'org.grails', module:'grails-core'
+        exclude group:'org.grails', module:'grails-async'
+        exclude group:'javax.transaction', module:'jta'
+    }
+}
+
+sourceSets {
+    main {
+        compileClasspath += configurations.provided
+    }
+    javadoc {
+        classpath = configurations.compile + configurations.provided
+    }
+}
+
+def installer = install.repositories.mavenInstaller
+def deployer = uploadArchives.repositories.mavenDeployer
+
+[installer, deployer]*.pom*.whenConfigured { pom ->
+    pom.artifactId = 'hibernate'
+}
\ No newline at end of file
diff --git a/grails-plugins/hibernate/src/main/groovy/grails/plugin/hibernate/HibernateGrailsPlugin.groovy b/grails-plugins/hibernate/src/main/groovy/grails/plugin/hibernate/HibernateGrailsPlugin.groovy
new file mode 100644
index 0000000..8d52e44
--- /dev/null
+++ b/grails-plugins/hibernate/src/main/groovy/grails/plugin/hibernate/HibernateGrailsPlugin.groovy
@@ -0,0 +1,76 @@
+package grails.plugin.hibernate
+
+import grails.config.Config
+import grails.core.GrailsApplication
+import grails.core.GrailsClass
+import grails.core.GrailsDomainClassProperty
+import grails.core.support.GrailsApplicationAware
+import grails.orm.bootstrap.HibernateDatastoreSpringInitializer
+import grails.plugins.Plugin
+import groovy.transform.CompileStatic
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.springframework.beans.factory.support.BeanDefinitionRegistry
+
+/**
+ * Plugin that integrates Hibernate into a Grails application
+ *
+ * @author Graeme Rocher
+ * @since 3.0
+ */
+@CompileStatic
+class HibernateGrailsPlugin extends Plugin {
+
+
+    def version = '4.3.5.5-SNAPSHOT'
+    def grailsVersion = '2.3.5 > *'
+    def author = 'Burt Beckwith'
+    def title = 'Hibernate 4 for Grails'
+    def description = 'Provides integration between Grails and Hibernate 4 through GORM'
+    def documentation = 'http://grails.org/plugin/hibernate4'
+
+    def observe = ['domainClass']
+    def loadAfter = ['controllers', 'domainClass']
+    def watchedResources = ['file:./grails-app/conf/hibernate/**.xml']
+    def pluginExcludes = ['src/templates/**']
+
+    def license = 'APACHE'
+    def organization = [name: 'Pivotal', url: 'http://pivotal.io']
+    def issueManagement = [system: 'JIRA', url: 'http://jira.grails.org/browse/GPHIB']
+    def scm = [url: 'https://github.com/grails-plugins/grails-hibernate4-plugin']
+
+
+    Closure doWithSpring() {{->
+        GrailsApplication grailsApplication = grailsApplication
+        Set<String> datasourceNames = []
+
+        Config config = grailsApplication.config
+        Map dataSources = config.getProperty('dataSources', Map, [:])
+
+        if(dataSources) {
+            for (name in config.keySet()) {
+                if(name == 'dataSource') {
+                    datasourceNames << GrailsDomainClassProperty.DEFAULT_DATA_SOURCE
+                }
+                else {
+                    datasourceNames << name
+                }
+            }
+        }
+        else {
+            Map dataSource = config.getProperty('dataSource', Map, [:])
+            if(dataSource) {
+                datasourceNames << GrailsDomainClassProperty.DEFAULT_DATA_SOURCE
+            }
+        }
+
+
+        def springInitializer = new HibernateDatastoreSpringInitializer(config, grailsApplication.getArtefacts(DomainClassArtefactHandler.TYPE).collect() { GrailsClass cls -> cls.clazz })
+        springInitializer.registerApplicationIfNotPresent = false
+        springInitializer.dataSources = datasourceNames
+        def beans = springInitializer.getBeanDefinitions((BeanDefinitionRegistry)applicationContext)
+
+        beans.delegate = delegate
+        beans.call()
+    }}
+
+}
diff --git a/grails-plugins/mongodb/.classpath b/grails-plugins/mongodb/.classpath
deleted file mode 100644
index 27107c2..0000000
--- a/grails-plugins/mongodb/.classpath
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
-	<classpathentry kind="src" path="grails-app/conf"/>
-	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
-	<classpathentry kind="src" path=".link_to_grails_plugins/release-2.2.0/src/groovy">
-		<attributes>
-			<attribute name="org.grails.ide.eclipse.core.SOURCE_FOLDER" value="true"/>
-		</attributes>
-	</classpathentry>
-	<classpathentry kind="src" path=".link_to_grails_plugins/release-2.2.0/src/java">
-		<attributes>
-			<attribute name="org.grails.ide.eclipse.core.SOURCE_FOLDER" value="true"/>
-		</attributes>
-	</classpathentry>
-	<classpathentry kind="src" path=".link_to_grails_plugins/rest-client-builder-1.0.3/src/groovy">
-		<attributes>
-			<attribute name="org.grails.ide.eclipse.core.SOURCE_FOLDER" value="true"/>
-		</attributes>
-	</classpathentry>
-	<classpathentry kind="con" path="org.grails.ide.eclipse.core.CLASSPATH_CONTAINER"/>
-	<classpathentry kind="output" path="target/eclipseclasses"/>
-</classpath>
diff --git a/grails-plugins/mongodb/.project b/grails-plugins/mongodb/.project
deleted file mode 100644
index c173311..0000000
--- a/grails-plugins/mongodb/.project
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<projectDescription>
-	<name>mongodb</name>
-	<comment></comment>
-	<projects>
-	</projects>
-	<buildSpec>
-		<buildCommand>
-			<name>org.eclipse.jdt.core.javabuilder</name>
-			<arguments>
-			</arguments>
-		</buildCommand>
-	</buildSpec>
-	<natures>
-		<nature>org.grails.ide.eclipse.core.nature</nature>
-		<nature>org.eclipse.jdt.groovy.core.groovyNature</nature>
-		<nature>org.eclipse.jdt.core.javanature</nature>
-	</natures>
-	<linkedResources>
-		<link>
-			<name>.link_to_grails_plugins</name>
-			<type>2</type>
-			<location>/home/burt/workspace.nosql/grails-data-mapping/grails-plugins/mongodb/target/plugins</location>
-		</link>
-	</linkedResources>
-</projectDescription>
diff --git a/grails-plugins/mongodb/.settings/org.codehaus.groovy.eclipse.preferences.prefs b/grails-plugins/mongodb/.settings/org.codehaus.groovy.eclipse.preferences.prefs
deleted file mode 100644
index bf339c7..0000000
--- a/grails-plugins/mongodb/.settings/org.codehaus.groovy.eclipse.preferences.prefs
+++ /dev/null
@@ -1,3 +0,0 @@
-#Created by grails
-eclipse.preferences.version=1
-groovy.dont.generate.class.files=true
diff --git a/grails-plugins/mongodb/MongodbGrailsPlugin.groovy b/grails-plugins/mongodb/MongodbGrailsPlugin.groovy
deleted file mode 100644
index 5941562..0000000
--- a/grails-plugins/mongodb/MongodbGrailsPlugin.groovy
+++ /dev/null
@@ -1,84 +0,0 @@
-
-import org.grails.datastore.gorm.mongo.plugin.support.MongoMethodsConfigurer
-import org.grails.datastore.gorm.mongo.plugin.support.MongoOnChangeHandler
-import org.grails.datastore.gorm.mongo.plugin.support.MongoSpringConfigurer
-import grails.converters.*
-import org.codehaus.groovy.grails.web.json.JSONWriter
-import com.mongodb.*
-
-
-class MongodbGrailsPlugin {
-    def license = "Apache 2.0 License"
-    def organization = [name: "SpringSource", url: "http://www.springsource.org/"]
-    def developers = [
-        [name: "Graeme Rocher", email: "grocher@vmware.com"]]
-    def issueManagement = [system: "JIRA", url: "http://jira.grails.org/browse/GPMONGODB"]
-    def scm = [url: "https://github.com/grails/grails-data-mapping"]
-
-    def version = "3.0.2"
-    def grailsVersion = "2.3.2 > *"
-    def observe = ['services', 'domainClass']
-    def loadAfter = ['domainClass', 'hibernate', 'hibernate4', 'services', 'cloudFoundry']
-    def author = "Graeme Rocher"
-    def authorEmail = "graeme.rocher@springsource.com"
-    def title = "MongoDB GORM"
-    def description = 'A plugin that integrates the Mongo document datastore into Grails, providing a GORM API onto it'
-
-    def documentation = "http://grails.github.io/grails-data-mapping/mongodb"
-
-    def doWithSpring = new MongoSpringConfigurer().getConfiguration()
-
-    def doWithApplicationContext = { 
-        JSON.registerObjectMarshaller DBObject, { dbo, json ->
-            JSONWriter writer = json.getWriter();
-
-            writer.object()
-            dbo.each {  k, v ->
-                writer.key(k)
-                json.convertAnother(v)
-            }
-            writer.endObject()
-
-            null
-        }
-        JSON.registerObjectMarshaller(BasicDBList, 999) { dbo, json ->
-            JSONWriter writer = json.getWriter();
-
-            writer.array();
-            dbo.each { val -> json.convertAnother(val) }
-            writer.endArray();
-
-            null
-        }
-
-        JSON.registerObjectMarshaller(BasicDBObject, 999) { dbo, json ->
-            JSONWriter writer = json.getWriter();
-
-            writer.object()
-            dbo.each {  k, v ->
-                writer.key(k)
-                json.convertAnother(v)
-            }
-            writer.endObject()
-
-            null
-        }
-
-    }
-
-    def doWithDynamicMethods = { ctx ->
-        def datastore = ctx.mongoDatastore
-        def transactionManager = ctx.mongoTransactionManager
-        def methodsConfigurer = new MongoMethodsConfigurer(datastore, transactionManager)    
-        methodsConfigurer.hasExistingDatastore = manager.hasGrailsPlugin("hibernate") || manager.hasGrailsPlugin("hibernate4")
-        def foe = application?.config?.grails?.gorm?.failOnError
-        methodsConfigurer.failOnError = foe instanceof Boolean ? foe : false
-        methodsConfigurer.configure()
-    }
-
-    def onChange = { event ->
-        if(event.ctx) {
-            new MongoOnChangeHandler(event.ctx.mongoDatastore, event.ctx.mongoTransactionManager).onChange(delegate, event)            
-        }
-    }   
-}
diff --git a/grails-plugins/mongodb/application.properties b/grails-plugins/mongodb/application.properties
deleted file mode 100644
index 05fac38..0000000
--- a/grails-plugins/mongodb/application.properties
+++ /dev/null
@@ -1 +0,0 @@
-app.grails.version=2.3.8
diff --git a/grails-plugins/mongodb/build.gradle b/grails-plugins/mongodb/build.gradle
new file mode 100644
index 0000000..f6e47a0
--- /dev/null
+++ b/grails-plugins/mongodb/build.gradle
@@ -0,0 +1,46 @@
+
+group = "org.grails.plugins"
+version = "4.0.0.BUILD-SNAPSHOT"
+
+apply from:'https://raw.githubusercontent.com/grails/grails-boot/master/gradle/maven-central-build.gradle'
+
+configurations {
+    provided
+}
+
+dependencies {
+
+
+    provided("org.grails:grails-core:$grailsVersion")
+    provided("org.grails:grails-plugin-converters:$grailsVersion")
+    provided 'javax.servlet:javax.servlet-api:3.1.0'
+    compile 'org.codehaus.groovy:groovy:2.3.7'
+
+    compile project(":grails-datastore-gorm-mongodb"), {
+        exclude group:'org.springframework', module:'spring-context'
+        exclude group:'org.springframework', module:'spring-core'
+        exclude group:'org.springframework', module:'spring-beans'
+        exclude group:'org.springframework', module:'spring-tx'
+        exclude group:'org.grails', module:'grails-bootstrap'
+        exclude group:'org.codehaus.groovy', module:'groovy-all'
+        exclude group:'org.grails', module:'grails-core'
+        exclude group:'org.grails', module:'grails-async'
+        exclude group:'javax.transaction', module:'jta'
+    }
+}
+
+sourceSets {
+    main {
+        compileClasspath += configurations.provided
+    }
+    javadoc {
+        classpath = configurations.compile + configurations.provided
+    }
+}
+
+def installer = install.repositories.mavenInstaller
+def deployer = uploadArchives.repositories.mavenDeployer
+
+[installer, deployer]*.pom*.whenConfigured { pom ->
+    pom.artifactId = 'mongodb'
+}
\ No newline at end of file
diff --git a/grails-plugins/mongodb/grails-app/conf/Config.groovy b/grails-plugins/mongodb/grails-app/conf/Config.groovy
deleted file mode 100644
index 2e57c6d..0000000
--- a/grails-plugins/mongodb/grails-app/conf/Config.groovy
+++ /dev/null
@@ -1,24 +0,0 @@
-// configuration for plugin testing - will not be included in the plugin zip
- 
-log4j = {
-    // Example of changing the log pattern for the default console
-    // appender:
-    //
-    //appenders {
-    //    console name:'stdout', layout:pattern(conversionPattern: '%c{2} %m%n')
-    //}
-
-    error  'org.codehaus.groovy.grails.web.servlet',  //  controllers
-           'org.codehaus.groovy.grails.web.pages', //  GSP
-           'org.codehaus.groovy.grails.web.sitemesh', //  layouts
-           'org.codehaus.groovy.grails.web.mapping.filter', // URL mapping
-           'org.codehaus.groovy.grails.web.mapping', // URL mapping
-           'org.codehaus.groovy.grails.commons', // core / classloading
-           'org.codehaus.groovy.grails.plugins', // plugins
-           'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration
-           'org.springframework',
-           'org.hibernate',
-           'net.sf.ehcache.hibernate'
-
-    warn   'org.mortbay.log'
-}
diff --git a/grails-plugins/mongodb/grails-app/conf/DataSource.groovy b/grails-plugins/mongodb/grails-app/conf/DataSource.groovy
deleted file mode 100644
index 76bedde..0000000
--- a/grails-plugins/mongodb/grails-app/conf/DataSource.groovy
+++ /dev/null
@@ -1,32 +0,0 @@
-dataSource {
-    pooled = true
-    driverClassName = "org.h2.Driver"
-    username = "sa"
-    password = ""
-}
-hibernate {
-    cache.use_second_level_cache = true
-    cache.use_query_cache = true
-    cache.provider_class = 'net.sf.ehcache.hibernate.EhCacheProvider'
-}
-// environment specific settings
-environments {
-    development {
-        dataSource {
-            dbCreate = "create-drop" // one of 'create', 'create-drop','update'
-            url = "jdbc:h2:mem:devDB"
-        }
-    }
-    test {
-        dataSource {
-            dbCreate = "update"
-            url = "jdbc:h2:mem:testDb"
-        }
-    }
-    production {
-        dataSource {
-            dbCreate = "update"
-            url = "jdbc:h2:prodDb"
-        }
-    }
-}
diff --git a/grails-plugins/mongodb/scripts/_Install.groovy b/grails-plugins/mongodb/scripts/_Install.groovy
deleted file mode 100644
index a212160..0000000
--- a/grails-plugins/mongodb/scripts/_Install.groovy
+++ /dev/null
@@ -1,10 +0,0 @@
-//
-// This script is executed by Grails after plugin was installed to project.
-// This script is a Gant script so you can use all special variables provided
-// by Gant (such as 'baseDir' which points on project base dir). You can
-// use 'ant' to access a global instance of AntBuilder
-//
-// For example you can create directory under project tree:
-//
-//    ant.mkdir(dir:"${basedir}/grails-app/jobs")
-//
diff --git a/grails-plugins/mongodb/scripts/_Uninstall.groovy b/grails-plugins/mongodb/scripts/_Uninstall.groovy
deleted file mode 100644
index 7c53169..0000000
--- a/grails-plugins/mongodb/scripts/_Uninstall.groovy
+++ /dev/null
@@ -1,5 +0,0 @@
-//
-// This script is executed by Grails when the plugin is uninstalled from project.
-// Use this script if you intend to do any additional clean-up on uninstall, but
-// beware of messing up SVN directories!
-//
diff --git a/grails-plugins/mongodb/scripts/_Upgrade.groovy b/grails-plugins/mongodb/scripts/_Upgrade.groovy
deleted file mode 100644
index 6a1a4c9..0000000
--- a/grails-plugins/mongodb/scripts/_Upgrade.groovy
+++ /dev/null
@@ -1,10 +0,0 @@
-//
-// This script is executed by Grails during application upgrade ('grails upgrade'
-// command). This script is a Gant script so you can use all special variables
-// provided by Gant (such as 'baseDir' which points on project base dir). You can
-// use 'ant' to access a global instance of AntBuilder
-//
-// For example you can create directory under project tree:
-//
-//    ant.mkdir(dir:"${basedir}/grails-app/jobs")
-//
diff --git a/grails-plugins/mongodb/src/main/groovy/grails/plugins/mongodb/MongodbGrailsPlugin.groovy b/grails-plugins/mongodb/src/main/groovy/grails/plugins/mongodb/MongodbGrailsPlugin.groovy
new file mode 100644
index 0000000..b623063
--- /dev/null
+++ b/grails-plugins/mongodb/src/main/groovy/grails/plugins/mongodb/MongodbGrailsPlugin.groovy
@@ -0,0 +1,107 @@
+package grails.plugins.mongodb
+
+import com.mongodb.BasicDBList
+import com.mongodb.BasicDBObject
+import com.mongodb.DBObject
+import grails.core.GrailsClass
+import grails.mongodb.bootstrap.MongoDbDataStoreSpringInitializer
+import grails.plugins.Plugin
+import groovy.transform.CompileStatic
+import org.grails.core.artefact.DomainClassArtefactHandler
+import org.grails.datastore.gorm.mongo.plugin.support.MongoMethodsConfigurer
+import org.grails.datastore.gorm.mongo.plugin.support.MongoOnChangeHandler
+import org.grails.datastore.mapping.mongo.MongoDatastore
+import org.grails.web.json.JSONWriter
+import grails.converters.JSON
+import org.springframework.beans.factory.support.BeanDefinitionRegistry
+import org.springframework.transaction.PlatformTransactionManager
+
+class MongodbGrailsPlugin extends Plugin {
+    def license = "Apache 2.0 License"
+    def organization = [name: "SpringSource", url: "http://www.springsource.org/"]
+    def developers = [
+        [name: "Graeme Rocher", email: "grocher@vmware.com"]]
+    def issueManagement = [system: "JIRA", url: "http://jira.grails.org/browse/GPMONGODB"]
+    def scm = [url: "https://github.com/grails/grails-data-mapping"]
+
+    def version = "3.0.2"
+    def grailsVersion = "2.3.2 > *"
+    def observe = ['services', 'domainClass']
+    def loadAfter = ['domainClass', 'hibernate', 'hibernate4', 'services', 'cloudFoundry']
+    def author = "Graeme Rocher"
+    def authorEmail = "graeme.rocher@springsource.com"
+    def title = "MongoDB GORM"
+    def description = 'A plugin that integrates the Mongo document datastore into Grails, providing a GORM API onto it'
+
+    def documentation = "http://grails.github.io/grails-data-mapping/mongodb"
+
+    @Override
+    Closure doWithSpring() {
+        def initializer = new MongoDbDataStoreSpringInitializer(config, grailsApplication.getArtefacts(DomainClassArtefactHandler.TYPE).collect() { GrailsClass cls -> cls.clazz })
+        initializer.registerApplicationIfNotPresent = false
+        return initializer.getBeanDefinitions((BeanDefinitionRegistry)applicationContext)
+    }
+
+    @Override
+    void doWithApplicationContext() {
+        JSON.registerObjectMarshaller DBObject, { dbo, json ->
+            JSONWriter writer = json.getWriter();
+
+            writer.object()
+            dbo.each {  k, v ->
+                writer.key(k)
+                json.convertAnother(v)
+            }
+            writer.endObject()
+
+            null
+        }
+        JSON.registerObjectMarshaller(BasicDBList, 999) { dbo, json ->
+            JSONWriter writer = json.getWriter();
+
+            writer.array();
+            dbo.each { val -> json.convertAnother(val) }
+            writer.endArray();
+
+            null
+        }
+
+        JSON.registerObjectMarshaller(BasicDBObject, 999) { dbo, json ->
+            JSONWriter writer = json.getWriter();
+
+            writer.object()
+            dbo.each {  k, v ->
+                writer.key(k)
+                json.convertAnother(v)
+            }
+            writer.endObject()
+
+            null
+        }
+    }
+
+    @Override
+    @CompileStatic
+    void doWithDynamicMethods() {
+        def ctx = applicationContext
+        def datastore = ctx.getBean(MongoDatastore)
+        def transactionManager = ctx.getBean('mongoTransactionManager', PlatformTransactionManager)
+        def methodsConfigurer = new MongoMethodsConfigurer(datastore, transactionManager)
+        methodsConfigurer.hasExistingDatastore = manager.hasGrailsPlugin("hibernate") || manager.hasGrailsPlugin("hibernate4")
+        methodsConfigurer.failOnError = config.getProperty('grails.gorm.failOnError', Boolean, false)
+        methodsConfigurer.configure()
+    }
+
+    @Override
+    @CompileStatic
+    void onChange(Map<String, Object> event) {
+
+        def ctx = applicationContext
+        event.application = grailsApplication
+        event.ctx = applicationContext
+
+        def mongoDatastore = ctx.getBean(MongoDatastore)
+        def mongoTransactionManager = ctx.getBean('mongoTransactionManager', PlatformTransactionManager)
+        new MongoOnChangeHandler(mongoDatastore, mongoTransactionManager).onChange(this, event)
+    }
+}
diff --git a/grails-plugins/neo4j/grails-app/conf/BuildConfig.groovy b/grails-plugins/neo4j/grails-app/conf/BuildConfig.groovy
index a5257e2..8191619 100644
--- a/grails-plugins/neo4j/grails-app/conf/BuildConfig.groovy
+++ b/grails-plugins/neo4j/grails-app/conf/BuildConfig.groovy
@@ -5,7 +5,7 @@
 grails.project.dependency.resolution = {
 
     inherits("global") {
-        excludes 'xml-apis', 'netty'//, 'xercesImpl'
+        excludes 'xml-apis', 'netty', 'logback-classic' //, 'xercesImpl'
     }
     log "warn"
     checksums true
@@ -63,6 +63,7 @@
         }
         test "org.seleniumhq.selenium:selenium-chrome-driver:$seleniumVersion"
         test "org.seleniumhq.selenium:selenium-firefox-driver:$seleniumVersion"
+        test "org.spockframework:spock-grails-support:0.7-groovy-2.0"
 
         // htmlunit seems to be broken
 /*        test("org.seleniumhq.selenium:selenium-htmlunit-driver:$seleniumVersion") {
diff --git a/grails-plugins/neo4j/test/integration/org/grails/datastore/gorm/neo4j/GetOrSetSpec.groovy b/grails-plugins/neo4j/test/integration/org/grails/datastore/gorm/neo4j/GetOrSetSpec.groovy
index 9fcaec6..4505ad6 100644
--- a/grails-plugins/neo4j/test/integration/org/grails/datastore/gorm/neo4j/GetOrSetSpec.groovy
+++ b/grails-plugins/neo4j/test/integration/org/grails/datastore/gorm/neo4j/GetOrSetSpec.groovy
@@ -5,10 +5,20 @@
 import org.codehaus.groovy.grails.web.json.JSONElement
 import org.neo4j.graphdb.DynamicRelationshipType
 import org.neo4j.graphdb.GraphDatabaseService
+import org.neo4j.graphdb.Transaction
 
 class GetOrSetSpec extends IntegrationSpec {
 
     GraphDatabaseService graphDatabaseService
+    Transaction tx
+
+    def setup() {
+        tx = graphDatabaseService.beginTx()
+    }
+
+    def cleanup() {
+        tx.close()
+    }
 
     def "test getOrSet method on nodes"() {
         setup:
@@ -66,4 +76,7 @@
         (object as JSON).render(sw)
         JSON.parse(sw.toString())
     }
+
+
+
 }
diff --git a/settings.gradle b/settings.gradle
index 4aa0322..6035621 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,7 +1,7 @@
 // Datastore Project
 include ("grails-datastore-core",
          "grails-datastore-gemfire",
-        "grails-datastore-jpa",
+//        "grails-datastore-jpa",
 /*        "grails-datastore-riak",*/
         "grails-datastore-simple",
         "grails-datastore-web",
@@ -34,6 +34,8 @@
         'grails-plugins:redis',
         'grails-plugins:riak',
 */
+        'grails-plugins/hibernate',
+        'grails-plugins/mongodb',
 
         // Boot Extensions
 //        'boot-plugins/gorm-hibernate4-spring-boot',
@@ -41,7 +43,7 @@
 
         // GORM Implementations
         'grails-datastore-gorm-cassandra',
-        'grails-datastore-gorm-jpa',
+//        'grails-datastore-gorm-jpa',
         'grails-datastore-gorm-neo4j',
         'grails-datastore-gorm-redis',
         'grails-datastore-gorm-rest-client',