jdaugherty opened a new pull request, #16694:
URL: https://github.com/apache/grails-core/pull/16694

   Fixes #16675
   
   ## Problem
   
   Groovy 5 resolves a String subscript on a `Map` as property access: at 
runtime `getAt(Object, String)` and `putAt(Object, String, Object)` win over 
the `Map` overloads, and the static compiler binds a String-keyed read the same 
way. Every Groovy object has the `properties` and `metaClass` properties, so 
for *any* `Map`, a `LinkedHashMap` included:
   
   | Expression | Groovy 4 | Groovy 5 |
   |---|---|---|
   | `map['properties']` | the entry | the meta-properties of the map object |
   | `map['properties'] = v` | map put | throws `ReadOnlyPropertyException` |
   | `map['metaClass'] = v` | map put | replaces the metaclass of the map |
   
   Under `@CompileStatic` the assignment is still dispatched at runtime by the 
class of the key, so a statically compiled `map[key] = value` fails the same 
way when `key` is `"properties"` (verified against Groovy 5.1.3, indy on and 
off).
   
   GORM for MongoDB decoded `Map` properties, embedded maps and nested 
documents with that subscript, so a document holding a GeoJSON `Feature`, whose 
`properties` member is part of the format, could not be loaded; the 
`BsonDocument` converter also read a nested key such as `firstKey` as a 
`BsonDocument` accessor. The data binders built the bound value of a `Map` 
property with the same subscript, so binding such a map, or an indexed key such 
as `attributes[properties]`, recorded a binding error instead of the entry.
   
   ## Fix
   
   `Map.get` / `Map.put` at every site where the key comes from a document or 
from the binding source:
   
   - `CodecExtensions`: the `BsonDocument` to `Map` converter and 
`MapCodec.decode`
   - `EmbeddedCollectionDecoder`: the `Map` branch
   - `GrailsWebDataBinder`: the bound map of a `Map` property, and the indexed 
persistent-instance path
   - `SimpleDataBinder`: the indexed `Map` property path
   - `AbstractStructuredBindingEditor.getPropertyValuesMap`
   
   Affects `8.0.x` and up; `7.x` is on Groovy 4.
   
   ## Documentation
   
   - `upgrading80x.adoc` ยง28.4, next to the existing Groovy 5 notes: the 
behaviour, that Grails stores and loads such keys, and that application code 
reads them with `get()`.
   - NOTEs in the data binding guide (Binding To Collections And Maps) and the 
GORM for MongoDB guide (Basic Collection Types).
   
   ## Testing
   
   New tests, each failing on `8.0.x` without the fix (with 
`ReadOnlyPropertyException`, or a missing entry) and passing with it:
   
   - `CodecExtensionsSpec`: the `BsonDocument` converter with `properties`, 
`metaClass`, `firstKey` and `class` keys; `MapCodec` decode; a GeoJSON-shaped 
round trip through `BsonDocumentWriter` / `BsonDocumentReader`
   - `EmbeddedCollectionDecoderSpec`; `BsonPersistentEntityCodecSpec` (entity 
round trip of a `Map` property)
   - `MapKeysNamedLikeBeanPropertiesSpec` in `grails-data-mongodb-core`, 
against a MongoDB container: the three scenarios of the issue's reproducer 
(save, assign on update, a document inserted with the driver), plus a dotted 
query on the nested key
   - `GrailsWebDataBinderSpec`, `GrailsWebDataBindingStructuredEditorSpec`, 
`CollectionBindingSpec`, `SimpleDataBinderSpec`
   
   Run locally: the specs above and `codeStyle` for `grails-data-mongodb-bson`, 
`grails-web-databinding` and `grails-databinding-core`. The full module suites 
are left to CI.
   
   Not in this PR: `DirtyCheckingMap`, the wrapper a loaded `Map` property 
comes back as, declares `parent`, `property`, `originalSize` and `assigned` 
accessors, so on Groovy 5 entries with those names are shadowed for subscript 
reads in application code (the `Map` API still reaches them). That is the 
remaining item from #16290.
   


-- 
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]

Reply via email to