LoginSignup
15

More than 5 years have passed since last update.

【Kotlin】バリデーションの書き方の基礎【SpringBoot】

Last updated at Posted at 2018-12-04

この記事はMicroAd Advent Calendarの5日目の記事です。

TL;DR

Kotlinでバリデーションをやります。主に書くのは以下2点についてです。

  1. アノテーションを使ったバリデーション
  2. AssertTrueを使ったバリデーション

他の書き方もありますが、とりあえず自分が知っているのがこの2つなのでまとめます。
当初アノテーション自作まで書いてましたが、長くなりすぎたので分割し、7日目に回しました。

前書き

この記事は以下の記事を元に書いています。

コントローラー

コントローラーは以下を用います。
受け取ったmyModelに対してバリデーションを行い、引っかかればエラーを、引っかからなければpostした内容を返しています。

MyController.kt
import com.wrongwrong.modeltest.model.MyModel
import org.springframework.validation.BindingResult
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("my")
class MyController{

    @PostMapping
    fun myPostTest(
            @RequestBody @Validated myModel: MyModel,
            bindingResult: BindingResult
    ): String {
        //エラーがあればエラーを文字列にして返す
        if(bindingResult.hasErrors()){
            return bindingResult.allErrors.toString()
        }
        //受け取った内容を返却
        return "post:" + myModel.toString()
    }
}

エラーの無い状態で叩くと以下のようになります。

エラー無し
$ curl -X POST -H "Content-Type: application/json" -d '{"id":1, "name":"wrong wrong", "create":"2018-11-01", "update":"2018-11-02"}' localhost:8080/my
post:MyModel(id=1, name=wrong wrong, create=Thu Nov 01 09:00:00 JST 2018, update=Fri Nov 02 09:00:00 JST 2018)

モデル

今回バリデーションを行う上で、元にするモデルは以下です。
全てNullableとしなければ正常にバリデーションが行えないので、必ずNullableで宣言してください(説明は本題と外れるので省略します)。
バリデーションしたい内容はコメントの通りです。

MyModel.kt
import java.util.*

data class MyModel(
        // nullを禁止したい
        val id: Long?,
        // 名前がスペース区切りになっていることを確認したい
        val name: String?,
        // createはupdateと同じか過去にしたい
        val create: Date?,
        val update: Date?
)

アノテーションを使ったバリデーション

まずidのバリデーションを、アノテーションとして実装されたバリデーターを使ってやっていきます。
data classでは、@field:NotNullというようにアノテーションを付与します。
Javaではfield:無しでもバリデーションが行えますが、Data Classではこれを付けなければ正常にバリデーションができません。
アノテーションを付与すると以下のようになります。

MyModel.kt
import java.util.*
import javax.validation.constraints.NotNull

data class MyModel(
        @field:NotNull(message = "idはnull不許可")
        val id: Long?,
        // 名前がスペース区切りになっていることを確認したい
        val name: String?,
        // createはupdateと同じか過去にしたい
        val create: Date?,
        val update: Date?
)

この状態でエラー有り/無しをそれぞれCurlで叩いた結果が以下です。

エラー無し
$ curl -X POST -H "Content-Type: application/json" -d '{"id":1}' localhost:8080/my
post:MyModel(id=1, name=null, create=null, update=null)
エラー有り
$ curl -X POST -H "Content-Type: application/json" -d '{}' localhost:8080/my
[Field error in object 'myModel' on field 'id': rejected value [null]; codes [NotNull.myModel.id,NotNull.id,NotNull.java.lang.Long,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myModel.id,id]; arguments []; default message [id]]; default message [idはnull不許可]]

利用できるアノテーション

javax.validation.constraintsクラスや、org.hibernate.validator.constraintsクラスを見ておくと、既存で利用できるアノテーションは大体まとまっています。
javax.validation.constraints (Java(TM) EE 8 Specification APIs)
org.hibernate.validator.constraints (Hibernate Validator 5.1.3.Final)

AssertTrueを使ったバリデーション

次にcreateとupdateの相関チェックをやっていきます。
相関チェックはJavaと同様、@AssertTrue(または@AssertFalse)を付与したBool型の関数で行います。
今回は相関チェックにのみ利用していますが、アノテーションが用意されていないような単体チェックにも利用できます。
相関チェックを加えると以下のようになります。

MyModel.kt
import java.util.*
import javax.validation.constraints.AssertTrue
import javax.validation.constraints.NotNull

data class MyModel(
        @field:NotNull(message = "idはnull不許可")
        val id: Long?,
        // 名前がスペース区切りになっていることを確認したい
        val name: String?,
        val create: Date?,
        val update: Date?
) {
    @AssertTrue(message = "updateがcreateより過去")
    fun isLater(): Boolean {
        if(create == null || update == null) return true
        return create.before(update) || create == update
    }
}

この状態でエラー有り/無しをそれぞれCurlで叩いた結果が以下です。

エラー有り
curl -X POST -H "Content-Type: application/json" -d '{"id":1, "create":"2018-11-03", "update":"2018-11-02"}' localhost:8080/my
[Field error in object 'myModel' on field 'later': rejected value [false]; codes [AssertTrue.myModel.later,AssertTrue.later,AssertTrue.boolean,AssertTrue]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myModel.later,later]; arguments []; default message [later]]; default message [updateがcreateより過去]]

後書き

記事は7日目へ続きます。

参考にさせていただいた記事

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15