Java Bean Validation API
API
默认包:javax.validation。
Validator
基础接口: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;
	}
}
groups
group允许在验证过程中限制约束策略的验证。在验证的过程中,group会作为参数传入,仅属于指定Group的约束才会验证。如果不指定,则是Default Group。
当指定多个Group时,验证顺序是不受控制的。
ConstraintViolation
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:返回以下对象:- bean约束,则返回约束应用的bean实例
- 放置在属性上的属性约束或容器元素约束,则返回属性所属的bean实例。
- 属性约束,调用Validator.validateValue(),返回ConstraintViolation,则为null。
- 方法参数、交叉参数、返回值 约束或者方法参数、返回值上放置的容器元素约束,则返回执行方法的对象。
- 构造函数的参数、交叉参数约束 或者构造函数的参数上放置的容器元素约束,则为null。
- 构造函数返回值约束,则为构造函数创建的对象实例。
 
- getExecutableParameters:返回方法或构造函数调用传入的参数。
- getExecutableReturnValue:返回方法或构造函数调用的返回值
- getInvalidValue:返回传给- isValid()的值,即被验证的值。对于交叉验证参数,则返回调用传入的参数数组。
- getConstraintDescriptor:约束的元数据
- getPropertyPath:返回从根对象到验证失败的对象的路径。
- unwrap:
Path
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
Node提供方法:
- getName():返回Node的表示。
- isInIterable():如果node表示一个包含在数组、多值容器(e.g. Iterable,Map)中的元素,则返回true。
- getIndex():返回元素在容器中的索引,或者 null
- getKey():返回元素在容器中的key,或者null。
- getKind():返回node 的类型
- as(Class<? extends Node>):node 转换为指定子类型。
Node的子类型:
- BeanNode
- PropertyNode
- MethodNode
- ConstructorNode
- ParameterNode
- CrossParameterNode
- ReturnValueNode
- ContainerElementNode
元素类型
public enum ElementKind {
	BEAN,
	PROPERTY,
	METHOD,
	CONSTRUCTOR,
	PARAMETER,
	CROSS_PARAMETER,
	RETURN_VALUE,
	CONTAINER_ELEMENT
}
Path生成规则
- 实例类型考虑的是运行时类型(实例的真实类型)而不是静态类型(声明类型)。
- 如果失败Node是根对象,则BeanNode的name为null,KIND为ElementKind.BEAN
- 当级联验证时: 
  - 级联属性时,添加一个PropertyNode,name为字段名或属性名。Kind为ElementKind.PROPERTY。
- 级联容器时,有index时,添加一个getIndex()返回不为null 的Node。
- 级联容器时,有key时,添加一个getKey()返回不为null 的Node。
- 级联可枚举容器时,返回isInIterable()为true 的Node
- … …
 
- 级联属性时,添加一个PropertyNode,name为字段名或属性名。Kind为
- 嵌套容器时
- 属性级别约束,返回 PropertyNode,name为字段或者属性名
- 类级别约束,返回 BeanNode,name为null。
- 方法,构造函数约束,
- 容器元素约束。
示例
Message插值(Message interpolation)
Message插值用于把约束的Message属性解析成可读的,完整的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共用。
触发方法验证
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!