payloadの指定

【前提条件】

[環境]
[参考資料]

Bean Validation1.1仕様書
The Java Community Process(SM) Program - communityprocess - final

[その他]

Validatorの生成はCDIを利用しています。

コンテキストパスは「Sample」、ApplicationPathは「/service」

【概要】

今回はValidatorのAPIにあるpayloadについてです。

payloadはチェックにカテゴリ情報を付加するためのAPIです。

【Payload】

Payloadを指定するためには
javax.validation.Payloadを実装する必要があります。

Payloadにはメソッドは定義されていないため、
目印のためのインターフェイスとなります。

import javax.validation.Payload;

public class Category {
    public static class Name implements Payload{};
    public static class Address implements Payload{};
}

サンプルではカテゴリの用途で使用します。
NameとAddressがPayloadを実装しています。

【Bean】

import javax.validation.constraints.Size;
import javax.ws.rs.FormParam;
import jp.glory.sample04.payload.Category;

public class PayloadBean {

    @Size(min = 10, payload = { Category.Name.class })
    @FormParam("firstName")
    private String firstName = null;

    @Size(min = 10, payload = { Category.Name.class })
    @FormParam("lastName")
    private String lastName = null;
    
    @Size(min = 10, payload = { Category.Address.class })
    @FormParam("zipCode")
    private String zipCode = null;
    
    @Size(min = 10, payload = { Category.Address.class })
    @FormParam("address")
    private String address = null;
    
    @Size(min = 10)
    @FormParam("note")
    private String note = null;

    // アクセサメソッドは省略
}

各チェック用のアノテーションにはpayload属性があるので、
先ほど作成したNameとAddressを配列の形で指定します。

payloadに指定できるのはClassです。

【チェック結果からの取得】

アノテーションで指定したpayloadは
入力チェック結果のオブジェクトに付与されます。

    final Set<ConstraintViolation<PayloadBean>> validateResult =  validator.validate(bean);

    for (final ConstraintViolation<PayloadBean> result : validateResult) {
            
        final ConstraintDescriptor descriptor = result.getConstraintDescriptor();
        final Set<Class> payloads = descriptor.getPayload();
    }

チェック結果からpayloadを取得するためには
javax.validation.metadata.ConstraintDescriptorを経由して取得します。

ConstraintDescriptor#getPayloadでClassのSetで返却されます。
payloadに何も指定しなかった場合、空のSetが返却されます。

【サンプル】

先ほどの書いたPayloadBeanを使って、
チェック結果でカテゴリを出力するサンプルを作成します。

import java.text.ParseException;
import java.util.Set;
import javax.inject.Inject;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.metadata.ConstraintDescriptor;
import javax.ws.rs.BeanParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import jp.glory.sample04.bean.PayloadBean;

@Path("sample04")
public class PayloadSampleResource {
    
    @Inject
    private Validator validator = null;
    
    @POST
    public Response postRequest(@BeanParam final PayloadBean bean) throws ParseException {

        final Set<ConstraintViolation<PayloadBean>> result =  validator.validate(bean);

        if (result.isEmpty()) {

            return createSuccessResponse();
        }

        return createErrorResponse(result);
    }

    private Response createErrorResponse(final Set <ConstraintViolation<PayloadBean>> validateResult) {
        
        final StringBuilder builder = new StringBuilder();
        
        builder.append("<html>");
        builder.append("<head>");
        builder.append("<meta charset=\"utf-8\">");
        builder.append("<title>Validation</title>");
        builder.append("</head>");
        builder.append("<body>");

        for (final ConstraintViolation<PayloadBean> result : validateResult) {
            
            final ConstraintDescriptor descriptor = result.getConstraintDescriptor();
            final Set<Class> payloads = descriptor.getPayload();
            
            builder.append("<div>");

            for (final Class payload : payloads) {
                builder.append(payload.getSimpleName());
            }

            builder.append(" : ");
            builder.append(result.getPropertyPath().toString());
            builder.append(" : ");
            builder.append(result.getInvalidValue());
            builder.append(" : ");
            builder.append(result.getMessage());
            builder.append("</div>");
        }

        builder.append("</body>");
        builder.append("</html>");
     
        return Response.ok(builder.toString()).build();
    }

    private Response createSuccessResponse() {
        
        final StringBuilder builder = new StringBuilder();
        
        builder.append("<html>");
        builder.append("<head>");
        builder.append("<meta charset=\"utf-8\">");
        builder.append("<title>Validation</title>");
        builder.append("</head>");
        builder.append("<body>");
        builder.append("<div>Input value is valid!</div>");
        builder.append("</body>");
        builder.append("</html>");
     
        return Response.ok(builder.toString()).build();
    }
}
<!DOCTYPE html>
<html>
    <head>
        <title>Payload Validation</title>
        <meta charset="UTF-8" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <style type="text/css">
            p.label {
                background: #00ffff;
                font-weight: bold;
            }
        </style>
    </head>
    <body>
        <form method="POST" id="validateForm" action="./service/sample04" >
            <p class="label">Category : Name</p>
            <div>
                <span>First Name : </span>
                <input type="text" name="firstName" value="" />
            </div>
            <div>
                <span>Last Name : </span>
                <input type="text" name="lastName" value="" />
            </div>
            <p class="label">Category : Address</p>
            <div>
                <span>Zip Code : </span>
                <input type="text" name="zipCode" value="" />
            </div>
            <div>
                <span>Address : </span>
                <input type="text" name="address" value="" />
            </div>
            <p class="label">Category : None</p>
            <div>
                <span>Note : </span>
                <input type="text" name="note" value="" />
            </div>
            <div>
                <input type="submit" value="送信" />
            </div>
        </form>
    </body>
</html>

【まとめ】

サンプルではpayloadをNameとAddressにカテゴライズして使用しました。

Bean Validationの仕様書でも
エラー内容の優先度(Info、Error)として使用していたので、
カテゴライズとして使うのがかなり有効なようです。