проверка bean не работает с kotlin (JSR 380) - PullRequest
0 голосов
/ 15 сентября 2018

Поэтому, во-первых, я не мог придумать лучшего названия для этого вопроса, поэтому я открыт для изменений.

Я пытаюсь проверить компонент с помощью механизма проверки компонентов (JSR-380) свесенняя загрузка.

Итак, у меня есть такой контроллер:

@Controller
@RequestMapping("/users")
class UserController {
    @PostMapping
    fun createUser(@Validated user: User, bindingResult: BindingResult): ModelAndView {
        return ModelAndView("someview", "user", user)
    }
}

с классом User, написанным на kotlin:

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[]"))
}

Недопустимые роли сопоставлены с нулем.

Как вы видите, я хочу, чтобы roles содержал хотя бы один элемент, ни один из которых не былноль.Однако при тестировании приведенного выше кода об ошибках привязки не сообщается, если roles содержит нулевые значения.Это действительно сообщает об ошибке, если набор пуст.Я думал, что это может быть проблемой с тем, как код kotlin компилируется, поскольку тот же самый код прекрасно работает, когда класс User написан на Java.Например:

@Data // just lombok...
public class User {
    @NotEmpty
    private Set<@NotNull Role> roles = new HashSet<>();
}

Тот же контроллер, тот же тест.

После проверки байт-кода я заметил, что версия kotlin не включает вложенную аннотацию @NotNull (см. Ниже).

Java:

private Ljava/util/Set; roles
@Ljavax/validation/constraints/NotEmpty;()
@Ljavax/validation/constraints/NotNull;() : FIELD, 0;
@Ljavax/validation/constraints/NotEmpty;() : FIELD, null

Kotlin:

private Ljava/util/Set; roles
@Ljavax/validation/constraints/NotEmpty;()
@Lorg/jetbrains/annotations/NotNull;() // added because roles is not nullable in kotlin

Теперь вопрос почему?

Вот пример проекта на случай, если вы захотите что-нибудь попробовать.

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

Ответ

Кажется, сейчас проблема с kotlin.Обратитесь к KT-27049 для получения дополнительной информации.


Обходной путь

Рафаль Г. уже указал, что мы можем использовать пользовательский валидаторкак обходной путь.Итак, вот некоторый код:

Аннотация:

import javax.validation.Constraint
import javax.validation.Payload
import kotlin.annotation.AnnotationTarget.*
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>> = []
)

ConstraintValidator:

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 }
    }
}

И, наконец, обновленный класс User:

data class User(
    @field:NotEmpty
    @field:NoNullElements
    var roles: MutableSet<Role> = HashSet()
)

Хотя проверка теперь работает, результирующее ConstrainViolation немного отличается.Например, elementType и propertyPath отличаются, как вы можете видеть ниже.

Java:

The Java Version

Kotlin:

The Kotlin Version

Источник доступен здесь: https://gitlab.com/darkatra/jsr380-kotlin-issue/tree/workaround

Еще раз спасибо за вашу помощь Рафаль Г.

0 голосов
/ 25 сентября 2018

Попробуйте добавить ? следующим образом:

data class User(
    @field:Valid
    @field:NotEmpty
    var roles: MutableSet<@NotNull Role?> = HashSet()
)

Тогда компилятор kotlin должен понимать, что роли могут быть null, и это может удовлетворить проверку, я мало знаю о JSR380, так что я простохотя догадываюсь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...