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()); } }
Outputstr 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()); } }
Outputstr 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()); }
}
OutputTradeHistory.<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()); } }
OutputshowTradeHistory.<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()); } }
OutputlastName 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()); } }
OutputuserId 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()); } }
OutputuserId 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()); } }
OutputuserId must not be null
Original Post
|
|