Bean Validation
Constrain Once, Validate Everywhere
Bean Validation is a Java specification that can constrain the object model through annotations, provides rich annotation definitions, and can reduce repeated and redundant constraint validation. Supports validation APIs for method input parameters, output parameters. Constraint validation can be performed manually, and the annotated constraints can also be validated in other frameworks such as Spring, JPA, etc. It is naturally more common to use it integrated with the framework.
Book book = new Book();
if (book != null
&& book.getCategory() != null
&& book.getCategory().trim().length() != 0
&& book.getTitle() != null
&& book.getTitle().trim().length() != 0
&& book.getWriter() != null
&& book.getWriter().trim().length() != 0) {
}As you can see from the code above, there is a lot of boilerplate constraint validation code.
1. Bean Validation History
The first version of Bean Validation was released in 2009, the latest version was released in October 2020. Hibernate Validator and Apache BVal are the main certified implementations of Bean Validation.
1.1 Bean Validation Version Features
The purpose of Bean Validation 2.0 and Bean Validation 3.0 is to complete the migration from Java EE to Jakarta EE and deal with the Java trademark issues involved in the Eclipse Foundation. There are no new features added, but it should be noted that the API package was changed from javax.validation to jakarta.validation in Bean Validation 3.0, which may cause compatibility issues with other frameworks.
- Bean Validation 1.0 basic Bean validation capabilities.
- Bean Validation 1.1 constraints at the method level, including input parameters and output parameters. Constraint violation messages EL expressions supported. And more.
- Bean Validation 2.0 added some new constraint annotations, such as @Email, @NotEmpty, etc. The getter method is no longer necessary and supports obtaining field values through reflection. Constraints can be placed on elements in the container (List / Map). Java 8 or later is required to use Bean Validation 2.0. And more.
2. Constraint Validation
Bean Validation provides many rich validation scenarios, including the most commonly used null values, numerical value limits, and nested bean validation. Group validation may be used in some scenarios, For example, adding new records to database does not require id constraints, but Updating and deleting records require id constraint.
2.1 Basic Validation
Compared with the constraint code at the beginning of this blog, the code here is much simpler. Imagine the situation when there are many attributes.
public class Book {
@javax.validation.constraints.NotBlank
private String title;
@javax.validation.constraints.NotBlank(message = "can not be blank")
private String writer;
@javax.validation.constraints.Max(value = 5, message = "must be lower or equal to {value}")
private Integer words = 10;
private String category = "Tech World";
}
validator.validate(new Book());2.2 Nested Validation
Use @Valid to enable nested validation.
class Book {Get 8techlife’s stories in your inbox
Join Medium for free to get updates from this writer.
.....
@javax.validation.constraints.NotEmpty
private List<@javax.validation.Valid Content> contents = List.of(new Content());
}
class Content {
@javax.validation.constraints.NotBlank
private String lines;
}
validator.validate(new Book());
2.3 Group Validation
Define ListGroup and MapGroup, you can select different groups for validation.
public class BeanForGroupValidation {
interface ListGroup {
}
interface MapGroup {
}
@NotNull(groups = ListGroup.class, message = "listGroup")
private List<String> list;
@NotNull(groups = MapGroup.class, message = "mapGroup")
private Map<String, String> map;
@NotNull(message = "belong defaultGroup")
private Map<String, String> defaultMap;
}
BeanForGroupValidation beanForGroupValidation = new BeanForGroupValidation();
// default validation
validator.validate(beanForGroupValidation);
// ListGroup validation
validator.validate(beanForGroupValidation, BeanForGroupValidation.ListGroup.class);
// MapGroup validation
validator.validate(beanForGroupValidation, BeanForGroupValidation.MapGroup.class);
// default and MapGroup validation
validator.validate(beanForGroupValidation, Default.class, BeanForGroupValidation.MapGroup.class);3. Performed Manually
The following example uses the implementation of Hibernate Validator provider to illustrate. Add dependencies:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.1.Final</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>3.0.1-b06</version>
</dependency>3.1 Sample Code
class Book {
@NotBlank
private String title = "Hello World";
@NotBlank(message = "writer can not be blank")
private String writer;
@Max(value = 5, message = "value must be lower or equal to {value}")
private Integer words = 10;
private String category = "Tech World";
}
// validation
Book book = new Book();
try (ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory()) {
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<Book>> result = validator.validate(book);
List<String> message = result.stream().map(v -> v.getPropertyPath() + " " + v.getMessage() + ": " + v.getInvalidValue()).toList();
message.forEach(System.out::println);
}4. Spring Integration
4.1 Spring MVC
By default, Spring MVC uses LocalValidatorFactoryBean as global Bean Validation, which loads Bean Validation Provider through SPI. We can also extend the Bean Validation implementation in Spring MVC.
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
@Bean
public Validator validator() {
ValidatorFactory vf = Validation.byProvider(HibernateValidator.class)
.configure().failFast(true)
.buildValidatorFactory();
return vf.getValidator();
}A simple application of method validation in Controller. Both @Validated and @Valid can mark method parameters, but only @Validated supports group validation.
@RequestMapping(value = "/beanValidation", method = RequestMethod.POST)
public void testBeanValidation(@Valid BeanForValidate beanForValidate)
// with group validation
@RequestMapping(value = "/beanValidation", method = RequestMethod.POST)
public void testBeanValidation(@Validated(value = Default.class) BeanForValidate beanForValidate)Violating constraints will throw a MethodArgumentNotValidException exception.
4.2 Method Validation
By creating a MethodValidationPostProcessor bean in Spring, the specified method can perform constraint validation through the @Validated annotation.
@Configuration
public class AppConfig {
@Bean
public MethodValidationPostProcessor validationPostProcessor() {
return new MethodValidationPostProcessor();
}
}@Validated can be applied to classes or interfaces. Violating constraints will throw a ConstraintViolationException exception.
@Validated
public class BeanValidationService {
void testBeanValidation(@Valid BeanForValidate beanForValidate){};
}
// with group validation
@Validated
public interface BeanValidationService {
@Validated(value = Default.class)
void testBeanValidation(@Valid BeanForValidate beanForValidate);
}








