https://kotlinlang.org logo
Title
a

Andrzej Sawoniewicz

06/09/2022, 2:56 PM
Hi, anybody know why using @Validated on a Controller class in Spring could mess up with constructor injections? I simply get null values for all injected objects. The problem came out after migration to Kotlin from Java.
:not-kotlin: 4
m

Mikhail

06/09/2022, 3:31 PM
Code?
I use
@Validated
on an interface. I prefer interface-driven controllers
a

Andrzej Sawoniewicz

06/09/2022, 3:32 PM
It works: @RestController @Validated public class TestController { private NativeWebRequest request; @Autowired public TestController(NativeWebRequest request) { this.request = request; } @GetMapping( value = "/test/{countryCode}", produces = {"application/json"}) public ResponseEntity<String> getTestResponse(@Pattern(regexp = "^[A-Z]{2}$") String countryCode) { return new ResponseEntity<>("ok", HttpStatus.OK); } } It does not work: @RestController @Validated open class TestController2 @Autowired constructor(private val request: NativeWebRequest) { @GetMapping(value = ["/test2/{countryCode}"], produces = ["application/json"]) fun getTest2Response(countryCode: @Pattern(regexp = "^[A-Z]{2}$") String?): ResponseEntity<String> { return ResponseEntity("ok", HttpStatus.OK) } } It works: @RestController //@Validated open class TestController2 @Autowired constructor(private val request: NativeWebRequest) { @GetMapping(value = ["/test2/{countryCode}"], produces = ["application/json"]) fun getTest2Response(countryCode: @Pattern(regexp = "^[A-Z]{2}$") String?): ResponseEntity<String> { return ResponseEntity("ok", HttpStatus.OK) } }
m

Mikhail

06/09/2022, 3:46 PM
well, everything works fine for me note that
ConstraintViolationException
is not handled in the first request
Also, you probably should inject
NativeWebRequest
not as a constructor parameter, but define it as a parameter of a function that handles the request look at my snippet
a

Andrzej Sawoniewicz

06/09/2022, 3:57 PM
THanks, any idea why it could not work on my side? @RestController @Validated open class TestController2 @Autowired constructor(private val thing: Thing) { @GetMapping(value = ["/test2/{countryCode}"]) fun getTest2Response(countryCode: @Pattern(regexp = "^[A-Z]{2}$") String?): ResponseEntity<String> { return ResponseEntity(thing.value, HttpStatus.OK) } }
I still get null value for the injected thing object
I use springboot 2.6.7 and Kotlin 1.6.21
m

Mikhail

06/09/2022, 3:59 PM
I see you use
open
do you use spring support plugin for kotlin?
in the
plugins {}
block of your
build.gradle.kts
:
kotlin("plugin.spring") version "1.6.21"
a

Andrzej Sawoniewicz

06/09/2022, 4:01 PM
Yes but for groovy version gradle: id 'org.jetbrains.kotlin.jvm' version '1.6.21'
m

Mikhail

06/09/2022, 4:04 PM
removed the spring plugin from my build config:
a

Andrzej Sawoniewicz

06/09/2022, 4:06 PM
plugins { id 'org.springframework.boot' version '2.6.7' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java' id 'org.jetbrains.kotlin.jvm' version '1.6.21' }
m

Mikhail

06/09/2022, 4:08 PM
well, repalce it with:
plugins {
    id 'org.springframework.boot' version '2.6.7'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
    id 'org.jetbrains.kotlin.jvm' version '1.6.21'
    id "org.jetbrains.kotlin.plugin.spring" version '1.6.21'
}
❤️ 3
a

Andrzej Sawoniewicz

06/09/2022, 4:11 PM
Wow, it works! I missed that 🙂 Thank you very much!
:cheers: 2
d

Diego Marzo

06/10/2022, 10:47 AM
Hi @Andrzej Sawoniewicz, cool you issue is fixed! I believe you could define your controller like this also:
@Validated
@RestController
class TestController(private val request: NativeWebRequest)
If you have your spring plug there is no need of "open", no need for "@Autowired" and no need for the explicit "constructor" I know it is not super important but you can remove some boilerplate