home wiki.fukuchiharuki.me
Menu

#author("2018-02-13T08:44:09+00:00","default:haruki","haruki")
#author("2018-02-14T06:29:03+00:00","default:haruki","haruki")
* キーワード [#q4d4b888]
- Spring Boot
- Validation/Validator
- Kotlin

* したいこと [#c3687675]

Kotlinでカスタム・バリデータを作成したい。

Javaでやるのと同じようにすればいいんだけど、Kotlinの文法的にちょっと躓いたのでメモ。

* どうやって [#ya594da9]

相関チェック:時間入力の前後チェックをしたいとして。

** Period.kt [#nebf5963]

 package me.fukuchiharuki.example.validation.constraints
 
 import me.fukuchiharuki.example.validation.PeriodValidator
 import javax.validation.Constraint
 import javax.validation.Payload
 import kotlin.reflect.KClass
 
 @Target(AnnotationTarget.CLASS, AnnotationTarget.FIELD, AnnotationTarget.ANNOTATION_CLASS)
 @Retention(AnnotationRetention.RUNTIME)
 @Constraint(validatedBy = [PeriodValidator::class])
 annotation class Period(
 
         val message: String = "{me.fukuchiharuki.example.validation.constraints.Period}",
         val groups: Array<KClass<*>> = [],
         val payload: Array<KClass<out Payload>> = [],
 
         val startField: String = "start",
         val endField: String = "end"
 
 )

** PeriodValidator.kt [#nbaf5664]

 package me.fukuchiharuki.example.validation
 
 import me.fukuchiharuki.example.validation.constraints.Period
 import org.springframework.beans.BeanWrapperImpl
 import java.time.LocalTime
 import javax.validation.ConstraintValidator
 import javax.validation.ConstraintValidatorContext
 
 class PeriodValidator: ConstraintValidator<Period, Object> {
 class PeriodValidator: ConstraintValidator<Period, Any> {
 
     private var message: String = ""
     private var startField: String = ""
     private var endField: String = ""
 
     override fun initialize(constraintAnnotation: Period?) {
         if (constraintAnnotation === null) return
         message = constraintAnnotation.message
         startField = constraintAnnotation.startField
         endField = constraintAnnotation.endField
     }
 
     override fun isValid(value: Object?, context: ConstraintValidatorContext?): Boolean {
     override fun isValid(value: Any?, context: ConstraintValidatorContext?): Boolean {
         val beanWrapper = BeanWrapperImpl(value)
         val startTimeInput = beanWrapper.getPropertyValue(startField).toString()
         val endTimeInput = beanWrapper.getPropertyValue(endField).toString()
         if (チェックする(startTimeInput, endTimeInput)) return true
         setContext(context!!)
         return false
     }
 
     private fun setContext(context: ConstraintValidatorContext) {
         context.disableDefaultConstraintViolation()
         context.buildConstraintViolationWithTemplate(message)
                 .addPropertyNode(endField)
                 .addConstraintViolation()
     }
 
 }


* ちなみに [#jd4a3d1e]

constraints.Periodはネストした子側のクラスのアノテーションにすることも、ネストした親側のプロパティのアノテーションにすることもできる。

- 子側のクラスのアノテーションにする場合
-- 親側のプロパティのアノテーションには次を書いて
 @field: Valid
-- 子側のクラスのアノテーションに次を書く
 @constraints.Period
- 親側のプロパティのアノテーションにする場合
-- 親側のプロパティのアノテーションに次を書く
 @constraints.Period

親側のプロパティのアノテーションに書く場合、「@field:」が要らないのね、なんで?

- Object でなくて Any を使う

* 参考 [#m6aa34bc]
- [[Spring Boot 入力チェック - NOTEです>http://ziqoo.com/wiki/index.php?Spring%20Boot%20%C6%FE%CE%CF%A5%C1%A5%A7%A5%C3%A5%AF]]