Field-level constraints
package org.hibernate.validator.referenceguide.chapter02.fieldlevel;
public class Car {
@NotNull
private String manufacturer;
@AssertTrue
private boolean isRegistered;
public Car(String manufacturer, boolean isRegistered) {
this.manufacturer = manufacturer;
this.isRegistered = isRegistered;
}
//getters and setters...
}
字段级别校验可以直接访问被校验的实例字段,does not invoke the property accessor method even if such an accessor exists.可以访问public、private etc等级别,静态字段是不支持的
Property-level constraints
public class Car {
private String manufacturer;
private boolean isRegistered;
public Car(String manufacturer, boolean isRegistered) {
this.manufacturer = manufacturer;
this.isRegistered = isRegistered;
}
@NotNull
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
@AssertTrue
public boolean isRegistered() {
return isRegistered;
}
public void setRegistered(boolean isRegistered) {
this.isRegistered = isRegistered;
}
}
不建议在filed 和 get上都加注释,否则会校验两次
Container element constraints
Hibernate Validator validates container element constraints specified on the following standard Java containers:
-
implementations of
java.util.Iterable
(e.g.List
s,Set
s), -
implementations of
java.util.Map
, with support for keys and values, -
java.util.Optional
,java.util.OptionalInt
,java.util.OptionalDouble
,java.util.OptionalLong
, -
the various implementations of JavaFX’s
javafx.beans.observable.ObservableValue
.
package org.hibernate.validator.referenceguide.chapter02.containerelement.set;
import java.util.HashSet;
import java.util.Set;
public class Car {
private Set<@ValidPart String> parts = new HashSet<>();
public void addPart(String part) {
parts.add( part );
}
//...
}
Car car = new Car();
car.addPart( "Wheel" );
car.addPart( null );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
ConstraintViolation<Car> constraintViolation =
constraintViolations.iterator().next();
assertEquals(
"'null' is not a valid car part.",
constraintViolation.getMessage()
);
assertEquals( "parts[].<iterable element>",
constraintViolation.getPropertyPath().toString() );
package org.hibernate.validator.referenceguide.chapter02.containerelement.optional;
public class Car {
private Optional<@MinTowingCapacity(1000) Integer> towingCapacity = Optional.empty();
public void setTowingCapacity(Integer alias) {
towingCapacity = Optional.of( alias );
}
//...
}
Car car = new Car();
car.setTowingCapacity( 100 );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
ConstraintViolation<Car> constraintViolation = constraintViolations.iterator().next();
assertEquals(
"Not enough towing capacity.",
constraintViolation.getMessage()
);
assertEquals(
"towingCapacity",
constraintViolation.getPropertyPath().toString()
);
Nested container elements
Constraints are also supported on nested container elements.
package org.hibernate.validator.referenceguide.chapter02.containerelement.nested;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.constraints.NotNull;
public class Car {
private Map<@NotNull Part, List<@NotNull Manufacturer>> partManufacturers =
new HashMap<>();
//...
}
Class-level constraints
不仅是单个属性校验 整个类级别的校验都可以,类级别校验非常有用如果对象不同属性有关联的话。
以下@ValidPassengerCount 加在类级别上,那么校验器就可以访问整个car对象,访问比较座位和乘客的数量。
package org.hibernate.validator.referenceguide.chapter02.classlevel;
@ValidPassengerCount
public class Car {
private int seatCount;
private List<Person> passengers;
//...
}
package org.hibernate.validator.referenceguide.chapter06.classlevel;
@Target({ TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { ValidPassengerCountValidator.class })
@Documented
public @interface ValidPassengerCount {
String message() default "{org.hibernate.validator.referenceguide.chapter06.classlevel." +
"ValidPassengerCount.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
package org.hibernate.validator.referenceguide.chapter06.classlevel;
public class ValidPassengerCountValidator
implements ConstraintValidator<ValidPassengerCount, Car> {
@Override
public void initialize(ValidPassengerCount constraintAnnotation) {
}
@Override
public boolean isValid(Car car, ConstraintValidatorContext context) {
if ( car == null ) {
return true;
}
return car.getPassengers().size() <= car.getSeatCount();
}
}
Object graphs
Cascaded validation
package org.hibernate.validator.referenceguide.chapter02.objectgraph;
public class Car {
@NotNull
@Valid
private Person driver;
//...
}
package org.hibernate.validator.referenceguide.chapter02.objectgraph;
public class Person {
@NotNull
private String name;
//...
}
对象图的校验是递归的,因此不能出现引用自己的情况,保证对象图没有闭环,在cascaded validation中 null值是被忽略的。
对象图也可用在容器中校验,容器参数加上@Valid 那么每个元素都会校验。
package org.hibernate.validator.referenceguide.chapter02.objectgraph.containerelement;
public class Car {
private List<@NotNull @Valid Person> passengers = new ArrayList<Person>();
private Map<@Valid Part, List<@Valid Manufacturer>> partManufacturers = new HashMap<>();
//...
}
package org.hibernate.validator.referenceguide.chapter02.objectgraph.containerelement;
public class Part {
@NotNull
private String name;
//...
}
package org.hibernate.validator.referenceguide.chapter02.objectgraph.containerelement;
public class Manufacturer {
@NotNull
private String name;
//...
}
When validating an instance of the Car
class shown in Example 2.12, “Cascaded validation of containers”, a ConstraintViolation
will be created:
-
if any of the
Person
objects contained in the passengers list has anull
name; -
if any of the
Part
objects contained in the map keys has anull
name; -
if any of the
Manufacturer
objects contained in the list nested in the map values has anull
name.
Validating bean constraints
Obtaining a Validator
instance
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
Validator methods
Validator#validate()
Car car = new Car( null, true );
Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car );
assertEquals( 1, constraintViolations.size() );
assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );
Validator#validateProperty()
Car car = new Car( null, true );
Set<ConstraintViolation<Car>> constraintViolations = validator.validateProperty(
car,
"manufacturer"
);
assertEquals( 1, constraintViolations.size() );
assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );
Validator#validateValue() // 将某个值 用class filed 上的校验规则进行校验
Set<ConstraintViolation<Car>> constraintViolations = validator.validateValue(
Car.class,
"manufacturer",
null
);
assertEquals( 1, constraintViolations.size() );
assertEquals( "must not be null", constraintViolations.iterator().next().getMessage() );
Bean Validation constraints
Hibernate Validator 6.0.22.Final - JSR 380 Reference Implementation: Reference Guide
Declaring and validating method constraints
Declaring method constraints
Parameter constraints
package org.hibernate.validator.referenceguide.chapter03.parameter;
public class RentalStation {
public RentalStation(@NotNull String name) {
//...
}
public void rentCar(
@NotNull Customer customer,
@NotNull @Future Date startDate,
@Min(1) int durationInDays) {
//...
}
}
Cross-parameter constraints
n order to define a cross-parameter constraint, its validator class must be annotated with @SupportedValidationTarget(ValidationTarget.PARAMETERS)
. The type parameter T
from the ConstraintValidator
interface must resolve to either Object
or Object[]
in order to receive the array of method/constructor arguments in the isValid()
method.
package org.hibernate.validator.referenceguide.chapter03.crossparameter;
public class Car {
@LuggageCountMatchesPassengerCount(piecesOfLuggagePerPassenger = 2)
public void load(List<Person> passengers, List<PieceOfLuggage> luggage) {
//...
}
}
package org.hibernate.validator.referenceguide.chapter06.crossparameter;
@Constraint(validatedBy = ConsistentDateParametersValidator.class)
@Target({ METHOD, CONSTRUCTOR, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Documented
public @interface ConsistentDateParameters {
String message() default "{org.hibernate.validator.referenceguide.chapter04." +
"crossparameter.ConsistentDateParameters.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
package org.hibernate.validator.referenceguide.chapter06.crossparameter;
@SupportedValidationTarget(ValidationTarget.PARAMETERS)
public class ConsistentDateParametersValidator implements
ConstraintValidator<ConsistentDateParameters, Object[]> {
@Override
public void initialize(ConsistentDateParameters constraintAnnotation) {
}
@Override
public boolean isValid(Object[] value, ConstraintValidatorContext context) {
if ( value.length != 2 ) {
throw new IllegalArgumentException( "Illegal method signature" );
}
//leave null-checking to @NotNull on individual parameters
if ( value[0] == null || value[1] == null ) {
return true;
}
if ( !( value[0] instanceof Date ) || !( value[1] instanceof Date ) ) {
throw new IllegalArgumentException(
"Illegal method signature, expected two " +
"parameters of type Date."
);
}
return ( (Date) value[0] ).before( (Date) value[1] );
}
}
package org.hibernate.validator.referenceguide.chapter03.parameterscriptassert;
public class Car {
@ParameterScriptAssert(lang = "javascript", script = "luggage.size() <= passengers.size() * 2")
public void load(List<Person> passengers, List<PieceOfLuggage> luggage) {
//...
}
}