Java Bean Annotation Constraint Validation 未完待續

殷老實發表於2017-07-17

邊學邊用,有問題歡迎指出。


Chapter 1. 簡單的 Annotation Constraint 的使用

package tutorial.chapter01;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Car {
	
	@NotNull
	private String manufacturer;
	
	@NotNull
	@Size(min = 2, max = 14)
	private String licensePlate;
	
	@Min(2)
	private int seatCount;
	
	
	public Car(String manufacturer, String licencePlate, int seatCount) {
		this.manufacturer = manufacturer;
		this.licensePlate = licencePlate;
		this.seatCount = seatCount;
	}
}

以上的程式碼片段,我們應用annotation 來限制 

1.  `manufacturer`不為 null

2. `licensePlate` string的長度在 2-14之間

3. ·seaCount· 的值最小為2


使用一下程式碼片段來檢驗

package tutorial.chapter01;

import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class CarTest {
	private static Validator validator;
	
	@BeforeClass
    public static void setUp() {
        ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
        validator = factory.getValidator();
    }

    @Test
    public void manufacturerIsNull() {
        Car car = new Car( null, "DD-AB-123", 4 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );
	//這裡我們故意將manufacture 設成 null, 其他項是正確的,我們將返回一個相對應的violation
        assertEquals( 1, constraintViolations.size() );
        assertEquals( "may not be null", constraintViolations.iterator().next().getMessage() );
    }

    @Test
    public void licensePlateTooShort() {
        Car car = new Car( "Morris", "D", 4 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );

        assertEquals( 1, constraintViolations.size() );
        assertEquals(
                "size must be between 2 and 14",
                constraintViolations.iterator().next().getMessage()
        );
    }

    @Test
    public void seatCountTooLow() {
        Car car = new Car( "Morris", "DD-AB-123", 1 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );

        assertEquals( 1, constraintViolations.size() );
        assertEquals(
                "must be greater than or equal to 2",
                constraintViolations.iterator().next().getMessage()
        );
    }

    @Test
    public void carIsValid() {
        Car car = new Car( "Morris", "DD-AB-123", 2 );

        Set<ConstraintViolation<Car>> constraintViolations =
                validator.validate( car );

        assertEquals( 0, constraintViolations.size() );
    }
}

當我們使用 annotation的時候, 編譯並執行的時候並不會給我們的限制進行檢驗,想要檢驗我們的變數是否滿足我們的annotation的限制的時候我們需要使用`ValidatorFactory` 來建立一個 Validator instance. Validator.validate() 方法將會返回 a set of ConstraintViolation.  我們就可以通過觀察 這個set來看看我們哪個 變數不符合限制。


Chapter 2. 


不同等級的 annotation 

a. 變數級別 :從以下程式碼片段可以看出,我們對class 的變數使用了annotation。這個chapter 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...
}


b. 方法級別: 以下 的作用和以上是一樣的,因為當我們 對方法進行限制的時候我們實際上是對它的 返回型別進行限制。

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;
    }
}

c. class 級別: 這個是對整個的類的內容進行限制,需要我們自己根據需求進行定製。 以後會提到,先從基礎來。


d. 因為不同級別的annotation,我們就會問那夫類和子類之間的繼承或者介面是怎麼處理的。很好的問題,其實也很簡單,那就是無論是繼承還是實現我們都會原封不動的接受得到的限制。但是! 接收到的限制不一定會表達,例如以下的例子。 如果我們把 @Valid 註釋掉,然後我門對Car 進行 validate, 那麼 Person 類是不會被 validate的。要想在validate Car的時候也Validate person那我們需要加上@Valid annotation. 


package org.hibernate.validator.referenceguide.chapter02.objectgraph;

public class Car {

    @NotNull
    //@Valid
    private Person driver;

    //...
}

package org.hibernate.validator.referenceguide.chapter02.objectgraph;

public class Person {

    @NotNull
    private String name;

    //...
}


@Valid的作用簡單來說就是繼續validate 被@Valid 標記的變臉內部的變臉

e.g. 這樣的話我們僅僅validate來list是否是 null

@NotNull
List<Person> list;

加上valid 才會繼續去validate person內部。

@NotNull
@Valid
List<Person> list;

e. 當得到 constraint violation 之後我門如何通過 ConstraintViolation 的instance來找到我門的violation.

Java Doc - ConstraintViolation 這裡是他的方法。我就拿其中一個我覺的有點意思的舉個例子. 考慮以下程式碼,當我們例項化一個valid 的car和person 但是 personname 的age是錯的。那當我們得到constraintviolation怎麼知道personname的路徑在哪裡呢? 使用: 

gePropertyPath()

結果是 

driver.personName.age

Class Car {
  @NotNull
  @Valid
  Person person;
  //.....
}

Class  Person {
  @NotNull
  @Valid
  PersonName personName;
  //...
}

Class PersonName {
  @Min(18)
  int age;
}

Chapter 03: 方法的parameter 和 return value 的constraint

這章總結來看,主要介紹瞭如何給一個方法的paramter 和 return value進行constraint validate. 



相關文章