JSR303

简介:JSR 303 标准的定义,与官方的实现,源码的阅读,自定义实现

简介

JSR303 是java标准的一个验证bean的框架,本文主要用来记录对其使用及设计的各种剖析

‘约束’如何定义

@Constraint

  1. 所有验证注解的元注解
  2. 方法

    public Class<? extends ConstraintValidator<?, ?>>[] validatedBy();
    

    定义验证的具体逻辑实现类

如

    @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
    @Retention(RUNTIME)
    @Documented
    @Constraint(validatedBy = { }) //此处使用了元注解@Constraint
    public @interface NotNull {
        ...
    }

‘每个约束’ 必须定义的属性

  1. message –> error msg 错误信息

    String message() default "{com.acme.constraint.MyConstraint.message}";
    
  2. groups –> 用来控制执行的顺序,或者执行部分验证

    Class<?>[] groups() default {};
    

    测试

    @NotNull(groups = G1.class)
    String code;
    @NotNull(groups = G2.class)
    String name;
    
    --如果validator.validate(s, G2.class); 只会验证name不能为可供
    
  1. 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
    4
    ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    Validator validator = factory.getValidator();
    Student s = new Student();
    Set<ConstraintViolation<Object>> validateSet = validator.validate(s);
  • 分析

    1. 当前所以的API 全是validation 提供的类,在普通开发者眼中,不知道具体的实现是什么,这就是面向接口编程
    2. Validation.buildDefaultValidatorFactory(); 创建一个验证工厂,是整个系统的入口,其实现内部细节如下
      1. 先找到通过java spi 实现接口的具体类 ValidationProvider –> HibernateValidator
      2. 通过对ValidationProvider.createGenericConfiguration(BootstrapState state);是面向接口的编程,其实现为,HibernateValidator. createGenericConfiguration() 然后将具体的配置对象ConfigurationImpl 返回给主流程中
      3. 面向接口Configuration 进行调用buildValidatorFactory()方法,其实实现为由ConfigurationImpl. buildValidatorFactory() 完成了Factory 的具体实现
    3. 获取到ValidatorFactory 然后调用factory.getValidator();,获取具体的Validator—> ValidatorImpl
    4. 最后调用validator.validate()验证对象

阅读中遇到的问题摘要

Java spi 技术规划

  1. javax.validation.spi.ValidationProvider 定义接口 ,在各大厂商进行不同实现时,各大厂商的jar包下 /META-INF/service/javax.validation.spi.ValidationProvider 的文件中,写上具体的实现
  2. 在获取具体实现的时候,使用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