MartinJesusDev opened a new issue, #16615:
URL: https://github.com/apache/grails-core/issues/16615
**Expected Behavior**
Reading and writing a trait-backed property through
`TraitPropertyAccessStrategy` works. The
strategy resolves the property to the private, name-mangled field that
Groovy generates on the
implementing class and builds a field-based `Getter`/`Setter` over it, so it
must make that field
accessible before the accessors are used.
**Actual Behaviour**
The first read or write through the strategy fails:
```
org.hibernate.PropertyAccessException: Could not set field value [value]
value by reflection :
[class ...FieldAccessProbeEntity.probeField]
at
org.hibernate.property.access.spi.SetterFieldImpl.set(SetterFieldImpl.java:72)
Caused by: java.lang.IllegalAccessException: class
org.hibernate.property.access.spi.SetterFieldImpl
cannot access a member of class ...FieldAccessProbeEntity with modifiers
"private"
```
`grails-data-hibernate7` reproduces the same failure (Hibernate 7 reports it
as
`Could not set value of type [java.lang.String]`).
**Steps To Reproduce**
On `8.0.x` (verified at `0e8fd03e56c2574e87ac824cd7831221e803873d`; the
`grails-data-hibernate5`
strategy is identical on `7.0.x`):
```groovy
trait FieldAccessProbe {
String probeField
}
class FieldAccessProbeEntity implements FieldAccessProbe { }
def "field-based access to a trait property reads back what the setter
wrote"() {
given:
def entity = new FieldAccessProbeEntity()
def access = new TraitPropertyAccessStrategy()
.buildPropertyAccess(FieldAccessProbeEntity, 'probeField')
when:
access.setter.set(entity, 'value') // h5: set(entity, 'value', null)
then:
access.getter.get(entity) == 'value'
}
```
**Environment Information**
- Operating System: Linux x86_64
- JDK Version: 21 (`8.0.x`), 17 (`7.0.x`)
- Gradle: wrapper 9.8.0 (`8.0.x`), 8.14.5 (`7.0.x`)
- Hibernate: 5.6 (`grails-data-hibernate5`), 7.x (`grails-data-hibernate7`)
**Version**
`8.0.x` (verified). The `grails-data-hibernate5` code is identical on
`7.0.x`, `7.1.x`, `7.2.x`,
`8.1.x` and `9.0.x`.
**Root cause and notes**
- `TraitPropertyAccessStrategy#buildPropertyAccess` obtains the generated
field with Spring's
`ReflectionUtils.findField` and never makes it accessible, unlike
Hibernate's field access path
(`ReflectHelper.findField`) and Grails'
`FieldEntityAccess.ReaderAndWriterMaker`, which both call
`makeAccessible` for the same field.
- The standard GORM flow can mask this: on `grails-data-hibernate5`,
`FieldEntityAccess.ReaderAndWriterMaker` makes the field accessible while
building the mapping
model, before Hibernate builds its property accessors; on
`grails-data-hibernate7` the default
access type is `PROPERTY`, so the strategy is not selected by default. The
strategy still needs
to be correct in isolation.
- Affected versions:
- `grails-data-hibernate5`: all maintained lines (`7.0.x`, `7.1.x`,
`7.2.x`, `8.0.x`, `8.1.x`,
`9.0.x`).
- `grails-data-hibernate7`: `8.0.x` and later (`8.1.x`, `9.0.x`); the
module does not exist on 7.x.
- Proposed fix: call `ReflectionUtils.makeAccessible(field)` on the resolved
field in
`TraitPropertyAccessStrategy#buildPropertyAccess` (both modules).
- I can submit the Hibernate 5 fix against `7.0.x` and the Hibernate 7 fix
against `8.0.x` as two
focused PRs.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]