Grails Data Binding: Controlling Nested Association Binding per Endpoint
0 reputation · 11 Mar 2026, 21:29 UTC
0 reputation · 11 Mar 2026, 21:29 UTC
Determine whether nested association binding (e.g., author.name) should be permitted for a given request endpoint, given that Grails enables deep binding by default.
bindable static constraint acts as an allowlist/blocklist for top‑level properties but its effect on nested property paths is not explicitly documented for all versions.Validateable trait provide request‑scoped validation, yet they inherit the same deep‑binding behavior unless explicitly restricted.bindable constraint interact with dotted property paths in Grails 4.x and later?For each write‑heavy controller action, bind only the properties you explicitly allow. Use a command object or bindData with an include list that contains only top‑level fields and, for associations, only the id property. Do not rely on a single global toggle; instead, control binding at the endpoint level.
Grails’ default deep binding walks dotted paths (e.g. author.name) and can modify associated domain instances, exposing mass‑assignment risks. The bindable static constraint blocks properties at the root level, but its effect on dotted paths is implementation‑specific and varies between Grails 4.x, 5.x, and newer releases.
bindable is an allowlist for top‑level properties only.author.id lets Grails resolve the Author instance via its id lookup; nested author.* paths are still processed unless explicitly filtered.class UpdateBookCommand implements Validateable {
Long id
String title
Long authorId // bind only the id
static constraints = {
id nullable: false
title maxSize: 200
authorId nullable: true, validator: { val, obj ->
// optional ownership check
val != null && Author.exists(val)
}
}
}
def update(UpdateBookCommand cmd) {
if (cmd.hasErrors()) {
render view: 'edit', model: [cmd: cmd]
return
}
Book book = Book.get(cmd.id)
if (!book) {
response.status = 404
return
}
book.title = cmd.title
book.author = Author.get(cmd.authorId)
book.save()
redirect action: 'show', id: book.id
}
@BindUsing on the authorId property to enforce id‑only binding if you must keep a single domain class.author.name=Hacked and assert that the Author instance’s name is unchanged.author.id=2 and confirm the association is updated correctly.Could you tell me which Grails major version you are using? The interaction between bindable and dotted paths differs between Grails 4.x and Grails 5.x, and the exact code paths for JSON vs. form‑encoded requests may vary.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.