首发博客地址
一、声明bean约束
1. 字段级别约束
- 不支持静态类型字段
- 验证引擎直接访问实例变量,不会调用属性的访问器
- 在验证字节码增强的对象时,应适用属性级别约束,因为字节码增库无法通过反射确定字段访问
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... }
2. 属性级别约束
- 必须注释getter而不是setter,这样可以限制没有设置方法的只读属性
- 该级别将使用属性访问策略来访问验证的值,即验证引擎通过属性访问器来访问数据
- 不要字段和getter都加校验,这样会导致校验两次
package org.hibernate.validator.referenceguide.chapter02.propertylevel; 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; } }
- 容器元素约束
3.1 Iterable
在该类型上加约束时,将会校验每个元素
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() );
3.2 List
也会校验每个元素
package org.hibernate.validator.referenceguide.chapter02.containerelement.list; public class Car { private List<@ValidPart String> parts = new ArrayList<>(); 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[1].<list element>", constraintViolation.getPropertyPath().toString() );
3.3 Map
package org.hibernate.validator.referenceguide.chapter02.containerelement.map; import java.util.HashMap; import java.util.Map; import javax.validation.constraints.NotNull; public class Car { public enum FuelConsumption { CITY, HIGHWAY } private Map<@NotNull FuelConsumption, @MaxAllowedFuelConsumption Integer> fuelConsumption = new HashMap<>(); public void setFuelConsumption(FuelConsumption consumption, int value) { fuelConsumption.put( consumption, value ); } //... }
Car car = new Car(); car.setFuelConsumption( Car.FuelConsumption.HIGHWAY, 20 ); Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car ); assertEquals( 1, constraintViolations.size() ); ConstraintViolation<Car> constraintViolation = constraintViolations.iterator().next(); assertEquals( "20 is outside the max fuel consumption.", constraintViolation.getMessage() ); assertEquals( "fuelConsumption[HIGHWAY].<map value>", constraintViolation.getPropertyPath().toString() );
Car car = new Car(); car.setFuelConsumption( null, 5 ); Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car ); assertEquals( 1, constraintViolations.size() ); ConstraintViolation<Car> constraintViolation = constraintViolations.iterator().next(); assertEquals( "must not be null", constraintViolation.getMessage() ); assertEquals( "fuelConsumption<K>[].<map key>", constraintViolation.getPropertyPath().toString() );
3.4 Optional
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 ); } //... } • 1
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() );
3.5 自定义容器
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom; public class Car { private GearBox<@MinTorque(100) Gear> gearBox; public void setGearBox(GearBox<Gear> gearBox) { this.gearBox = gearBox; } //... }
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom; public class GearBox<T extends Gear> { private final T gear; public GearBox(T gear) { this.gear = gear; } public Gear getGear() { return this.gear; } }
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom; public class Gear { private final Integer torque; public Gear(Integer torque) { this.torque = torque; } public Integer getTorque() { return torque; } public static class AcmeGear extends Gear { public AcmeGear() { super( 60 ); } } }
package org.hibernate.validator.referenceguide.chapter02.containerelement.custom; public class GearBoxValueExtractor implements ValueExtractor<GearBox<@ExtractedValue ?>> { @Override public void extractValues(GearBox<@ExtractedValue ?> originalValue, ValueExtractor.ValueReceiver receiver) { receiver.value( null, originalValue.getGear() ); } }
Car car = new Car(); car.setGearBox( new GearBox<>( new Gear.AcmeGear() ) ); Set<ConstraintViolation<Car>> constraintViolations = validator.validate( car ); assertEquals( 1, constraintViolations.size() ); ConstraintViolation<Car> constraintViolation = constraintViolations.iterator().next(); assertEquals( "Gear is not providing enough torque.", constraintViolation.getMessage() ); assertEquals( "gearBox", constraintViolation.getPropertyPath().toString() );
3.6 嵌套容器元素
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<>(); //... }
4. 类级别约束
- 在这种情况下,验证的对象不是单个属性而是完整的对象
- 适合依赖于对象的多个属性之间的相关性很高的场景
package org.hibernate.validator.referenceguide.chapter02.classlevel; @ValidPassengerCount public class Car { private int seatCount; private List<Person> passengers; //... }
5. 约束继承
在一个类实现接口或扩展另一个类时,在超类上声明的所有约束注释都以与该类本身上指定的约束相同的方式约束
package org.hibernate.validator.referenceguide.chapter02.inheritance; public class Car { private String manufacturer; @NotNull public String getManufacturer() { return manufacturer; } //... }
package org.hibernate.validator.referenceguide.chapter02.inheritance; public class RentalCar extends Car { private String rentalStation; @NotNull public String getRentalStation() { return rentalStation; } //... }
- RentalCar 不仅会校验getRentalStation,而且会校验父类的getManufacturer
- 若继承换成接口,也是会校验超类的