[[mvc-ann-modelattrib-method-args]]
= `@ModelAttribute`

[.small]#xref:web/webflux/controller/ann-methods/modelattrib-method-args.adoc[See equivalent in the Reactive stack]#

You can use the `@ModelAttribute` annotation on a method argument to access an attribute from
the model or have it be instantiated if not present. The model attribute is also overlain with
values from HTTP Servlet request parameters whose names match to field names. This is referred
to as data binding, and it saves you from having to deal with parsing and converting individual
query parameters and form fields. The following example shows how to do so:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
	@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
	public String processSubmit(@ModelAttribute Pet pet) { // <1>
		// method logic...
	}
----
<1> Bind an instance of `Pet`.

Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
fun processSubmit(@ModelAttribute pet: Pet): String { // <1>
	// method logic...
}
----
<1> Bind an instance of `Pet`.
======

The `Pet` instance above is sourced in one of the following ways:

* Retrieved from the model where it may have been added by a
  xref:web/webmvc/mvc-controller/ann-modelattrib-methods.adoc[@ModelAttribute method].
* Retrieved from the HTTP session if the model attribute was listed in
  the class-level xref:web/webmvc/mvc-controller/ann-methods/sessionattributes.adoc[`@SessionAttributes`] annotation.
* Obtained through a `Converter` where the model attribute name matches the name of a
  request value such as a path variable or a request parameter (see next example).
* Instantiated using its default constructor.
* Instantiated through a "`primary constructor`" with arguments that match to Servlet
  request parameters. Argument names are determined through JavaBeans
  `@ConstructorProperties` or through runtime-retained parameter names in the bytecode.

One alternative to using a xref:web/webmvc/mvc-controller/ann-modelattrib-methods.adoc[@ModelAttribute method] to
supply it or relying on the framework to create the model attribute, is to have a
`Converter<String, T>` to provide the instance. This is applied when the model attribute
name matches to the name of a request value such as a path variable or a request
parameter, and there is a `Converter` from `String` to the model attribute type.
In the following example, the model attribute name is `account` which matches the URI
path variable `account`, and there is a registered `Converter<String, Account>` which
could load the `Account` from a data store:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
	@PutMapping("/accounts/{account}")
	public String save(@ModelAttribute("account") Account account) { // <1>
		// ...
	}
----
<1> Bind an instance of `Account` using an explicit attribute name.

Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
	@PutMapping("/accounts/{account}")
	fun save(@ModelAttribute("account") account: Account): String { // <1>
		// ...
	}
----
<1> Bind an instance of `Account` using an explicit attribute name.
======

After the model attribute instance is obtained, data binding is applied. The
`WebDataBinder` class matches Servlet request parameter names (query parameters and form
fields) to field names on the target `Object`. Matching fields are populated after type
conversion is applied, where necessary. For more on data binding (and validation), see
xref:web/webmvc/mvc-config/validation.adoc[Validation]. For more on customizing data binding, see
xref:web/webmvc/mvc-controller/ann-initbinder.adoc[`DataBinder`].

Data binding can result in errors. By default, a `BindException` is raised. However, to check
for such errors in the controller method, you can add a `BindingResult` argument immediately next
to the `@ModelAttribute`, as the following example shows:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
	@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
	public String processSubmit(@ModelAttribute("pet") Pet pet, BindingResult result) { // <1>
		if (result.hasErrors()) {
			return "petForm";
		}
		// ...
	}
----
<1> Adding a `BindingResult` next to the `@ModelAttribute`.

Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
	@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
	fun processSubmit(@ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
		if (result.hasErrors()) {
			return "petForm"
		}
		// ...
	}
----
<1> Adding a `BindingResult` next to the `@ModelAttribute`.
======

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:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
	@ModelAttribute
	public AccountForm setUpForm() {
		return new AccountForm();
	}

	@ModelAttribute
	public Account findAccount(@PathVariable String accountId) {
		return accountRepository.findOne(accountId);
	}

	@PostMapping("update")
	public String update(@Valid AccountForm form, BindingResult result,
			@ModelAttribute(binding=false) Account account) { // <1>
		// ...
	}
----
<1> Setting `@ModelAttribute(binding=false)`.

Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
	@ModelAttribute
	fun setUpForm(): AccountForm {
		return AccountForm()
	}

	@ModelAttribute
	fun findAccount(@PathVariable accountId: String): Account {
		return accountRepository.findOne(accountId)
	}

	@PostMapping("update")
	fun update(@Valid form: AccountForm, result: BindingResult,
			   @ModelAttribute(binding = false) account: Account): String { // <1>
		// ...
	}
----
<1> Setting `@ModelAttribute(binding=false)`.
======

You can automatically apply validation after data binding by adding the
`jakarta.validation.Valid` annotation or Spring's `@Validated` annotation
(xref:core/validation/beanvalidation.adoc[Bean Validation] and
xref:web/webmvc/mvc-config/validation.adoc[Spring validation]). The following example shows how to do so:

[tabs]
======
Java::
+
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
----
		@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
		public String processSubmit(@Valid @ModelAttribute("pet") Pet pet, BindingResult result) { // <1>
			if (result.hasErrors()) {
				return "petForm";
			}
			// ...
		}
----
<1> Validate the `Pet` instance.

Kotlin::
+
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
----
	@PostMapping("/owners/{ownerId}/pets/{petId}/edit")
	fun processSubmit(@Valid @ModelAttribute("pet") pet: Pet, result: BindingResult): String { // <1>
		if (result.hasErrors()) {
			return "petForm"
		}
		// ...
	}
----
<1> Validate the `Pet` instance.
======

Note that using `@ModelAttribute` is optional (for example, to set its attributes).
By default, any argument that is not a simple value type (as determined by
{api-spring-framework}/beans/BeanUtils.html#isSimpleProperty-java.lang.Class-[BeanUtils#isSimpleProperty])
and is not resolved by any other argument resolver is treated as if it were annotated
with `@ModelAttribute`.


