apache / apache/grails-core

Refresh doesn't work for entities which contains hasMany mapping.

Open
#14,534 5 comments 5 reactions 0 assignees View on GitHub
relates-to: gorm
Dominant language
Groovy
Stars
2.9k
Forks
975
Avg merge
1d 22h
Merged PRs (30d)
92

Description

After upgrade grails to version to 3.3.9 and GORM version to 6.1.10.RELEASE I've got error during refresh any entity which contains mapping like "hasMany".

Similar problem which I've found here is https://github.com/grails/grails-data-mapping/issues/1096, but no solution was provided.

Link to github(test application):
https://github.com/dmkolpakov/grails-data-mapping-issue-1210

Steps for reproduce:
Just run provided application from github repository above in HomeController issue will reproduced.

Please pay attention that I've specified access type for properties for entities in application.groovy.

import javax.persistence.*
grails.gorm.default.mapping = {
'*'(accessType: AccessType.PROPERTY)
}

According my investigation, problem happens because in new version trait DirtyCheckable was added for all domain's entities by default, if we use AccessType.PROPERTY, it invoke setter for certain property and mark entity as dirty, I'm not sure that is right, but more interesting is that hibernate can't proceed with it. I'm going to proceed my investigation, but if you have some thoughts please advise to me.

```

For example:

class Vehicle {

Integer year

String name
Model model
Make make
static hasMany = [owners: Owner]

static constraints = {
year min: 1900
name maxSize: 255
}
}

....

def vehicle = Vehicle.findByName("Pickup")
vehicle.refresh()
```

Exception example:

```
java.lang.reflect.InvocationTargetException: null
at org.grails.core.DefaultGrailsControllerClass$ReflectionInvoker.invoke(DefaultGrailsControllerClass.java:211)
at org.grails.core.DefaultGrailsControllerClass.invoke(DefaultGrailsControllerClass.java:188)
at org.grails.web.mapping.mvc.UrlMappingsInfoHandlerAdapter.handle(UrlMappingsInfoHandlerAdapter.groovy:90)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at org.springframework.boot.web.filter.ApplicationContextHeaderFilter.doFilterInternal(ApplicationContextHeaderFilter.java:55)
at org.grails.web.servlet.mvc.GrailsWebRequestFilter.doFilterInternal(GrailsWebRequestFilter.java:77)
at org.grails.web.filters.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:67)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.orm.hibernate5.HibernateSystemException: Exception occurred inside setter of org.grails.guides.Vehicle.owners; nested exception is org.hibernate.PropertyAccessException: Exception occurred inside setter of org.grails.guides.Vehicle.owners
at org.springframework.orm.hibernate5.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:296)
at org.grails.orm.hibernate.GrailsHibernateTemplate.convertHibernateAccessException(GrailsHibernateTemplate.java:724)
at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:303)
at org.grails.orm.hibernate.GrailsHibernateTemplate.refresh(GrailsHibernateTemplate.java:457)
at org.grails.orm.hibernate.GrailsHibernateTemplate.refresh(GrailsHibernateTemplate.java:453)
at org.grails.orm.hibernate.AbstractHibernateGormInstanceApi.refresh(AbstractHibernateGormInstanceApi.groovy:241)
at org.grails.datastore.gorm.GormEntity$Trait$Helper.refresh(GormEntity.groovy:90)
at org.grails.guides.HomeController.index(HomeController.groovy:7)
... 14 common frames omitted
Caused by: org.hibernate.PropertyAccessException: Exception occurred inside setter of org.grails.guides.Vehicle.owners
at org.hibernate.property.access.spi.SetterMethodImpl.set(SetterMethodImpl.java:67)
at org.hibernate.tuple.entity.AbstractEntityTuplizer.setPropertyValues(AbstractEntityTuplizer.java:664)
at org.hibernate.tuple.entity.PojoEntityTuplizer.setPropertyValues(PojoEntityTuplizer.java:207)
at org.hibernate.persister.entity.AbstractEntityPersister.setPropertyValues(AbstractEntityPersister.java:4692)
at org.hibernate.engine.internal.TwoPhaseLoad.doInitializeEntity(TwoPhaseLoad.java:183)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:125)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1139)
at org.hibernate.loader.Loader.processResultSet(Loader.java:998)
at org.hibernate.loader.Loader.doQuery(Loader.java:936)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:312)
at org.hibernate.loader.Loader.loadEntity(Loader.java:2209)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:60)
at org.hibernate.loader.entity.AbstractEntityLoader.load(AbstractEntityLoader.java:50)
at org.hibernate.persister.entity.AbstractEntityPersister.load(AbstractEntityPersister.java:4069)
at org.hibernate.event.internal.DefaultRefreshEventListener.onRefresh(DefaultRefreshEventListener.java:171)
at org.hibernate.event.internal.DefaultRefreshEventListener.onRefresh(DefaultRefreshEventListener.java:48)
at org.hibernate.internal.SessionImpl.fireRefresh(SessionImpl.java:1193)
at org.hibernate.internal.SessionImpl.refresh(SessionImpl.java:1166)
at org.hibernate.internal.SessionImpl.refresh(SessionImpl.java:1161)
at org.grails.orm.hibernate.GrailsHibernateTemplate$11.doInHibernate(GrailsHibernateTemplate.java:460)
at org.grails.orm.hibernate.GrailsHibernateTemplate.doExecute(GrailsHibernateTemplate.java:299)
... 19 common frames omitted
Caused by: java.lang.reflect.InvocationTargetException: null
at org.hibernate.property.access.spi.SetterMethodImpl.set(SetterMethodImpl.java:44)
... 40 common frames omitted
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:584)
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:576)
at org.hibernate.collection.internal.AbstractPersistentCollection.access$200(AbstractPersistentCollection.java:55)
at org.hibernate.collection.internal.AbstractPersistentCollection$1.doWork(AbstractPersistentCollection.java:165)
at org.hibernate.collection.internal.AbstractPersistentCollection$1.doWork(AbstractPersistentCollection.java:146)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:249)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:145)
at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:143)
at org.grails.datastore.mapping.dirty.checking.DirtyCheckable$Trait$Helper.markDirty(DirtyCheckable.groovy:81)
... 41 common frames omitted
```

### Task List

- [x] Steps to reproduce provided
- [x] Stacktrace (if present) provided
- [x] Example that reproduces the problem uploaded to Github
- [x] Full description of the issue provided (see below)

### Environment Information

- **Operating System**: Windows 7 Professional
- **GORM Version:** 6.1.10.RELEASE
- **Grails Version (if using Grails):** 3.3.9
- **JDK Version:** java8_191

Contributor guide

Open the contributing guide

Research direction

Reproduce the failure from the linked test application, starting at HomeController.index with the Vehicle entity's hasMany owners mapping and AccessType.PROPERTY configuration. Inspect the refresh call and the provided stack trace, especially DirtyCheckable.markDirty and the Vehicle.owners setter path. Done means refreshing the entity no longer raises the reported LazyInitializationException.

Written by the indexing model from the issue text.

Assessment

Tech stack
groovy
Domain
backend, database
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.