I’m learning spring boot with Kotlin and I’m tryin...
# spring
d
I’m learning spring boot with Kotlin and I’m trying to do a WebClient call with Flux. I have these methods in a controller:
Copy code
@GetMapping("/slow-service-users")
    fun getAllUsers(): List<User?>? {
        Thread.sleep(2000L) // delay
        return userRepository.findAll()
    }

    @GetMapping(value = ["/users-non-blocking"])
    fun getUsersNonBlocking(): Flux<User?>? {
        <http://logger.info|logger.info>("Starting NON-BLOCKING Controller!")
        val userFlux: Flux<User?> = WebClient.create()
            .get()
            .uri("<http://localhost:8080/slow-service-users>")
            .retrieve()
            .bodyToFlux(User::class.java)
        userFlux.subscribe { user -> <http://logger.info|logger.info>(user.toString()) }
        <http://logger.info|logger.info>("Exiting NON-BLOCKING Controller!")
        return userFlux
    }
/slow-service-users
returns a proper response. But when I call
/users-non-blocking
, I get this error:
Copy code
"org.springframework.web.reactive.function.client.WebClientResponseException: 200 OK from GET <http://localhost:8080/slow-service-users>; nested exception is org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/json' not supported for bodyType=com.example.app.models.User
How can I fix this
Content type 'application/json' not supported for bodyType
error ? The project repo is here: https://github.com/danygiguere/springboot-kotlin-example. The user model is:
Copy code
@Entity
class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    var id: Long? = null

    var username = ""

    @Column(unique = true)
    var email = ""

    var password = ""
        @JsonIgnore
        get() = field
        set(value) {
            val passwordEncoder = BCryptPasswordEncoder()
            field = passwordEncoder.encode(value)
        }

    fun comparePassword(password: String): Boolean {
        return BCryptPasswordEncoder().matches(password, this.password)
    }

    val firstName: String = ""

    val lastName: String = ""

    @JsonManagedReference
    @OneToMany(cascade = [(CascadeType.ALL)], orphanRemoval = true, fetch = FetchType.EAGER)
    @JoinColumn(name = "userId", referencedColumnName = "id")
    var posts: List<Post>? = null
}
g
i know this is not directly tied to your question but your endpoints should return
Mono<ServerResponse>
👀 1
if you are interest i could bring up an example i have laying around of how i got it set up
d
you mean
Mono…
instead of
Flux<User?>
?
k
I would try to define content type on endpoint via @GetMapping(produces=application/json) and in webclient define header ACCEPT to application/json
g
@dany giguere yeah that's what i mean, your endpoints return a single server response where the body is the
Flux<User>
d
ok thanks guys. tried addding application/json and also changing to Mono but I sill have the same error. Here is my function now:
Copy code
@GetMapping(value = ["/users-non-blocking"], produces = ["application/json"])
    fun getUsersNonBlocking(): Mono<User> {
        <http://logger.info|logger.info>("Starting NON-BLOCKING Controller!")
        val userFlux: Mono<User> = WebClient.create()
            .get()
            .uri("<http://localhost:8080/slow-service-users>")
            .header("ACCEPT", "application/json")
            .retrieve()
            .bodyToMono(User::class.java)
        userFlux.subscribe { user -> <http://logger.info|logger.info>(user.toString()) }
        <http://logger.info|logger.info>("Exiting NON-BLOCKING Controller!")
        return userFlux
    }
k
just to be sure, you have produces on slow-service too?
d
yes Jakub, I do have the
produces = [“application/json”]
as well on the slow-service too
k
if you call your slow endpoint via insomnia/postman how does response look like?
d
I get a 200 with the proper payload:
Copy code
[
    {
        "id": 1,
        "username": "johndoe1",
        "email": "<mailto:johndoe1@test.com|johndoe1@test.com>",
        "firstName": "",
     ...
]
k
d
thanks a lot @kqr. Indeed I had to pass something like an array. This works now :
Copy code
@GetMapping("/slow-service-users")
    fun getAllUsers(): List<User?>? {
//        Thread.sleep(2000L) // delay
        return userRepository.findAll()
    }

    @GetMapping(value = ["/users-non-blocking"])
    fun getUsersNonBlocking(): Mono<ArrayList<*>> {
        <http://logger.info|logger.info>("Starting NON-BLOCKING Controller!")
        val userFlux: Mono<ArrayList<*>> = WebClient.create()
            .get()
            .uri("<http://localhost:8080/slow-service-users>")
            .retrieve()
            .bodyToMono(ArrayList::class.java)
        userFlux.subscribe { user -> <http://logger.info|logger.info>(user.toString()) }
        <http://logger.info|logger.info>("Exiting NON-BLOCKING Controller!")
        return userFlux
    }
662 Views