spring validation in composition - spring

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?
)

Related

Validate complex object on GET request

I'm trying to apply input validation on a complex parameter of a get request.
What I have:
data class FilterDTO (
#Valid
#NotNull
val id: Long? = null,
#NotNull
val code: String? = null
)
#Validated
#RestController
#RequestMapping("/foo")
class FooController {
#GetMapping
fun get(
#Valid filter: FilterDTO,
#Valid #NotNull #RequestParam("bar") bar: String?
) {
// ...
}
}
The above endpoint validates correctly the #NotNull on the bar parameter but it seems to ignore the validation on the complex FilterDTO object.
I have tried:
Adding #Valid on FilterDTO's properties (even with Kotlin's #field: and #get:)
Adding #Validated (??) on the FilterDTO whole class
Couldn't make it work.
Is it possible to have a complex get parameter validated?
Thanks
Just found the problem. For anyone getting here, I should be annotating with #field: the validations I want. So simply changing my DTO to this worked:
data class FilterDTO (
#field:NotNull
val id: Long? = null,
#field:NotNull
val code: String? = null
)

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!

#RequestBody and #Valid not validating empty/blank string field in kotlin object

My request is parsed into the Kotlin object that is the request body in the controller. Currently, if the fields are null - a validation exception is thrown which is exactly what i want.
However, I am using #NotBlank and this doesn't seem to validate the way it's meant to against "" or " ". What am I missing?
#NotEmpty also doesn't check against "". They both seem to just check against null, which is only part of what I'm looking for.
Essentially I am looking for the request not to be null, the list field not to be null, the inner BumblebeeEvent in the list not to be null, and each Event to have it's fields validated (e.g. not null, "" or " ").
Here is my controller:
#Controller
class BumblebeeEventController {
#PostMapping("/publish")
fun eventIntake(#RequestBody #Valid payload: BumblebeeEventList) : ResponseEntity<String>{
return ResponseEntity("Published ${eventList.size} event(s) successfully",HttpStatus.OK)
}
}
class Event(#NotBlank val localTime: String){}
class BumblebeeEvent(#NotNull val event: Event)
class BumblebeeEventList(#NotNull val events: List<BumblebeeEvent>){}
Thanks in advance
try with
class Event(#NotBlank val localTime: String){}
class BumblebeeEvent(#NotNull #Valid val event: Event)
class BumblebeeEventList(#NotNull #Valid val events: List<BumblebeeEvent>){}
You must indicate that the validation must go also in the nested object

(Spring boot) How can I ignore some field from request body inside rest controller

Suppose I have signUp method inside rest controller class looks like this.
#PostMapping("/signup")
fun authenticateSignUp(#RequestBody command: RegisterUserCommand): CompletableFuture<String> {
return commandGateway.send<String>(command)
}
So it requires request body which is RegisterUserCommand.
data class RegisterUserCommand(
val userId: String,
val balance: BigDecimal,
val username: String,
private val email: String,
private val password: String
)
I want to ignore some fields like userId, balance so I can generate it later inside controller like this
#PostMapping("/signup")
fun authenticateSignUp(#RequestBody request: RegisterUserCommand): CompletableFuture<String> {
val command = request.copy(userId = ObjectId.get().toHexString(), balance = BigDecimal.ZERO)
return commandGateway.send<String>(command)
}
Are there any annotation to ignore this field so it won't return bad request even though I didn't put userId, balance within request body
As correctly pointed out by #flaxel, you can use ? from Kotlin and I believe add #JvmOverloads constructor to it as well.
But, in my opinion, using DTO is the best way to deal with that for sure.
The input of your Controller should not be the Command but just a DTO with the fields you are interested in. How you build your command with enhanced values should not be affected by it.
In this case, you would have something like this (also added #TargetAggregateIdentifier because probably you missed it):
data class RegisterUserCommand(
#TargetAggregateIdentifier
val userId: String,
val balance: BigDecimal,
val username: String,
private val email: String,
private val password: String
)
...
data class RegisterUserDto(
val username: String,
private val email: String,
private val password: String
)
...
#PostMapping("/signup")
fun authenticateSignUp(#RequestBody request: RegisterUserDto): CompletableFuture<String> {
val command = new RegisterUserCommand // build the command the way you want it
return commandGateway.send<String>(command)
}
I guess you can mark the variable as nullable with the ? operator. But I would suggest to use DTOs.
data class RegisterUserDto(
val username: String,
private val email: String,
private val password: String
)

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

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

Resources