Close

JavaBean Validation - javax.validation.Validator Examples

JavaBean Validation JAVA EE 

This example shows how to use field-level constraints. The validation is performed on Validator#validate(..) call. This call returns a set of ConstraintViolation which can be used to access validation messages and other validation info.

package com.logicbig.example;


import javax.validation.*;
import javax.validation.constraints.NotNull;

public class BeanFieldValidationExample {
private static final Validator validator;

static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}

private static class MyBean {
@NotNull
private String str;

public String getStr () {
return str;
}

public void setStr (String str) {
this.str = str;
}
}

public static void main (String[] args) {
MyBean myBean = new MyBean();
validator.validate(myBean).stream()
.forEach(BeanFieldValidationExample::printError);
}

private static void printError (ConstraintViolation<MyBean> violation) {
System.out.println(violation.getPropertyPath()
+ " " + violation.getMessage());
}
}

Output

str must not be null
Original Post




This example shows how to use property-level constraints.

package com.logicbig.example;

import javax.validation.*;
import javax.validation.constraints.NotNull;

public class BeanPropertyValidationExample {
private static final Validator validator;

static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}

private static class MyBean {
private String str;

@NotNull
public String getStr () {
return str;
}

public void setStr (String str) {
this.str = str;
}
}

public static void main (String[] args) {
MyBean myBean = new MyBean();
validator.validate(myBean).stream()
.forEach(BeanPropertyValidationExample::printError);
}

private static void printError (ConstraintViolation<MyBean> violation) {
System.out.println(violation.getPropertyPath()
+ " " + violation.getMessage());
}
}

Output

str must not be null
Original Post




This examples shows how to create class-level constraint.

package com.logicbig.example;

import javax.validation.*;
import java.lang.annotation.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Set;

public class ClassLevelConstraintExample {

//using our custom constraint on class level
@ValidOrder
public static class Order {
private final BigDecimal price;
private final BigDecimal quantity;

public Order (BigDecimal price, BigDecimal quantity) {
this.price = price;
this.quantity = quantity;
}

public BigDecimal getPrice () {
return price;
}

public BigDecimal getQuantity () {
return quantity;
}

public BigDecimal getTotalPrice () {
return (price != null && quantity != null ?
price.multiply(quantity) : BigDecimal.ZERO)
.setScale(2, RoundingMode.CEILING);
}
}

//Our constraint definition
@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = OrderValidator.class)
@Documented
public static @interface ValidOrder {
String message () default "total price must be 50 or greater for online order. " +
"Found: ${validatedValue.totalPrice}";

Class<?>[] groups () default {};

Class<? extends Payload>[] payload () default {};
}

//our validator
public static class OrderValidator implements ConstraintValidator<ValidOrder, Order> {
@Override
public void initialize (ValidOrder constraintAnnotation) {
}

@Override
public boolean isValid (Order order, ConstraintValidatorContext context) {
if (order.getPrice() == null || order.getQuantity() == null) {
return false;
}
return order.getTotalPrice()
.compareTo(new BigDecimal(50)) >= 0;
}
}

//performing validation
public static void main (String[] args) {
Order order = new Order(new BigDecimal(4.5), new BigDecimal(9));

Validator validator = getValidator();
Set<ConstraintViolation<Order>> constraintViolations = validator.validate(order);

if (constraintViolations.size() > 0) {
constraintViolations.stream().forEach(
ClassLevelConstraintExample::printError);
} else {
//proceed using order
System.out.println(order);
}
}

private static Validator getValidator(){
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
Validator validator = factory.getValidator();
factory.close();
return validator;
}

private static void printError (
ConstraintViolation<Order> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}


}

Output

 total price must be 50 or greater for online order. Found: 40.50
Original Post




This examples shows how to create cross-parameter constraint on constructors.

package com.logicbig.example;

import javax.validation.*;
import javax.validation.constraintvalidation.SupportedValidationTarget;
import javax.validation.constraintvalidation.ValidationTarget;
import javax.validation.executable.ExecutableValidator;
import java.lang.annotation.*;
import java.lang.reflect.Constructor;
import java.time.LocalDate;
import java.util.Set;

public class CrossParameterConstructorExample {

//Using cross param constraint on the example bean constructor
public static class TradeHistory {
private final LocalDate startDate;
private final LocalDate endDate;

@DateRangeParams
public TradeHistory (LocalDate startDate, LocalDate endDate) {
this.startDate = startDate;
this.endDate = endDate;
}

public LocalDate getStartDate () {
return startDate;
}

public LocalDate getEndDate () {
return endDate;
}
}

//the constraint definition
@Target({ElementType.CONSTRUCTOR, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateRangeValidator.class)
@Documented
public static @interface DateRangeParams {
String message () default "'start date' must be less than 'end date'. " +
"Found: 'start date'=${validatedValue[0]}, " +
"'end date'=${validatedValue[1]}";

Class<?>[] groups () default {};

Class<? extends Payload>[] payload () default {};
}

//the validator implementation
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public static class DateRangeValidator implements
ConstraintValidator<DateRangeParams, Object[]> {
@Override
public void initialize (DateRangeParams constraintAnnotation) {
}

@Override
public boolean isValid (Object[] value, ConstraintValidatorContext context) {
if (value == null || value.length != 2 ||
!(value[0] instanceof LocalDate) ||
!(value[1] instanceof LocalDate)) {
return false;
}

return ((LocalDate) value[0]).isBefore((LocalDate) value[1]);
}
}

//performing validation
public static void main (String[] args) throws NoSuchMethodException {
LocalDate startDate = LocalDate.of(2021, 8, 10);
LocalDate endDate = LocalDate.of(2021, 7, 1);

TradeHistory tradeHistory = new TradeHistory(startDate, endDate);

Constructor<TradeHistory> constructor = TradeHistory.class.getConstructor(LocalDate
.class, LocalDate.class);

Validator validator = getValidator();
ExecutableValidator executableValidator = validator.forExecutables();
Set<ConstraintViolation<TradeHistory>> constraintViolations =
executableValidator.validateConstructorParameters(constructor,
new Object[]{startDate, endDate});

if (constraintViolations.size() > 0) {
constraintViolations.stream().forEach(
CrossParameterConstructorExample::printError);
} else {
//proceed using order
System.out.println(tradeHistory);
}
}

private static Validator getValidator(){
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
Validator validator = factory.getValidator();
factory.close();
return validator;
}

private static void printError (ConstraintViolation<TradeHistory> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}


}

Output

TradeHistory.<cross-parameter> 'start date' must be less than 'end date'. Found: 'start date'=2021-08-10, 'end date'=2021-07-01
Original Post

This examples shows how to create cross-parameter constraint on methods.

package com.logicbig.example;

import javax.validation.*;
import javax.validation.constraintvalidation.SupportedValidationTarget;
import javax.validation.constraintvalidation.ValidationTarget;
import javax.validation.executable.ExecutableValidator;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.time.LocalDate;
import java.util.Set;

public class CrossParameterMethodExample {

//Using cross param constraint on the example bean method
public static class TradeHistoryExecutor {

@DateRangeParams
public void showTradeHistory (LocalDate startDate, LocalDate endDate) {
System.out.printf("processing trade history from %s to %s %n",
startDate, endDate);
}
}

//The constraint definition
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateRangeValidator.class)
@Documented
public static @interface DateRangeParams {
String message () default "'start date' must be less than 'end date'. " +
"Found: 'start date'=${validatedValue[0]}, " +
"'end date'=${validatedValue[1]}";

Class<?>[] groups () default {};

Class<? extends Payload>[] payload () default {};
}

//The validator implementation
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public static class DateRangeValidator implements
ConstraintValidator<DateRangeParams, Object[]> {
@Override
public void initialize (DateRangeParams constraintAnnotation) {
}

@Override
public boolean isValid (Object[] value, ConstraintValidatorContext context) {
if (value == null || value.length != 2 ||
!(value[0] instanceof LocalDate) ||
!(value[1] instanceof LocalDate)) {
return false;
}

return ((LocalDate) value[0]).isBefore((LocalDate) value[1]);
}
}

//performing validation
public static void main (String[] args) throws NoSuchMethodException {
LocalDate startDate = LocalDate.of(2021, 8, 10);
LocalDate endDate = LocalDate.of(2021, 7, 1);

TradeHistoryExecutor tradeHistory = new TradeHistoryExecutor();
Method theMethod = TradeHistoryExecutor.class.getDeclaredMethod
("showTradeHistory", LocalDate.class, LocalDate.class);

Validator validator = getValidator();
ExecutableValidator executableValidator = validator.forExecutables();
Set<ConstraintViolation<TradeHistoryExecutor>> constraintViolations =
executableValidator.validateParameters(
tradeHistory,
theMethod,
new Object[]{startDate, endDate});

if (constraintViolations.size() > 0) {
constraintViolations.stream().forEach(
CrossParameterMethodExample::printError);
} else {
//proceed using order
System.out.println(tradeHistory);
}
}

private static Validator getValidator(){
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
Validator validator = factory.getValidator();
factory.close();
return validator;
}

private static void printError (ConstraintViolation<TradeHistoryExecutor> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}
}

Output

showTradeHistory.<cross-parameter> 'start date' must be less than 'end date'. Found: 'start date'=2021-08-10, 'end date'=2021-07-01
Original Post




This examples shows how to validate a group of constraints using 'group' element of constraint annotations to specify a group and then calling Validator#validate(T object, Class<?> groups) method.
Here we are creating a group:

package com.logicbig.example;

public interface GroupUserName {
}

Creating another group:

package com.logicbig.example;

public interface GroupAddress {
}

Creating bean:

package com.logicbig.example;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class User {
@NotNull(groups = GroupUserName.class)
String firstName;
@NotNull(groups = GroupUserName.class)
String lastName;

@NotNull(groups = GroupAddress.class)
String streetAddress;
@NotNull(groups = GroupAddress.class)
String country;
@NotNull(groups = GroupAddress.class)
@Size(min = 5, groups = GroupAddress.class)
String zipCode;

@NotNull
String userId;

public String getFirstName () {
return firstName;
}

public void setFirstName (String firstName) {
this.firstName = firstName;
}

public String getLastName () {
return lastName;
}

public void setLastName (String lastName) {
this.lastName = lastName;
}

public String getStreetAddress () {
return streetAddress;
}

public void setStreetAddress (String streetAddress) {
this.streetAddress = streetAddress;
}

public String getCountry () {
return country;
}

public void setCountry (String country) {
this.country = country;
}

public String getZipCode () {
return zipCode;
}

public void setZipCode (String zipCode) {
this.zipCode = zipCode;
}

public String getUserId () {
return userId;
}

public void setUserId (String userId) {
this.userId = userId;
}
}

Doing validation on 'GroupUserName':

package com.logicbig.example;

import javax.validation.*;
import java.util.Set;

public class ConstraintGroupExample {
private static final Validator validator;

static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}

public static void main (String[] args) {
User user = new User();
user.setFirstName("Jennifer");
// user.setLastName("Wilson");

Set<ConstraintViolation<User>> constraintViolations =
validator.validate(user, GroupUserName.class);

if (constraintViolations.size() > 0) {
constraintViolations.stream().forEach(
ConstraintGroupExample::printError);
} else {
//proceed using user object
System.out.println(user);
}
}

private static void printError (ConstraintViolation<User> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}
}

Output

lastName must not be null
Original Post




Doing validation on both groups.

package com.logicbig.example;

import javax.validation.*;
import javax.validation.groups.Default;
import java.util.*;
import java.util.stream.Collectors;

public class ConstraintGroupExample2 {
private static final Validator validator;

static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}

public static void main(String[] args) {
User user = new User();
user.setFirstName("Jennifer");
// user.setLastName("Wilson");

Set<ConstraintViolation<User>> constraintViolations =
validator.validate(user, GroupUserName.class,
GroupAddress.class, Default.class);

if (constraintViolations.size() > 0) {
Map<String, List<ConstraintViolation<User>>> groupViolationsMap =
constraintViolations.stream().collect(
Collectors.groupingBy(v ->
v.getConstraintDescriptor().getGroups().iterator()
.next().getSimpleName(), TreeMap::new, Collectors.toList()));

groupViolationsMap.forEach((k, v) -> {
System.out.printf("%n-- Group: %s --%n", k);
v.stream().sorted(Comparator.comparing(o -> o.getPropertyPath().toString()))
.forEach(ConstraintGroupExample2::printError);

});
} else {
//proceed using user object
System.out.println(user);
}
}

private static void printError(ConstraintViolation<User> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}
}

Output


-- Group: Default --
userId must not be null

-- Group: GroupAddress --
country must not be null
streetAddress must not be null
zipCode must not be null

-- Group: GroupUserName --
lastName must not be null
Original Post

Not specifying any group, so javax.validation.groups.Default will be used.

package com.logicbig.example;

import javax.validation.*;
import java.util.Set;

public class ConstraintGroupExample3 {
private static final Validator validator;

static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}

public static void main (String[] args) {
User user = new User();
user.setFirstName("Jennifer");
// user.setLastName("Wilson");

Set<ConstraintViolation<User>> constraintViolations =
validator.validate(user);

if (constraintViolations.size() > 0) {
constraintViolations.stream().forEach(
ConstraintGroupExample3::printError);
} else {
//proceed using user object
System.out.println(user);
}
}

private static void printError (ConstraintViolation<User> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}
}

Output

userId must not be null
Original Post




@GroupSequence example

This example shows how to use @GroupSequence to validate groups in order, one by one. We are using same bean and groups from last example.

package com.logicbig.example;

import javax.validation.GroupSequence;
import javax.validation.groups.Default;

@GroupSequence({Default.class, GroupUserName.class, GroupAddress.class})
public interface GroupSequenceForUser {
}

package com.logicbig.example;

import javax.validation.*;
import java.util.Set;

public class ConstraintGroupSequenceExample {
private static final Validator validator;

static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}

public static void main (String[] args) {
User user = new User();

Set<ConstraintViolation<User>> constraintViolations =
validator.validate(user, GroupSequenceForUser.class);

if (constraintViolations.size() > 0) {
constraintViolations.stream().forEach(
ConstraintGroupSequenceExample::printError);
} else {
//proceed using user object
System.out.println(user);
}
}

private static void printError (ConstraintViolation<User> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}
}

Output

userId must not be null
Original Post




In this example we are using @GroupSequence on our bean class to redefine the default group.

package com.logicbig.example;

import javax.validation.GroupSequence;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.groups.Default;

@GroupSequence({User2.class, GroupUserName.class, GroupAddress.class})
public class User2 {
@NotNull(groups = GroupUserName.class)
String firstName;
@NotNull(groups = GroupUserName.class)
String lastName;

@NotNull(groups = GroupAddress.class)
String streetAddress;
@NotNull(groups = GroupAddress.class)
String country;
@NotNull(groups = GroupAddress.class)
@Size(min = 5, groups = GroupAddress.class)
String zipCode;

@NotNull
String userId;

public String getFirstName () {
return firstName;
}

public void setFirstName (String firstName) {
this.firstName = firstName;
}

public String getLastName () {
return lastName;
}

public void setLastName (String lastName) {
this.lastName = lastName;
}

public String getStreetAddress () {
return streetAddress;
}

public void setStreetAddress (String streetAddress) {
this.streetAddress = streetAddress;
}

public String getCountry () {
return country;
}

public void setCountry (String country) {
this.country = country;
}

public String getZipCode () {
return zipCode;
}

public void setZipCode (String zipCode) {
this.zipCode = zipCode;
}

public String getUserId () {
return userId;
}

public void setUserId (String userId) {
this.userId = userId;
}
}

package com.logicbig.example;

import javax.validation.*;
import javax.validation.groups.Default;
import java.util.Set;

public class RedefiningDefaultGroupExample {
private static final Validator validator;

static {
Configuration<?> config = Validation.byDefaultProvider().configure();
ValidatorFactory factory = config.buildValidatorFactory();
validator = factory.getValidator();
factory.close();
}

public static void main (String[] args) {
User2 user = new User2();

Set<ConstraintViolation<User2>> constraintViolations =
validator.validate(user);

if (constraintViolations.size() > 0) {
constraintViolations.stream().forEach(
RedefiningDefaultGroupExample::printError);
} else {
//proceed using user object
System.out.println(user);
}
}

private static void printError (ConstraintViolation<User2> violation) {
System.out.println(violation.getPropertyPath() + " " + violation.getMessage());
}
}

Output

userId must not be null
Original Post




See Also