Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 514 Vote(s) - 3.47 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Kotlin Spring bean validation nullability

#1
In my Spring application that is built with Kotlin I would like to use bean validation on a data class that looks like this.

data class CustomerDto(
@field: NotBlank
val firstName: String,

@field: NotBlank
val lastName: String)

On sending a post with an empty firstName to the customer endpoint I would like to get the constraint validations but due to the fields not allowing null values I don't get the validations but rather get the following error.

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

Is there any other option to mark the dto field as not optional and still get the constraint violations? When I mark them as being optional I have to use the !! on the not nullable fields in the code when mapping them to my entities.

Thanks.
Reply

#2
I believe you are going at it the wrong way.

Kotlin's null safety operators exact purpose is to enforce you to explicitly express nullability behavior in your code in order to drastically minimize NPE, or at least make sure you knowingly caused them yourself :). In your (or any MVC like access pattern) case, you are faced with the following scenario

- Field might be null as part of the DTO payload
- Framework validation should disqualify the DTO if field is null.
- If framework validation has succeeded, the DTO field is **implicitly assumed to be not null**.

Though it makes sense in terms of logical flow, it's actually a violation that may result in an NPE, because nothing in the model/contract guarantees these fields won't be null

Still, In java, you'd have just made that final assumption using a getter(you'd have been using a getter anyway, it's java, right?).

Well - it's no different in kotlin, if that's what you require:

```kotlin
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!!
}
```
(This examples assumes you are using `jackson` for JSON de/serialization)

While still manually forcing non-nullability using the `!!` operator (which is something you wanted to avoid), you are now abstracting that aspect from the rest of your codebase, getting that java-getter like behavior
Reply

#3
I think a better solution is to use Kotlin's default value inside properties:

data class CustomerDto(
@field: NotBlank
val firstName: String="",

@field: NotBlank
val lastName: String="")

First name and last name attributes will always have a value (from json or default value =""). The solution is not perfect but It works like it was expected.
Reply

#4
I'm late to the party here, but I hope it can help someone else.

Since Spring first tries to create an instance of the bean annotated with `@ModelAttribute` before actually trying to bind the fields (see [ModelAttributeMethodProcessor][ModelAttributeMethodProcessor]), we don't have much choice. While we can use a default value for the fields, this is not an option for complex objects (e.g. `MultipartFile`).

Looking at the source code, I found out Spring can set those values using a [DataBinder][WebDataBinder]. So, we can declare the fields to be initialized later without the need to be nullable.

```kotlin
class MyClassDTO {

@field:NotBlank(message = "Name cannot be blank")
lateinit var name: String

@field:NotBlank(message = "Topic cannot be blank")
lateinit var topic: String

@field:NotNull(message = "File cannot be null")
lateinit var file: MultipartFile
}
```

[ModelAttributeMethodProcessor]:

[To see links please register here]

[WebDataBinder]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through