jdaugherty opened a new issue, #15795:
URL: https://github.com/apache/grails-core/issues/15795

   ### 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**
   
   - 7.0.x (current), starting with the merge of PR #15699 (#15681 fix).
   
   **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**
   
   1. 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
       }
   }
   2. Define a concrete domain subclass that declares no constraint for id:
   
   class BindableIdRecord extends AbstractBindableIdRecord {
       static constraints = { description nullable: true }
   }
   3. 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
   
   - A subclass override (id bindable: false) must continue to win over an 
inherited bindable: true.
   - The original #15681 behavior must be preserved: special properties that 
only landed in a non-domain parent's whitelist by default (no explicit 
constraint) must still not be inherited.


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