简介:JSR 303 标准的定义,与官方的实现,源码的阅读,自定义实现
简介
JSR303 是java标准的一个验证bean的框架,本文主要用来记录对其使用及设计的各种剖析
‘约束’如何定义
@Constraint
- 所有验证注解的元注解
方法
public Class<? extends ConstraintValidator<?, ?>>[] validatedBy();
定义验证的具体逻辑实现类
如
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { }) //此处使用了元注解@Constraint
public @interface NotNull {
...
}
‘每个约束’ 必须定义的属性
message –> error msg 错误信息
String message() default "{com.acme.constraint.MyConstraint.message}";
groups –> 用来控制执行的顺序,或者执行部分验证
Class<?>[] groups() default {};
测试
@NotNull(groups = G1.class) String code; @NotNull(groups = G2.class) String name; --如果validator.validate(s, G2.class); 只会验证name不能为可供
payload –> 用来控制关联
Class<? extends Payload>[] payload() default {};
接口 ConstraintValidator
所有约束的实现逻辑需要继承的接口
public interface ConstraintValidator<A extends Annotation, T> {
void initialize(A constraintAnnotation);
boolean isValid(T value, ConstraintValidatorContext context);
}
isValid()方法,表示是否验证通过,其中参数ConstraintValidatorContext 是一个接口
如@NotNull 的验证逻辑
public class NotNullValidator implements ConstraintValidator<NotNull, Object> {
public void initialize(NotNull parameters) {
}
public boolean isValid(Object object, ConstraintValidatorContext constraintValidatorContext) {
return object != null;
}
}
接口 ConstraintValidatorContext
该接口为 ‘isValid()方法’ 提供上下文信息
ConstraintValidatorFactory
该接口用来生成具体的验证实现类工厂
JavaBean如何用注解来描述约定
- 3.1 ‘约束’ 可以定义到接口及父类,实现类受影响
- 3.2 ‘约束’ 可以定义到属性及方法上
- 3.3 ‘约束’ 可以应用到 数组及集合上
编程中如何使用’约束’来验证JavaBean
例子:
1
2
3
4ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
Student s = new Student();
Set<ConstraintViolation<Object>> validateSet = validator.validate(s);分析
- 当前所以的API 全是validation 提供的类,在普通开发者眼中,不知道具体的实现是什么,这就是面向接口编程
- Validation.buildDefaultValidatorFactory(); 创建一个验证工厂,是整个系统的入口,其实现内部细节如下
- 先找到通过java spi 实现接口的具体类 ValidationProvider –> HibernateValidator
- 通过对ValidationProvider.createGenericConfiguration(BootstrapState state);是面向接口的编程,其实现为,HibernateValidator. createGenericConfiguration() 然后将具体的配置对象ConfigurationImpl 返回给主流程中
- 面向接口Configuration 进行调用buildValidatorFactory()方法,其实实现为由ConfigurationImpl. buildValidatorFactory() 完成了Factory 的具体实现
- 获取到ValidatorFactory 然后调用factory.getValidator();,获取具体的Validator—> ValidatorImpl
- 最后调用validator.validate()验证对象
阅读中遇到的问题摘要
Java spi 技术规划
- javax.validation.spi.ValidationProvider 定义接口 ,在各大厂商进行不同实现时,各大厂商的jar包下 /META-INF/service/javax.validation.spi.ValidationProvider 的文件中,写上具体的实现
- 在获取具体实现的时候,使用ServiceLoader.load 加载ServerLoader
1
2
3
ServiceLoader<ValidationProvider> loader = ServiceLoader.load( ValidationProvider.class, classloader );
Iterator<ValidationProvider> providerIterator = loader.iterator();
List<ValidationProvider<?>> validationProviderList = new ArrayList<ValidationProvider<?>>();
另1
java.util.Collections.unmodifiableSet()方法的声明。
public static <T> boolean addAll(Collection<? super T> c, T.. a)
在方法调用返回指定set的不可修改视图。
test
package com.yiibai;
import java.util.*;
public class CollectionsDemo {
public static void main(String[] s) {
// create set
Set<String> set = new HashSet<String>();
// populate the set
set.add("Welcome");
set.add("to");
set.add("TP");
System.out.println("Initial set value: "+set);
// create unmodifiable set
Set unmodset = Collections.unmodifiableSet(set);
// try to modify the set
unmodset.add("Hello");
}
}
现在编译和运行上面的代码示例,将产生以下结果。
Initial set value: [to, Welcome, TP]
Exception in thread "main" java.lang.UnsupportedOperationException
另2
Class.cast() 源码
public T cast(Object obj) {
if (obj != null && !isInstance(obj))
throw new ClassCastException();
return (T) obj;
}
很明显, 这个方法只是简单的进行了强制转换, 字符类型强制转换成Double肯定是错误的.
另3 ResourceBundle 依据locale来读取properties文件,实现国际化
ResourceBundle rb = ResourceBundle.getBundle("fileName");
//默认会读取fileName_zh_CN.properties 的文件
Locale locale = new Locale("en", "US");
ResourceBundle rb1 = ResourceBundle.getBundle("fileName", locale);
//默认会读取fileName_en_US.properties 的文件
validation-api 文档结构
+javax.validation
+++bootstrap ##基础引导程序
+++constraints ##提供的注解
+++constraintvalidation ##约束验证
+++executable ##可执行的
+++groups ##组
+++metadata ##元数据
+++spi ##spi接口
java.lang.reflect.Constructor 构造器类
--获取到class
Class clazz = Class.forName("org.pt.jsr.bean.validation.Student");
--获取到class所有的构造方法
Constructor[] c = clazz.getConstructors();
另 jpa
- JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。
- Sun引入新的JPA ORM规范出于两个原因:其一,简化现有Java EE和Java SE应用开发工作;其二,Sun希望整合ORM技术,实现天下归一。
另 java.lang.Void
原以为Void类为void类的包装类,但是查看Void类的
源码后发现并不是如此,Void类的源码如下:
/**
* The {@code Void} class is an uninstantiable placeholder class to hold a
* reference to the {@code Class} object representing the Java keyword
* void.
* Void类是一个不可实例化的占位符类,它持有对标识Java关键字void的Class对象的引用。
并且本身的构造函数为private
* @author unascribed
* @since JDK1.1
*/
public final class Void {
/**
* The {@code Class} object representing the pseudo-type corresponding to
* the keyword {@code void}.
*/
@SuppressWarnings("unchecked")
public static final Class<Void> TYPE = (Class<Void>) Class.getPrimitiveClass("void");
/*
* The Void class cannot be instantiated.
*/
private Void() {}
}
枚举容器
EnumMap从名字我们可以看出这个Map是给枚举类用的。它的key为枚举元素,value自定义。在工作中我们也可以用其他的Map来实现我们关于枚举的需求,但是为什么要用这个EnumMap呢?因为它的性能高
EnumSet这是一个用来操作Enum的集合,是一个抽象类,它有两个继承类:JumboEnumSet和RegularEnumSet。在使用的时候,需要制定枚举类型。它的特点也是速度非常快,为什么速度很快呢?因为每次add的时候,每个枚举值只占一个长整型的一位。
JSR
- JSR是Java Specification Requests的缩写,意思是Java 规范提案。是指向JCP(Java Community Process)提出新增一个标准化技术规范的正式请求。任何人都可以提交JSR,以向Java平台增添新的API和服务。JSR已成为Java界的一个重要标准。
- JSR
常用的标准
- 从Spring 3.0开始,Spring开始支持JSR-330标准的注解(依赖注入)。这些注解和Spring注解扫描的方式是一致的
- JSR 303 - Bean Validation (Hibernate Validator)
- Java API for RESTful Web Services (JAX-RS) 1.1 (JSR 311)
- Common Annotations for the Java Platform 1.1 (JSR 250)
- JSR 370: JavaTM API for RESTful Web Services (JAX-RS 2.1) Specification