Skip to content

Commit

Permalink
Document list/map/array constructor data binding
Browse files Browse the repository at this point in the history
Closes gh-32426
  • Loading branch information
rstoyanchev committed Jun 24, 2024
1 parent e48cbc5 commit 6e82bf0
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 7 deletions.
18 changes: 11 additions & 7 deletions framework-docs/modules/ROOT/pages/core/validation/beans-beans.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,20 @@ The target class should have a single public constructor or a single non-public
with arguments. If there are multiple constructors, then a default constructor if present
is used.

By default, constructor parameter names are used to look up argument values, but you can
configure a `NameResolver`. Spring MVC and WebFlux both rely to allow customizing the name
of the value to bind through an `@BindParam` annotation on constructor parameters.
By default, argument values are looked up via constructor parameter names. Spring MVC and
WebFlux support a custom name mapping through the `@BindParam` annotation on constructor
parameters or fields if present. If necessary, you can also configure a `NameResolver` on
`DataBinder` to customize the argument name to use.

xref:beans-beans-conventions[Type conversion] is applied as needed to convert user input.
If the constructor parameter is an object, it is constructed recursively in the same
manner, but through a nested property path. That means constructor binding creates both
the target object and any objects it contains.

Constructor binding supports `List`, `Map`, and array arguments either converted from
a single string, e.g. comma-separated list, or based on indexed keys such as
`accounts[2].name` or `account[KEY].name`.

Binding and conversion errors are reflected in the `BindingResult` of the `DataBinder`.
If the target is created successfully, then `target` is set to the created instance
after the call to `construct`.
Expand Down Expand Up @@ -90,13 +95,12 @@ details. The below table shows some examples of these conventions:
| Indicates the nested property `name` of the property `account` that corresponds to
(for example) the `getAccount().setName()` or `getAccount().getName()` methods.

| `account[2]`
| `accounts[2]`
| Indicates the _third_ element of the indexed property `account`. Indexed properties
can be of type `array`, `list`, or other naturally ordered collection.

| `account[COMPANYNAME]`
| Indicates the value of the map entry indexed by the `COMPANYNAME` key of the `account` `Map`
property.
| `accounts[KEY]`
| Indicates the value of the map entry indexed by the `KEY` value.
|===

(This next section is not vitally important to you if you do not plan to work with
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ NOTE: The `@BindParam` may also be placed on the fields that correspond to const
parameters. While `@BindParam` is supported out of the box, you can also use a
different annotation by setting a `DataBinder.NameResolver` on `DataBinder`

Constructor binding supports `List`, `Map`, and array arguments either converted from
a single string, e.g. comma-separated list, or based on indexed keys such as
`accounts[2].name` or `account[KEY].name`.

WebFlux, unlike Spring MVC, supports reactive types in the model, e.g. `Mono<Account>`.
You can declare a `@ModelAttribute` argument with or without a reactive type wrapper, and
it will be resolved accordingly to the actual value.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ NOTE: The `@BindParam` may also be placed on the fields that correspond to const
parameters. While `@BindParam` is supported out of the box, you can also use a
different annotation by setting a `DataBinder.NameResolver` on `DataBinder`

Constructor binding supports `List`, `Map`, and array arguments either converted from
a single string, e.g. comma-separated list, or based on indexed keys such as
`accounts[2].name` or `account[KEY].name`.

In some cases, you may want access to a model attribute without data binding. For such
cases, you can inject the `Model` into the controller and access it directly or,
alternatively, set `@ModelAttribute(binding=false)`, as the following example shows:
Expand Down

0 comments on commit 6e82bf0

Please sign in to comment.