The GitHub Actions job "Groovy Snapshot Canary Build" on grails-core.git/fix/16675-map-entries-named-like-properties has failed. Run started by GitHub user jdaugherty (triggered by jdaugherty).
Head commit for run: 231a2e70b83cc6412dc747689a328b1d2a99ff5a / James Daugherty <[email protected]> Read and write Map entries through the Map API where the key is user data 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, `map['properties']` now returns the meta-properties of the map object and `map['properties'] = value` throws ReadOnlyPropertyException. 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 for a key named `properties`. 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, and the BsonDocument converter 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. Use Map.get and Map.put at every site where the key comes from a document or from the binding source: the BsonDocument converter and the MapCodec in CodecExtensions, EmbeddedCollectionDecoder, GrailsWebDataBinder, SimpleDataBinder and AbstractStructuredBindingEditor. A loaded Map property comes back as a DirtyCheckingMap, whose own accessors (target, parent, property, originalSize, assigned) shadow entries of those names through the wrapper although the plain map it wraps exposes them. The wrapper now resolves exactly those five names to the entry in getProperty and setProperty, writing through put so the owner is marked dirty, and leaves every other name to the wrapped map's behaviour. That restores the Grails 7 behaviour for dotted and subscript access in dynamic and statically compiled code alike, except dotted access from statically compiled code, which binds to the accessor at compile time as it always has. Removing the accessors instead, as dc214d94e1 did for params, would rename getOriginalSize() and isAssigned() on the DirtyCheckableCollection interface, an SPI change this patch line should not make. Upgrade note 28.4, and notes in the data binding and GORM for MongoDB guides, say that application code reads such an entry with get(). Fixes #16675 Report URL: https://github.com/apache/grails-core/actions/runs/39480212331 With regards, GitHub Actions via GitBox
