---
title: YAVI has become easier to use with Spring MVC's @Valid/Validated in Spring 6.1
tags: ["Java", "YAVI", "Spring Boot", "Spring MVC"]
categories: ["Programming", "Java", "org", "springframework", "validation"]
date: 2023-07-10T07:16:44Z
updated: 2023-07-10T07:35:31Z
---

> ⚠️ This article was automatically translated by OpenAI (gpt-4o-mini).
> It may be edited eventually, but please be aware that it may contain incorrect information at this time.

In Spring 6.1.0-M1, a functional Validator factory method was added (https://github.com/spring-projects/spring-framework/pull/29890).

As a result, converting YAVI's Validator to Spring's Validator has become easier. Therefore, YAVI has become easier to use in Controllers that perform validation with `@Valid`/`@Validated`.

Let's take the "Validating Form Input" guide from [Spring's documentation](https://spring.io/guides) as an example and change Bean Validation to YAVI.

First, let's define the validation.

The original definition is:

```java
package com.example.validatingforminput;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;

public class PersonForm {

	@NotNull
	@Size(min=2, max=30)
	private String name;

	@NotNull
	@Min(18)
	private Integer age;

	// ...
}
```

When written with YAVI, for example:

```java
package com.example.validatingforminput;

import am.ik.yavi.builder.ValidatorBuilder;
import am.ik.yavi.core.Validator;

public class PersonForm {

	public static Validator<PersonForm> validator = ValidatorBuilder.<PersonForm>of()
			.constraint(PersonForm::getName, "name", c -> c.notNull().greaterThanOrEqual(2).lessThanOrEqual(30))
			.constraint(PersonForm::getAge, "age", c -> c.notNull().greaterThanOrEqual(18))
			.build();

	// ...
}
```

This is how it looks.

The original code for using validation in the Controller is:

```java
package com.example.validatingforminput;

import jakarta.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Controller
public class WebController implements WebMvcConfigurer {

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/results").setViewName("results");
	}

	@GetMapping("/")
	public String showForm(PersonForm personForm) {
		return "form";
	}

	@PostMapping("/")
	public String checkPersonInfo(@Valid PersonForm personForm, BindingResult bindingResult) {

		if (bindingResult.hasErrors()) {
			return "form";
		}

		return "redirect:/results";
	}
}
```

When using YAVI + Spring 6.1, it can be written as follows:

```java
package com.example.validatingforminput;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;


@Controller
public class WebController implements WebMvcConfigurer {

	@Override
	public void addViewControllers(ViewControllerRegistry registry) {
		registry.addViewController("/results").setViewName("results");
	}

	@InitBinder
	void initBinder(WebDataBinder binder) {
		Validator personValidator = Validator.forInstanceOf(PersonForm.class, PersonForm.validator.toBiConsumer(Errors::rejectValue));
		binder.addValidators(personValidator);
	}

	@GetMapping("/")
	public String showForm(PersonForm personForm) {
		return "form";
	}

	@PostMapping("/")
	public String checkPersonInfo(@Validated PersonForm personForm, BindingResult bindingResult) {

		if (bindingResult.hasErrors()) {
			return "form";
		}

		return "redirect:/results";
	}
}
```

The following part utilizes the factory method available in Spring 6.1:

```java
Validator personValidator = Validator.forInstanceOf(PersonForm.class, PersonForm.validator.toBiConsumer(Errors::rejectValue));
```

In the above example, Bean Validation and `spring-boot-starter-validation` are excluded from the dependencies. Therefore, `@Validated` (Spring's annotation) is used instead of `@Valid` (Bean Validation's annotation). Both can be used.

The overall diff can be found at https://github.com/making/gs-validating-form-input/commit/7261b26bf94c4aae86b52c68f9f78380e07a79f3.

The diff for just the Controller is as follows:

<img width="1024" alt="image" src="https://github.com/making/blog.ik.am/assets/106908/0c72d61a-156c-4a9d-a49c-63b42475c467">

The Controller code can now use YAVI instead of Bean Validation without significant changes.

---

By the way, as mentioned in the [documentation](https://yavi.ik.am/#integrations), YAVI has been easily usable with Spring MVC even before this.

In this example, it can be written as follows:

```java
	@PostMapping("/")
	public String checkPersonInfo(@Validated PersonForm personForm, BindingResult bindingResult) {
		ConstraintViolations violations = PersonForm.validator.validate(personForm);
		if (!violations.isValid()) {
			violations.apply(bindingResult::rejectValue);
			return "form";
		}

		return "redirect:/results";
	}
```

or

```java
	@PostMapping("/")
	public String checkPersonInfo(@Validated PersonForm personForm, BindingResult bindingResult) {
		return PersonForm.validator.applicative()
				.validate(personForm)
				.fold(violations -> {
					ConstraintViolations.of(violations).apply(bindingResult::rejectValue);
					return "form";
				}, form -> "redirect:/results");
	}
```

This update has particularly enhanced compatibility for those who prefer the programming model using `@Valid`/`@Validated`.
