В моем приложении Spring, созданном с помощью Kotlin, я хотел бы использовать проверку bean-компонентов для класса данных, который выглядит следующим образом.
data class CustomerDto(
@field: NotBlank
val firstName: String,
@field: NotBlank
val lastName: String)
При отправке сообщения с пустым firstName в конечную точку клиента я хотел бы получить проверки ограничений, но из-за того, что поля не допускают нулевые значения, я не получаю проверки, а скорее получаю следующую ошибку.
"status": 400,
"error": "Bad Request",
"message": "JSON parse error: Instantiation of [simple type, class pkg.CustomerDto] value failed for JSON property firstName due to missing (therefore NULL) value for creator parameter firstName which is a non-nullable type; nested exception is com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class pkg.CustomerDto] value failed for JSON property firstName due to missing (therefore NULL) value for creator parameter firstName which is a non-nullable type\n at [Source: (PushbackInputStream); line: 19, column: 1] (through reference chain: pkg.CustomerDto[\"firstName\"])",
"path": "/shop/5/customer"
Есть ли другой вариант, чтобы пометить поле dto как необязательное и по-прежнему получать нарушения ограничений? Когда я помечаю их как необязательные, я должен использовать !! в полях кода, не допускающих значения NULL, при сопоставлении их с моими сущностями.
Спасибо.
Нет, у меня нет хорошего решения, кроме как сделать все необязательным или использовать !! при сопоставлении с моими объектами полагаться на нулевую безопасность в моей модели. Я был бы заинтересован в решении Spring, которое вы имели в виду.
После небольшого поиска, я думаю, это может быть немного сложнее, чем я думал в первую очередь, однако, возможно. Вопрос в том, оправдывают ли подходы те усилия, которые вам необходимо приложить. Во-первых, следует использовать Spring AOP, второй HandlerInterceptors, который позволяет вам получать доступ и изменять запрос до того, как Джексон десериализует полезную нагрузку запроса в ваш CustomerDTO. Это определенно непростое решение, взгляните на этот вопрос: stackoverflow.com/questions/50932518/…




Я считаю, что вы идете неверным путем.
Точная цель нулевых операторов безопасности Kotlin - заставить вас явно выражать поведение нулевого значения в вашем коде, чтобы резко минимизировать NPE или, по крайней мере, убедиться, что вы сознательно вызвали их сами :). В вашем (или любом другом MVC-подобном шаблоне доступа) случае вы сталкиваетесь со следующим сценарием
Хотя это имеет смысл с точки зрения логического потока, на самом деле это нарушение, которое может привести к NPE, потому что ничто в модели / контракте не гарантирует, что эти поля не будут нулевыми.
Тем не менее, в java вы бы просто сделали это последнее предположение, используя геттер (вы бы все равно использовали геттер, это java, верно?).
Что ж - в котлине ничего не изменилось, если это то, что вам нужно:
data class CustomerDto(@field:NotNull
@JsonProperty("firstName") private val _firstName: String? = null,
@field:NotNull
@JsonProperty("lastName") private val _lastName: String? = null) {
val firstName get() = _firstName!!
val lastName get() = _lastName!!
}
(В этом примере предполагается, что вы используете jackson для де / сериализации JSON)
Хотя вы все еще вручную форсируете недопустимость обнуления с помощью оператора !! (чего вы хотели избежать), теперь вы абстрагируете этот аспект от остальной части своей кодовой базы, получая поведение, подобное java-getter.
Вы описываете проблему, но мне было интересно, есть ли способ сделать аннотацию @NotNull в Kotlin ненулевым полем. Я все еще думаю, что этого можно достичь, если Spring сначала выполнит проверку, а затем отобразит целевой класс, как то, что описывает @Matt, но с поддержкой фреймворка.
Я понимаю вашу проблему, но я также считаю, что макет класса данных, который я предложил, решает эту проблему способом "kotlin", потому что он позволяет вам пользоваться как нулевой безопасностью kotlin, так и проверкой Spring (вы все равно можете аннотировать поля DTO) при абстрагировании первый из остальной части вашего приложения и сохраняя его как соображение при проектировании внутреннего класса данных. Я не понимаю, как этого недостаточно.
field: JsonProperty необходимо использовать, чтобы распознать аннотацию для поля. Получатель должен иметь аннотацию get: JsonIgnore, чтобы Джексон не использовал получатель для идентификации. Если он идентифицирует и вызывает метод получения, когда скрытое значение равно нулю, это приведет к исключению JsonProcessingException из-за NPE. Далее, даже при этом, в случае ошибки проверки, в ответе spring будет отображаться имя поля вместо свойства json. Это описано в этом вопросе: stackoverflow.com/questions/41717866/…
Я думаю, что лучшим решением будет использовать значение Kotlin по умолчанию внутри свойств:
data class CustomerDto(
@field: NotBlank
val firstName: String = "",
@field: NotBlank
val lastName: String = "")
Атрибуты имени и фамилии всегда будут иметь значение (из json или значение по умолчанию = ""). Решение не идеальное, но работает так, как ожидалось.
Имейте в виду, что это значение по умолчанию помогает только в том случае, если свойство отсутствует в json, например, в { "firstName": "Name" }. Но он все равно выдает исключение, если json явно определяет свойство как null, например, { "firstName": "Name", "lastName": null }
Хороший вопрос, возможно, тишина здесь подтверждает мое впечатление. Imo нет никакого способа, поскольку успешное построение объекта является предпосылкой для проверки поля. Тем не менее, я хотел бы прочитать мнение чемпиона Котлина. У меня есть для этого решение, связанное с Spring, но я думаю, вы хотите решить его по-Kotlin?