默认包:javax.validation
。
基础接口:javax.validation.Validator
。
public interface Validator {
/** 验证 object
*/
<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);
/** 验证属性
*/
<T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups);
/** 验证属性值为指定value
*/
<T> Set<ConstraintViolation<T>> validateValue(
Class<T> beanType, String propertyName, Object value, Class<?>... groups);
/** 获取指定类的BeanDescriptor
*/
BeanDescriptor getConstraintsForClass(Class<?> clazz);
<T> T unwrap(Class<T> type);
ExecutableValidator forExecutables();
}
<T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups);
<T> Set<ConstraintViolation<T>> validateProperty(T object, String propertyName, Class<?>... groups);
<T> Set<ConstraintViolation<T>> validateValue(
Class<T> beanType, String propertyName, Object value, Class<?>... groups);
ExecutableValidator forExecutables();
返回的是 javax.validation.executable.ExecutableValidator
。
public interface ExecutableValidator {
/** 校验方法的所有参数
*/
<T> Set<ConstraintViolation<T>> validateParameters(
T object, Method method, Object[] parameterValues, Class<?>... groups);
/** 校验方法的返回值
*/
<T> Set<ConstraintViolation<T>> validateReturnValue(
T object, Method method, Object returnValue, Class<?>... groups);
/** 校验构造函数的参数
*/
<T> Set<ConstraintViolation<T>> validateConstructorParameters(
Constructor<? extends T> constructor, Object[] parameterValues, Class<?>... groups);
/** 校验构造函数的返回值
*/
<T> Set<ConstraintViolation<T>> validateConstructorReturnValue(
Constructor<? extends T> constructor, T createdObject, Class<?>... groups);
}
//orderService:Object ,placeOrder:Method
executableValidator.validateParameters(orderService, placeOrder, new Object[] { null, item1, 1 }, Group);
@Interceptor
public class SampleMethodInterceptor {
@Inject
private Validator validator;
@AroundInvoke
public Object invoke(MethodInvocation invocation) throws Throwable {
// Avoid Validator invocation on FactoryBean.getObjectType/isSingleton
if (isFactoryBeanMetadataMethod(invocation.getMethod())) {
return invocation.proceed();
}
Class<?>[] groups = determineValidationGroups(invocation);
// Standard Bean Validation 1.1 API
ExecutableValidator execVal = this.validator.forExecutables();
Method methodToValidate = invocation.getMethod();
Set<ConstraintViolation<Object>> result;
try {
//校验参数
result = execVal.validateParameters(
invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
catch (IllegalArgumentException ex) {
// Probably a generic type mismatch between interface and impl as reported in SPR-12237 / HV-1011
// Let's try to find the bridged method on the implementation class...
methodToValidate = BridgeMethodResolver.findBridgedMethod(
ClassUtils.getMostSpecificMethod(invocation.getMethod(), invocation.getThis().getClass()));
result = execVal.validateParameters(
invocation.getThis(), methodToValidate, invocation.getArguments(), groups);
}
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
Object returnValue = invocation.proceed();
//校验返回值
result = execVal.validateReturnValue(invocation.getThis(), methodToValidate, returnValue, groups);
if (!result.isEmpty()) {
throw new ConstraintViolationException(result);
}
return returnValue;
}
}
group允许在验证过程中限制约束策略的验证。在验证的过程中,group会作为参数传入,仅属于指定Group的约束才会验证。如果不指定,则是Default
Group。
当指定多个Group时,验证顺序是不受控制的。
ConstraintViolation
用于描述验证失败的信息。
public interface ConstraintViolation<T> {
String getMessage();
String getMessageTemplate();
T getRootBean();
Class<T> getRootBeanClass();
Object getLeafBean();
Object[] getExecutableParameters();
Object getExecutableReturnValue();
Path getPropertyPath();
Object getInvalidValue();
ConstraintDescriptor<?> getConstraintDescriptor();
<U> U unwrap(Class<U> type);
}
getMessage
:返回验证失败的本地化的message。getMessageTemplate
:返回非解析的message(一般是约束的message属性)。框架使用此值作为错误码key。getRootBean
:返回导致验证失败的根对象(例如传给Validator.validate()
方法的object
参数)。对于方法验证,返回的是正在执行方法的对象,对于构造函数或Validator.validateValue()
,返回null。getRootBeanClass
:rootBean
的Class。对于构造函数返回构造函数所在的类。getLeafBean
:返回以下对象:
Validator.validateValue()
,返回ConstraintViolation
,则为null。getExecutableParameters
:返回方法或构造函数调用传入的参数。getExecutableReturnValue
:返回方法或构造函数调用的返回值getInvalidValue
:返回传给 isValid()
的值,即被验证的值。对于交叉验证参数,则返回调用传入的参数数组。getConstraintDescriptor
:约束的元数据getPropertyPath
:返回从根对象到验证失败的对象的路径。unwrap
:public interface Path extends Iterable<Path.Node> {
@Override
String toString();
/**
* Represents an element of a navigation path.
*/
interface Node {
String getName();
boolean isInIterable();
Integer getIndex();
Object getKey();
ElementKind getKind();
<T extends Node> T as(Class<T> nodeType);
@Override
String toString();
}
interface MethodNode extends Node {
List<Class<?>> getParameterTypes();
}
interface ConstructorNode extends Node {
List<Class<?>> getParameterTypes();
}
interface ReturnValueNode extends Node {
}
interface ParameterNode extends Node {
int getParameterIndex();
}
interface CrossParameterNode extends Node {
}
interface BeanNode extends Node {
/** 获取bean的容器类型
*/
Class<?> getContainerClass();
/** 获取 类型参数的index。
*/
Integer getTypeArgumentIndex();
}
/**
* Node representing a property.
*
* @since 1.1
*/
interface PropertyNode extends Node {
Class<?> getContainerClass();
Integer getTypeArgumentIndex();
}
/** 容器元素节点
*/
interface ContainerElementNode extends Node {
Class<?> getContainerClass();
Integer getTypeArgumentIndex();
}
}
Path
为Node
的可迭代集合。
Node提供方法:
getName()
:返回Node的表示。isInIterable()
:如果node表示一个包含在数组、多值容器(e.g. Iterable,Map)中的元素,则返回true。getIndex()
:返回元素在容器中的索引,或者 nullgetKey()
:返回元素在容器中的key,或者null。getKind()
:返回node 的类型as(Class<? extends Node>)
:node 转换为指定子类型。Node的子类型:
public enum ElementKind {
BEAN,
PROPERTY,
METHOD,
CONSTRUCTOR,
PARAMETER,
CROSS_PARAMETER,
RETURN_VALUE,
CONTAINER_ELEMENT
}
BeanNode
的name
为null,KIND
为ElementKind.BEAN
ElementKind.PROPERTY
。getIndex()
返回不为null 的Node。getKey()
返回不为null 的Node。isInIterable()
为true 的NodeMessage插值用于把约束的Message属性解析成可读的,完整的Message。
每个符合Bean验证的实现都包含一个默认的消息插值,遵守规范的算法来解析消息。
消息插值的前提条件:
message
属性定义消息message
属性必须定义一个默认值。message
属性。message
格式message
是个字符串,支持参数。参数用{}
或${}
定义。特定字符需要使用转义符。\\,\{,\},\$
Value must be between {min} and {max}
Must be greater than ${inclusive == true ? 'or equal to ' : ''}{value}
从message属性中抽取参数,作为key从命名为ValidationMessages
(通常使用属性文件/ValidationMessages.properties
和它的本地变量)的ResourceBundle
查询,使用定义的locale
。如果查找到属性,则用属性值替换变量。递归应用此规则直到没有参数。
参数作为key从Bean Validation provider
内置的ResourceBundle
查询属性值,使用定义的locale
。如果查找到属性,则用属性值替换变量。此规则不能递归应用。
如果步骤2触发一个替换,则应用步骤1,否则执行步骤4
消息参数如果匹配了约束的属性,则用约束声明中指定的属性值替换。参数插值优先于消息表达式
//参数
javax.validation.constraints.Size.message=size must be between {min} and {max}
//声明的属性
@Size(min=1, max=50)
private String title;
消息字符串中的消息表达式是用EL解析。
interpolate(String,Context, Locale)
//默认使用 Locale.getDefault()
消息表达式使用 ${}
包含起来,引用的变量需要在EL上下文中能够访问。以下属性和bean可以在EL上下文中访问:
validatedValue
引用被验证的值。formatter
引用格式化器。${formatter.format('%1$.2f', validatedValue)}
如果在消息插值期间发生异常,例如由于无效表达式或引用未知属性,则消息表达式保持不变。
自定义消息插值,需要实现接口MessageInterpolator
。
public interface MessageInterpolator {
String interpolate(String messageTemplate, Context context);
String interpolate(String messageTemplate, Context context, Locale locale);
/**
* Information related to the interpolation context.
*/
interface Context {
//返回 导致验证失败的约束的metadata
ConstraintDescriptor<?> getConstraintDescriptor();
//返回正在被验证的值
Object getValidatedValue();
<T> T unwrap(Class<T> type);
}
}
messageTemplate
:约束声明时的message
属性值或者提供给ConstraintValidatorContext
方法的参数。
消息插值器实现必须是线程安全的。 此实例在ValidatorFactory
构造时通过 Configuration.messageInterpolator(MessageInterpolator)
设置,并且被由其构造的Validator
共用。