How to configure Spring MVC to validate constructor parameters of controller method arguments - spring

I'm writing a project in Kotlin and have this in a controller:
#PostMapping("/token")
fun generateToken(#RequestBody #Valid credentials: Credentials) { /* something */ }
data class Credentials(#Email #NotBlank val email: String,
#NotBlank val password: String)
By default #Valid annotation tells Spring to validate object fields. But Kotlin places constraint annotations on the constructor parameters, so validation doesn't work. To make it work I have to define use-site targets for annotations:
data class Credentials(#field:Email #field:NotBlank val email: String,
#field:NotBlank val password: String)
which is annoying and adds visual garbage. Is it possible to configure Spring to validate constructor parameters?

There isn't a whole lot you can do. You can make it look a little better by combining annotations for each field, e.g.:
data class Credentials(#field:[Email NotBlank] val email: String,
#field:NotBlank val password: String)
Other than that, your only other options are:
Manually configured Spring validation classes
Validating the data within your code body

Related

Searching by Value in Redis in Spring Boot and Kotlin

Let's consider we are in Spring Boot with Kotlin. For Redis queries, we're using a RedisTemplate dependency.
Considering the following data class:
data class Person (
val id: String,
val name: String,
val birthDate: ZonedDateTime
)
For saving we'll use:
fun save(person: Person) {
redisTemplate.opsForValue().set(person.id, person)
}
Then, is it possible to search by name, which is a property of the Person class - in order to retrieve a collection of Person's with the same name? And if yes, how can this be done with RedisTemplate?
Thank you in advance!

Bean Validation on complex objects - Kotlin Spring Boot

I have a data class that is being validated except for the contents of the lists
data class EmailDto(
#get:Valid
#get:NotEmpty
val recipients: List<#Email String>,
#get:NotBlank
val subject: String,
#get:Valid
val cc: List<#Email String> = listOf(),
#get:Valid
val bcc: List<#Email String> = listOf(),
)
So my problem is if I use a value of listOf() for recipients the validation fires and gives me an exception, whereas listOf("test.com") does not cause an exception when it should since the string value isn't a valid email address.
I've tried all different kinds of targets on the annotations and omitted them but I can't seem to get any validation to work on complex fields. Does anyone have any insight on this? I haven't been able to really track anything down searching online.

Kotlin Type Mismatch: Taking String from URL path variable and using it as an ID

My Spring Boot Application in Kotlin has a POST endpoint defined like this:
fun postTermin( #PathVariable("pathID") pathID: String, #Validated #RequestBody termin: RequestBody): ResponseEntity<Appointment> {
return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
}
I'd like to take that "pathID" and use it to find an entity from a repository like so:
myRepository.findById(pathID)
The CRUDRepository I'm calling there is for an Entity "Dealer" where the ID is defined as:
#Id
#Column(name = "id", length = 10, nullable = false)
open var id: String = ""
The Problem: I get this compile error:
Kotlin: Type mismatch: inferred type is Optional<Dealer!> but Dealer?
was expected
What's the problem here? Why the "Optional"?
The comment by Slaw really helped.
As described in Spring Data JPA How to use Kotlin nulls instead of Optional there's also a "findByIdOrNull" function for CRUDRepository, i had missed that.
For my use case, that works.

Spring validation for Kotlin primitives

I have created simple Spring Boot project with using Kotlin 1.4.10.
I have simple DTO in the project:
data class TestRequest(
#field:NotNull val id: Int,
val optionalId: Int?,
val name: String,
val optionalName: String?,
#field:NotNull val value: Double,
val optionalValue: Double?,
val nested: NestedRequest,
val optionalNested: NestedRequest?
)
data class NestedRequest(
#field:NotNull val nestedId: Long,
val nestedOptionalId: Long?,
val nestedName: String,
val optionalNestedName: String?
)
I am wondering, what is best practice to write Kotlin DTO's and validate them?
From one side, Kotlin allows to mark fields as not-null, which seems to be convenient for validation.
From another, in case of Kotlin numeric types (Int, Long, Double etc), which seems to have default value, as Java primitives do, so checking of nullability does not work for such fields unlike string ones.
If I use #JsonProperty(required = true), nullability will be checked by Jackson and not by validator, so this approach is also incorrect.
As a result I've got a question - is there a proper way of validating Kotlin DTO's at all?
As you have noticed, it is hard to validate kotlin primitive types for nulability, because they have default values.
I would say that using a combination of Jackson (for nullability of primitive types) and Javax validation (stuff like min/max value) is fine.
However, if you don't want to use Jackson validation, you can validate primtive types by setting the type of the variable as nullable but annotating it as #NotNull.
For example:
import javax.validation.Valid
import javax.validation.constraints.NotNull
data class MyClass(
#get:Valid
#get:NotNull
val someInt: Int?,
val someText: String
)
Now, because the type is nullable (in this example Int?) Jackson won't insert a default value for someInt, therefore someInt is going to have a value of null. After that, when the object gets validated, an error will be thrown because the value of someInt is null.
For example, if we have the following #PostMapping:
#PostMapping("/test")
fun testFunction(#RequestBody #Valid data: MyClass) {
print(data)
}
Sending a POST request with body:
{
"someText": "wow"
}
Will return an error like this one:
"timestamp": "2020-10-02T15:22:53.361+00:00",
"status": 400,
"error": "Bad Request",
"trace": "org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in public void main.api.TestPublicController.myObject(main.api.MyClass): [Field error in object 'myClass' on field 'someInt': rejected value [null]; ...

spring validation in composition

I have the following data classes:
data class User (
#field:NotEmpty
val firstName: String?
#field:NotEmpty
val lastName: String?
)
data class Expert (
#field:NotEmpty
val name: String?
#field:NotNull
val contact: User?
)
And I would like to use my rest API endpoint to create an expert with spring validation:
#RestController
#RequestMapping("/api/experts")
class ExpertController(private val expertService: ExpertService) {
#PostMapping
#ResponseStatus(HttpStatus.CREATED)
fun create(#Valid #RequestBody dto: Expert) = expertService.create(dto)
}
Validation on name and contact fields works fine. But validation on firstName and lastName fields (User class) doesn't work. Is it a normal behaviour? I can't use validation on composition? Why? Or am I missing something?
In order for the User to be validated if it is contained within an Expert, you will need to add the #Valid annotation to it, so Spring's Validator knows to keep checking, otherwise it will stop.
Try this (untested):
data class Expert (
#field:NotEmpty
val name: String?
#field:NotNull
#field:Valid
val contact: User?
)

Resources