↓の続きです。
wrongwrong163377.hatenablog.com
記事執筆時点でのプロジェクトリポジトリは以下。
github.com
やること
フィールド用に名前が半角スペースで2分割できるかをチェックするCustom Validatorを作ります。
深い理解ができていないので、作って動かす程度の内容です。
Custom Validatorを作る上で必要な作業は以下の3つです。
- アノテーションクラスを用意する
- バリデーターを作る
- 付与して使う
アノテーションクラスを用意する
アノテーションクラスは、Javaでいう@interface
です。
早速ですが、完成したアノテーションクラスは以下の通りです。
@Target(AnnotationTarget.FIELD) @Retention(AnnotationRetention.RUNTIME) @MustBeDocumented @ReportAsSingleViolation @Constraint(validatedBy = [CanSplitBySpaceValidator::class]) annotation class CanSplitBySpace( val message: String = "message", val groups: Array<KClass<out Any>> = [], val payload: Array<KClass<out Payload>> = [] )
バリデーターを作る
こちらはJavaの内容とほぼ変わりません。
class CanSplitBySpaceValidator: ConstraintValidator<CanSplitBySpace, String>{ override fun initialize(constraintAnnotation: CanSplitBySpace) {} override fun isValid(value: String?, context: ConstraintValidatorContext?): Boolean { //nullなら何もしない if(value == null) return true //スペースで2分割できなければいけない return value.split(" ").size == 2 } }
ConstraintValidator
に指定しているのは、作成したアノテーションと、アノテーションが処理する対象のクラスです。
ここまでを合わせて
作成したアノテーションとバリデーターは以下の通りです。
import javax.validation.* import kotlin.reflect.KClass //アノテーション @Target(AnnotationTarget.FIELD) @Retention(AnnotationRetention.RUNTIME) @MustBeDocumented @ReportAsSingleViolation @Constraint(validatedBy = [CanSplitBySpaceValidator::class]) annotation class CanSplitBySpace( val message: String = "message", val groups: Array<KClass<out Any>> = [], val payload: Array<KClass<out Payload>> = [] ) //バリデーター本体 class CanSplitBySpaceValidator: ConstraintValidator<CanSplitBySpace, String>{ override fun initialize(constraintAnnotation: CanSplitBySpace) {} override fun isValid(value: String?, context: ConstraintValidatorContext?): Boolean { //nullなら何もしない if(value == null) return true //スペースで2分割できなければいけない return value.split(" ").size == 2 } }
付与して使う
前述の通り、field:
を付ける必要はありません(付けても問題なく動きます)。
//import com.wrongwrong.modeltest.annotation.CanSplitBySpace インポート import java.util.* import javax.validation.constraints.AssertTrue import javax.validation.constraints.NotNull data class MyModel( @field:NotNull(message = "idはnull不許可") val id: Long?, @CanSplitBySpace(message = "名前が半角スペースで2つに分割できない") 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, "name":"wrongwrong", "create":"2018-11-01", "update":"2018-11-02"}' localhost:8080/my [Field error in object 'myModel' on field 'name': rejected value [wrongwrong]; codes [CanSplitBySpace.myModel.name,CanSplitBySpace.name,CanSplitBySpace.java.lang.String,CanSplitBySpace]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myModel.name,name]; arguments []; default message [name]]; default message [名前が半角スペースで2つに分割できない]]
$ 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)