1. Avaje Validator
Bean validation via Avaje Validator.
1.1. Usage
1) Add the dependency:
<dependency>
<groupId>io.jooby</groupId>
<artifactId>jooby-avaje-validator</artifactId>
<version>3.4.1</version>
</dependency>
2) Configure annotation processor
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>...</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.avaje</groupId>
<artifactId>avaje-validator-generator</artifactId>
<version>2.2</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
3) Install
import io.jooby.avaje.validator.AvajeValidatorModule;
{
install(new AvajeValidatorModule());
}
4) Usage in MVC routes
import io.jooby.annotation.*;
import jakarta.validation.Valid;
@Path("/mvc")
public class Controller {
@POST("/validate-body")
public void validateBody(@Valid Bean bean) { (1)
...
}
@POST("/validate-query")
public void validateQuery(@Valid @QueryParam Bean bean) { (2)
...
}
@POST("/validate-list")
public void validateList(@Valid List<Bean> beans) { (3)
...
}
@POST("/validate-map")
public void validateMap(@Valid Map<String, Bean> beans) { (4)
...
}
}
1 | Validate a bean decoded from the request body |
2 | Validate a bean parsed from query parameters. This works the same for @FormParam or @BindParam |
3 | Validate a list of beans. This also applies to arrays @Valid Bean[] beans |
4 | Validate a map of beans |
4) Usage in in script/lambda routes
import io.jooby.validation.BeanValidator;
{
use(BeanValidator.validate());
post("/validate", ctx -> {
Bean bean = ctx.body(Bean.class);
...
});
}
Please note, if you are mixing both approaches (MVC/scripts), it’s better to avoid using a filter, as it may lead to double validation on MVC routes. In this case, it’s recommended to use the handler version (see below). |
BeanValidator.validate()
behaves identically to validation in MVC routes.
It also supports validating list, array, and map of beans.
There is a handler version of it, so you can apply per route:
import io.jooby.validation.BeanValidator.validate;
{
post("/validate", validate(ctx -> {
Bean bean = ctx.body(Bean.class);
...
}));
}
1.2. Constraint Violations Rendering
AvajeValidatorModule
provides default built-in error handler that
catches ConstraintViolationException
and transforms it into the following response:
{
"title": "Validation failed",
"status": 422,
"errors": [
{
"field": "firstName",
"messages": [
"must not be empty",
"must not be null"
],
"type": "FIELD"
},
{
"field": null,
"messages": [
"passwords are not the same"
],
"type": "GLOBAL"
}
]
}
It is possible to override the title
and status
code of the response above:
{
install(new AvajeJsonbModule());
install(new AvajeValidatorModule()
.statusCode(StatusCode.BAD_REQUEST)
.validationTitle("Incorrect input data")
);
}
If the default error handler doesn’t fully meet your needs, you can always disable it and provide your own:
{
install(new AvajeJsonbModule());
install(new AvajeValidatorModule().disableViolationHandler());
error(ConstraintViolationException.class, new MyConstraintViolationHandler());
}
1.3. Manual Validation
The module exposes Validator
as a service, allowing you to run validation manually at any time.
1.3.1. Script/lambda:
import io.avaje.validation.Validator;
{
post("/validate", ctx -> {
Validator validator = require(Validator.class);
validator.validate(ctx.body(Bean.class));
...
});
}
1.3.2. MVC routes with dependency injection:
1) Install DI framework at first.
import io.jooby.avaje.validator.AvajeValidatorModule;
{
install(AvajeInjectModule.of()); (1)
install(new AvajeValidatorModule());
}
1 | Avaje is just an example, you can achieve the same with Dagger or Guice |
2) Inject Validator
in controller, service etc.
import io.avaje.validation.Validator;
import jakarta.inject.Inject;
@Path("/mvc")
public class Controller {
private final Validator validator;
@Inject
public Controller(Validator validator) {
this.validator = validator;
}
@POST("/validate")
public void validate(Bean bean) {
Set<ConstraintViolation<Bean>> violations = validator.validate(bean);
...
}
}
1.4. Configuration
Any property defined at validation
will be added automatically:
validation.fail_fast = true
Or programmatically:
import io.jooby.avaje.validator.AvajeValidatorModule;
{
install(new AvajeValidatorModule().doWith(cfg -> {
cfg.failFast(true);
}));
}