Open Fradantim opened 3 years ago
I've tested this with Spring Boot 2.5.4 and this has a slightly different behavior than the one you've described (a different error message). I guess this is all related to #26212.
"/pojoA"
endpoint produces Flux<Pojo>
as "application/x-ndjson"
. The http://ndjson.org/ spec is about producing separate JSON documents, separated by newlines. This is especially useful for streaming responses. In this case, Spring serializes each Pojo
separately as they come using the current configuration for the "application/json"
media type."/pojoB"
endpoint produces Mono<List<EntityModel<Pojo>>>
with no specific media type. This falls back to "application/json"
using the default JSON configuration. This does not produce HAL-JSON, as this merely serializes EntityModel
instances as best as it can."/pojoC"
endpoint produces Flux<EntityModel<Pojo>>
with the ndjson media type. Since #26212, Spring Framework now automatically selects an alternate ObjectMapper
configuration if a specific type has been registered with the infrastructure. Here, Spring HATEOAS registers a specific one for all classes extending RepresentationModel
. This means we're trying to find a JSON serializer registered for the EntityModel
+"application/x-ndjson"
pair. Nothing has been registered and the serialization process fails with an error message.First, I must say that your assumptions are wrong - serializing an EntityModel
outside of the media types supported by Spring HATEOAS is not supported. In this case, this merely gets serialized as JSON but I don't think Spring HATEOAS guarantees any behavior here. I don't think that HAL-JSON resources are meant to be streamed with in a media type like ND-JSON, @odrotbohm ?
@rstoyanchev I initially thought about some inconsistency, blindly serializing in one case and rejecting in another. It seems that this is all related to the following: with "application/json"
, we collect the elements and consider the org.springframework.web.servlet.mvc.method.annotation.ReactiveTypeHandler.CollectedValuesList
type; with ND-JSON, we are considering EntityModel
elements one by one because this is a streaming media type.
Should we do something special with registered types when it comes to collections or collected values?
If you think that the current behavior is fine, then we should close this issue on this side.
This seems to be a duplicate of spring-projects/spring-hateoas#1584 that has quite a bit of discussion on Spring HATEOAS' take on things. Also, there's spring-projects/spring-framework#27074 that discusses especially 3 in detail.
I am torn on 2, as, AFAIR, handling collections inspects the collection's element type for ObjectMapper
selection. Thus, from a consistency point of view, I guess I'd expect the additional Mono
wrapping not to result in different serialization behavior compared to without the Mono
wrapping. That said, the devil is in the details, here, too. Accepting */*
makes this work as it can adapt to the media type for calculated for List
(likely application/json
). If the media type to be produced was calculated from the element type, we'd end up with application/hal+json
but then end up rendering a simple JSON array, which is not valid HAL (also discussed in detail here).
The gist of spring-projects/spring-framework#27074's take on 3 is that I think looking up an ObjectMapper
for EntityModel
and application/x-ndjson
is wrong, as the processing is already implementing the media type and looking up ObjectMapper
instances for the elements of the stream. The NDJSON spec requires them to be of plain JSON, which means that a lookup should rather use application/json
as media type to produce. Spring HATEOAS current setup would then cause that to be answered with the ObjectMapper
registered for the first listed media type in @EnableHypermediaSupport
, for which in a standard Spring Boot arrangement HAL is the actual format produced. I.e. the client would see a stream of HAL rendered EntityModel
documents.
Happy to jump on a call if needed, as I can see that it's quite a complex topic to discuss via text.
Putting this into 6.x Backlog along with #27400. @odrotbohm as discussed, please update the issue title to reflect the actual enhancement request more clearly.
Do we have any progress here? Thanks.
Affects: org.springframework.boot:spring-boot-starter-parent:2.5.2
Currently also an open stackoverflow question.
While trying to expose and consume an endpoint which produces
application/x-ndjson
and returns a HAL-JSON some kind of integration is missing, I'm able to return and de-serialize aMono<List>
of HAL-JSON, but not aFlux
.pom.xml and Pojo class
``` xml (...)Calling for Flux of Pojo
Works like a charm:
Calling for Mono of List of EntityModel of Pojo
Another gem:
But calling for Flux of EntityModel of Pojo
Fails with an exception:
Is this not an intended use case? If you can provide me a little of info about the jackson encoders perhaps I can contribute with my grain of sand.