kotlin에서는 콩 검증이 동작하지 않습니다(JSR 380).
그래서 우선 이 질문에 대한 더 좋은 제목이 생각나지 않아서 변화를 받아들일 수 있습니다.
spring boot에 bean validation mechanism(JSR-380)을 사용하여 bean을 검증하려고 합니다.
이런 컨트롤러가 있어요
@Controller
@RequestMapping("/users")
class UserController {
@PostMapping
fun createUser(@Valid user: User, bindingResult: BindingResult): ModelAndView {
return ModelAndView("someview", "user", user)
}
}
사용자 클래스는 코틀린으로 기술되어 있습니다.
data class User(
@field:NotEmpty
var roles: MutableSet<@NotNull Role> = HashSet()
)
그리고 이것이 테스트입니다.
@Test
internal fun shouldNotCreateNewTestWithInvalidParams() {
mockMvc.perform(post("/users")
.param("roles", "invalid role"))
.andExpect(model().attributeHasFieldErrors("user", "roles[]"))
}
잘못된 역할이 null에 매핑되었습니다.
보다시피 나는 원한다.roles
항목이 null이 아닌 항목을 하나 이상 포함해야 합니다.그러나 위의 코드를 테스트할 때 다음과 같은 경우 바인딩 오류가 보고되지 않습니다.roles
에는 늘 값이 포함되어 있습니다.다만, 세트가 비어 있는 경우는 에러가 보고됩니다.User 클래스가 Java로 작성되어 있을 때, 같은 코드로 Kotlin 코드가 컴파일 되는 것이 문제인 것 같습니다.다음과 같이 합니다.
@Data // just lombok...
public class User {
@NotEmpty
private Set<@NotNull Role> roles = new HashSet<>();
}
같은 컨트롤러, 같은 테스트.
바이트 코드를 확인한 결과 kotlin 버전에 nested가 포함되어 있지 않습니다.@NotNull
주석(아래 참조).
자바:
private Ljava/util/Set; roles
@Ljavax/validation/constraints/NotEmpty;()
@Ljavax/validation/constraints/NotNull;() : FIELD, 0;
@Ljavax/validation/constraints/NotEmpty;() : FIELD, null
코틀린:
private Ljava/util/Set; roles
@Ljavax/validation/constraints/NotEmpty;()
@Lorg/jetbrains/annotations/NotNull;() // added because roles is not nullable in kotlin. this does not affect validation
이제 질문은 왜일까?
여기 당신이 무언가를 시도하고 싶을 때를 대비한 샘플 프로젝트가 있습니다.
답변(Kotlin 1.3.70)
kotlin 코드를 jvm target 1.8 이상으로 컴파일하고,-Xemit-jvm-type-annotations
를 참조해 주세요.
Spring Boot 프로젝트의 경우 다음 변경만 수행하면 됩니다(Spring Boot 2.3.3 및 Kotlin 1.4.0에서 테스트 완료).
- 폼 세트에는 다음 속성이 있습니다.
<properties> <java.version>11</java.version> <kotlin.version>1.4.0</kotlin.version> </properties>
- 더하다
<arg>-Xemit-jvm-type-annotations</arg>
에게kotlin-maven-plugin
:<build> <plugin> <artifactId>kotlin-maven-plugin</artifactId> <groupId>org.jetbrains.kotlin</groupId> <configuration> <args> <arg>-Xjsr305=strict</arg> <arg>-Xemit-jvm-type-annotations</arg> </args> <compilerPlugins> <plugin>spring</plugin> </compilerPlugins> </configuration> <dependencies> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-maven-allopen</artifactId> <version>${kotlin.version}</version> </dependency> </dependencies> </plugin> </build>
회피책 (Kotlin 1.3.70 이전)
Rafal G.는 이미 이 문제를 해결하기 위해 커스텀 검증기를 사용할 수 있다고 지적했습니다.여기 몇 가지 코드가 있습니다.
주석:
import javax.validation.Constraint
import javax.validation.Payload
import kotlin.annotation.AnnotationTarget.ANNOTATION_CLASS
import kotlin.annotation.AnnotationTarget.CONSTRUCTOR
import kotlin.annotation.AnnotationTarget.FIELD
import kotlin.annotation.AnnotationTarget.FUNCTION
import kotlin.annotation.AnnotationTarget.TYPE_PARAMETER
import kotlin.annotation.AnnotationTarget.VALUE_PARAMETER
import kotlin.reflect.KClass
@MustBeDocumented
@Constraint(validatedBy = [NoNullElementsValidator::class])
@Target(allowedTargets = [FUNCTION, FIELD, ANNOTATION_CLASS, CONSTRUCTOR, VALUE_PARAMETER, TYPE_PARAMETER])
@Retention(AnnotationRetention.RUNTIME)
annotation class NoNullElements(
val message: String = "must not contain null elements",
val groups: Array<KClass<out Any>> = [],
val payload: Array<KClass<out Payload>> = []
)
Constraint Validator:
import javax.validation.ConstraintValidator
import javax.validation.ConstraintValidatorContext
class NoNullElementsValidator : ConstraintValidator<NoNullElements, Collection<Any>> {
override fun isValid(value: Collection<Any>?, context: ConstraintValidatorContext): Boolean {
// null values are valid
if (value == null) {
return true
}
return value.stream().noneMatch { it == null }
}
}
마지막으로 업데이트된 사용자 클래스:
data class User(
@field:NotEmpty
@field:NoNullElements
var roles: MutableSet<Role> = HashSet()
)
현재 검증이 실행되지만 결과적으로 발생하는 RestraintViolation은 약간 다릅니다.예를 들어,elementType
그리고.propertyPath
다음과 같이 다릅니다.
자바:
코틀린:
출처는, https://github.com/DarkAtra/jsr380-kotlin-issue/tree/workaround 에서 입수할 수 있습니다.
추가해 보다?
다음과 같습니다.
data class User(
@field:Valid
@field:NotEmpty
var roles: MutableSet<@NotNull Role?> = HashSet()
)
그러면 Kotlin 컴파일러는 역할이 다음과 같을 수 있다는 것을 깨달아야 합니다.null
인증을 받을 수 있을지도 모릅니다만, 저는 JSR380에 대해 잘 모르기 때문에 추측하고 있습니다.
저도 비슷한 문제가 있었어요.해결책은 다음과 같은 종속성을 추가하는 것이었습니다.
implementation "org.springframework.boot:spring-boot-starter-validation"
의존관계가 REST , 「REST」의 「REST」의 「REST」의 「REST」의 「REST」의 「REST」의 「REST」의 「REST」의 「REST」의 예외는 발생하지 않았습니다.javax.validation
콩의 제약이 충족되지 않았습니다. 던지다MethodArgumentNotValidException
.
언급URL : https://stackoverflow.com/questions/52345291/bean-validation-not-working-with-kotlin-jsr-380
'programing' 카테고리의 다른 글
식에 의한 그룹이 아닌 ORA-00979 (0) | 2023.02.15 |
---|---|
pymongo를 사용하여 mongodb에서 ObjectId로 검색 (0) | 2023.02.15 |
에러: 모듈 'node-sass'를 찾을 수 없습니다. (0) | 2023.02.11 |
워드프레스를 AWS lamda 함수로 배포하시겠습니까? (0) | 2023.02.11 |
WooCommerce - 수량 변경 시 총 가격 자동 업데이트 (0) | 2023.02.11 |