Issue description
Summary
When an abstract base class (e.g. a @DirtyCheck class in src/main/groovy) declares an explicit bindable: true constraint on one of the default-excluded special properties (id, version, dateCreated, lastUpdated), a concrete domain subclass that does not redeclare the constraint fails to inherit it. The property is silently excluded from data binding even though the parent explicitly opted it in.
This is a regression introduced by the fix for #15681 (PR #15699).
Affected version
Root cause
PR #15699 added a filter in DefaultASTDatabindingHelper.getPropertyNamesToIncludeInWhiteList that strips the default-excluded special properties from the inherited parent whitelist for any domain class:
if (isDomainClass && DOMAIN_CLASS_PROPERTIES_TO_EXCLUDE_BY_DEFAULT.contains(parentPropertyName)) {
continue;
}
This correctly prevents GORM-injected id/version from leaking out of a non-domain @DirtyCheck base into the subclass whitelist. However, the filter is unconditional: it cannot tell the difference between a special property that landed in the parent whitelist by default (the case #15681 fixed) and one the parent made bindable via an explicit bindable: true constraint (which should be inherited). As a result, the explicit constraint is discarded.
Steps to reproduce
-
Define an abstract @DirtyCheck base in src/main/groovy that opts id into binding:
@DirtyCheck
abstract class AbstractBindableIdRecord {
String description
static constraints = {
id bindable: true
}
}
-
Define a concrete domain subclass that declares no constraint for id:
class BindableIdRecord extends AbstractBindableIdRecord {
static constraints = { description nullable: true }
}
-
Bind a request that includes id:
def record = new BindableIdRecord()
bindData(record, params) // params: id=99&description=...
Expected behavior
id is bound (the inherited bindable: true constraint is honored): record.id == 99.
Actual behavior
id is not bound: record.id == null. The inherited explicit constraint is ignored.
Notes
Issue description
Summary
When an abstract base class (e.g. a
@DirtyCheckclass in src/main/groovy) declares an explicit bindable: true constraint on one of the default-excluded special properties (id, version, dateCreated, lastUpdated), a concrete domain subclass that does not redeclare the constraint fails to inherit it. The property is silently excluded from data binding even though the parent explicitly opted it in.This is a regression introduced by the fix for #15681 (PR #15699).
Affected version
Root cause
PR #15699 added a filter in DefaultASTDatabindingHelper.getPropertyNamesToIncludeInWhiteList that strips the default-excluded special properties from the inherited parent whitelist for any domain class:
This correctly prevents GORM-injected id/version from leaking out of a non-domain
@DirtyCheckbase into the subclass whitelist. However, the filter is unconditional: it cannot tell the difference between a special property that landed in the parent whitelist by default (the case #15681 fixed) and one the parent made bindable via an explicit bindable: true constraint (which should be inherited). As a result, the explicit constraint is discarded.Steps to reproduce
Define an abstract @DirtyCheck base in src/main/groovy that opts id into binding:
Define a concrete domain subclass that declares no constraint for id:
Bind a request that includes id:
Expected behavior
id is bound (the inherited bindable: true constraint is honored): record.id == 99.
Actual behavior
id is not bound: record.id == null. The inherited explicit constraint is ignored.
Notes