Hibernate MappingException with inheritance of a concrete non-domain class in Grails

1.5k views Asked by At

The Scenario

I have a need to represent an object in two different contexts. One context should not persist and the other should. The persistent objects are actual data pulled from another system. The non-persistent objects represent parts of a product definition. The two will be compared, and I'm not interested in storing the definition data. The persisting object needs to have additional information stored with it.

The Implementation

In order to accomplish this, I decided that the most logical thing to do would be to create the base class in the src/groovy folder to avoid grails/hibernate wanting to persist it as a domain class.

class Resource{
    String name
    Date lastModified 
}

The domain class that I want to persist looks like the following.

class OwnedResource extends Resource{  
  Date dateCreated, lastUpdated
  Owner owner
  static belongsTo = [owner: Owner]
  static mapping = {
   //I assumed I would need this so that grails would not expect 
   //to store the object in the base class table that doesn't exist
   tablePerHierarchy true 
   table 'owned_resource'
  }
}

Lastly we then have the Owner class which hasMany OwnedResources.

class Owner{
  Date dateCreated, lastUpdated
  String name
  static hasMany = [
    resources: OwnedResource
  ]
}

The Problem

When I run-app, I end up getting a friendly Hibernate exception:

2011-10-24 20:32:01,307 [main] ERROR context.GrailsContextLoader  - Error executing bootstraps: 
Error creating bean with name 'messageSource': Initialization of bean failed; nested exception 
is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean 
property 'sessionFactory'; nested exception is 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'sessionFactory': Invocation of init method failed; nested exception is 
org.hibernate.MappingException: Association references unmapped class: OwnedResource

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'messageSource': Initialization of bean failed; nested exception is 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean 
property 'sessionFactory'; nested exception is 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 
'sessionFactory': Invocation of init method failed; nested exception is 
org.hibernate.MappingException: Association references unmapped class: OwnedResource
at org.grails.tomcat.TomcatServer.start(TomcatServer.groovy:212)
at grails.web.container.EmbeddableServer$start.call(Unknown Source)
at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy:158)
at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy)
at _GrailsSettings_groovy$_run_closure10.doCall(_GrailsSettings_groovy:280)
at _GrailsSettings_groovy$_run_closure10.call(_GrailsSettings_groovy)
at _GrailsRun_groovy$_run_closure5.doCall(_GrailsRun_groovy:149)
at _GrailsRun_groovy$_run_closure5.call(_GrailsRun_groovy)
at _GrailsRun_groovy.runInline(_GrailsRun_groovy:116)
at _GrailsRun_groovy.this$4$runInline(_GrailsRun_groovy)
at _GrailsRun_groovy$_run_closure1.doCall(_GrailsRun_groovy:59)
at RunApp$_run_closure1.doCall(RunApp.groovy:33)
at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
at gant.Gant.withBuildListeners(Gant.groovy:427)
at gant.Gant.this$2$withBuildListeners(Gant.groovy)
at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
at gant.Gant.dispatch(Gant.groovy:415)
at gant.Gant.this$2$dispatch(Gant.groovy)
at gant.Gant.invokeMethod(Gant.groovy)
at gant.Gant.executeTargets(Gant.groovy:590)
at gant.Gant.executeTargets(Gant.groovy:589)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager': Cannot resolve reference to bean 'sessionFactory' while setting bean property 'sessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.hibernate.MappingException: Association references unmapped class: OwnedResource
... 24 more

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Invocation of init method failed; nested exception is org.hibernate.MappingException: Association references unmapped class: OwnedResource
... 24 more

Caused by: org.hibernate.MappingException: Association references unmapped class: OwnedResource
... 24 more

Perhaps my implementation is bad practice, since after much googling and searching of StackOverflow, I have yet to encounter anyone facing this same issue or attempting a similar implementation. Most people are attempting to use abstract classes, which does work. I want the class Resource to be concrete because I need to instantiate it. The answer may simply be that grails doesn't allow this functionality, but I'd like to hear a definitive answer and any possible work arounds. I'm leaning toward having to duplicate the class instead of using inheritance.

What am I doing wrong and why is this error occurring? Can this implementation be done in grails?

2

There are 2 answers

0
dbrin On

Use abstract base class Resource and then add a 3rd class that extends Resource that is not a domain object but a simple utility class that you can use for other things and not worry about persistence. Good luck... Dmitry.

1
mgg On

In this case if you are trying to extending a class that it is outside the domain folder, you should declare that class as abstract.

Otherwise Hibernate will try to map it, and because it´s not in the domain folder everything will eventually blow up.