-
Notifications
You must be signed in to change notification settings - Fork 199
Description
In Grails 2.4 it was possible to implement an alternative identity type (such as UUID) globally for applications that require it, instead of the default long identity type.
This was achieved with a combination of a global mapping in Config.groovy and an abstract base class for domain entities, declaring an explicit UUID id property, that all domain classes extend. (The abstract class would be declared in src/main/ and behave the same way as a JPA @MappedSuperclass.)
In Grails 3 I have explored different ways to achieve this, but have been unable to find a solution that satisfies DRY principals. UUID identity can be defined for individual concrete domain classes.
Objective:
To use UUID generated identity on domain classes globally within an application (and plugins: specifically audit-logging), instead of the default long identity type.
General method:
Declare an explicit (or automatic) id property of type UUID (UUID id) on a common base class for all domain entities and set the column generator and type somewhere, i.e.:
static mapping = {
id(generator: "uuid2", type: "uuid-binary") // H2
}
Working implementation in Grails 2.4:
1. Declare UUID id on a common abstract base class for entities (declared in src/main/groovy) and configure a global id mapping for the 'id' column in Config.groovy.
Strategies tried in Grails 3:
1. Declare UUID id on an abstract base class and put global id mapping into application.groovy (as per Grails 2.4)
THIS FAILS: GORM does not detect the entity (seen from domain entity count) - and exceptions are thrown on use. Example exception:
java.lang.IllegalStateException: Either class [co.example.domain.User] is not a domain class or GORM has not been initialized correctly or has already been shutdown. If you are unit testing your entities using the mocking APIs
at org.grails.datastore.gorm.GormEnhancer.stateException(GormEnhancer.groovy:159) ~[grails-datastore-gorm-5.0.0.RC3.jar:na]
at org.grails.datastore.gorm.GormEnhancer.findInstanceApi(GormEnhancer.groovy) ~[grails-datastore-gorm-5.0.0.RC3.jar:na]
at org.grails.datastore.gorm.GormEntity$Trait$Helper.currentGormInstanceApi(GormEntity.groovy:1311) ~[grails-datastore-gorm-5.0.0.RC3.jar:na]
at org.grails.datastore.gorm.GormEntity$Trait$Helper.save(GormEntity.groovy:140) ~[grails-datastore-gorm-5.0.0.RC3.jar:na]
at org.grails.datastore.gorm.GormEntity$Trait$Helper$save.call(Unknown Source) ~[na:na]
(I have tried putting the base class in grails-app/domain instead of src/main/groovy the latter.
2. Declare UUID id and put id mapping into the concrete domain class
THIS WORKS but is not DRY, requiring declaration in every domain class
3. Declare only the id mapping on the concrete domain class
THIS FAILS with Exception:
org.hibernate.PropertySetterAccessException: IllegalArgumentException occurred while calling setter for property [co.example.domain.User.id (expected type = java.lang.Long)]; target = [User()], property value = [ff71d73a-d499-4be5-a46d-31d5c9d16f70] setter of co.example.domain.User.id
4. Declare UUID id and id mapping on the abstract base class
THIS FAILS: GORM does not detect the entity and exceptions are thrown for 'no such domain class'
5. Do not declare UUID id on any class and put global id mapping into application.groovy
THIS FAILS: GORM declares id field as 'long' but generator is UUID. Exception:
org.hibernate.PropertySetterAccessException: IllegalArgumentException occurred while calling setter for property [co.example.domain.User.id (expected type = java.lang.Long)]; target = [User()], property value = [1a86c51c-fd85-459d-b973-2269a3ff0dd6] setter of co.example.domain.User.id
I cannot find in the official documentation how to change the identity type from the default long type.
In Grails 2.4, global mapping configuration always seemed to be a workaround if used to define to-be-inherited mappings for common fields that are declared in a base class; however I was certainly grateful for it's existence. I also notice that the importFrom method in constraints has been removed in Grails 3; I used this extensively in Grails 2.4. Therefore I now need to find out if Grails 3 does the inheritance of properties, constraints and mappings that are defined in a tree of parent classes automatically, or if such declarations are still ignored, as they appeared to be in Grails 2? (The expected behaviour would be IMHO to inherit constraints and mappings from superclasses along with properties, including from abstract base classes declared outside of the grails-app/domain directory; i.e. the Grails equivalents of JPA @MappedSuperclass.)
Am I doing something wrong here, or is global identity type change currently an ability not supported in Grails 3?