The GitHub Actions job "Coverage" on 
grails-core.git/fix/16675-map-entries-named-like-properties has succeeded.
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/39480212148

With regards,
GitHub Actions via GitBox

Reply via email to