I have a UserDto
with related items taken from repository which is Project-Reactor based, thus returns Flux/Mono
publishers.
My idea was to add fields/getters to DTO, which themselves are publishers
and lazily evaluate them (subscribe) on demand, but there is a problem:
Controller returns Flux
of DTO
s, all is fine, except spring doesn't serialize inner Publisher
s
What I'm trying to achieve in short:
@Repository
class RelatedItemsRepo {
static Flux<Integer> findAll() {
// simulates Flux of User related data (e.g. Orders or Articles)
return Flux.just(1, 2, 3);
}
}
@Component
class UserDto {
// Trying to get related items as field
Flux<Integer> relatedItemsAsField = RelatedItemsRepo.findAll();
// And as a getter
@JsonProperty("related_items_as_method")
Flux<Integer> relatedItemsAsMethod() {
return RelatedItemsRepo.findAll();
}
// Here was suggestion to collect flux to list and return Mono
// but unfortunately it doesn't make the trick
@JsonProperty("related_items_collected_to_list")
Mono<List<Integer>> relatedItemsAsList() {
return RelatedItemsRepo.findAll().collectList();
}
// .. another user data
}
@RestController
@RequestMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public class MyController {
@GetMapping
Flux<UserDto> dtoFlux() {
return Flux.just(new UserDto(), new UserDto(), new UserDto());
}
}
And this is the response I get:
HTTP/1.1 200 OK
Content-Type: application/json
transfer-encoding: chunked
[
{
"related_items_as_method": {
"prefetch": -1,
"scanAvailable": true
},
"related_items_collected_to_list": {
"scanAvailable": true
}
},
{
"related_items_as_method": {
"prefetch": -1,
"scanAvailable": true
},
"related_items_collected_to_list": {
"scanAvailable": true
}
},
{
"related_items_as_method": {
"prefetch": -1,
"scanAvailable": true
},
"related_items_collected_to_list": {
"scanAvailable": true
}
}
]
It seems like Jackson doesn't serialize Flux
properly and just calls .toString()
on it (or something similar).
My question is: Is there existing Jackson serializers for Reactor Publishers or should I implement my own, or maybe am I doing something conceptually wrong.
So in short: how can I push Spring to evaluate those fields (subscribe to them)
If I understand correctly, what you try to achieve is to create an API that needs to respond with the following response:
HTTP 200
[
{
"relatedItemsAsField": [1,2,3]
},
{
"relatedItemsAsField": [1,2,3]
},
{
"relatedItemsAsField": [1,2,3]
}
]
I would collect all the elements emitted by the Flux generated by RelatedItemsRepo#findAll
by using Flux#collectList
, then map
this to set the UserDto
object as required.
Here is a gist.