spring-projects / spring-projects/spring-framework
Spring WebFlux HATEOAS No Encoder for EntityModel with preset Content-Type 'null'
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
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 a Mono<List> of HAL-JSON, but not a Flux.
pom.xml and Pojo class
(...)
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
(...)
<dependencies>
(...)
public class Pojo {
private Integer id;
private String name;
public Pojo(Integer id, String name) {
this.id=id; this.name=name;
}
public Integer getId() { return id; }
public String getName() { return name; }
}
@RestController
@RequestMapping()
public class PojoResource {
Flux<Pojo> getPojos() {
return Flux.just(new Pojo(1, "alpha"), new Pojo(2, "beta"), new Pojo(3, "gamma"));
}
@GetMapping(value="/pojoA", produces = MediaType.APPLICATION_NDJSON_VALUE)
public Flux<Pojo> getAllPojosAsStream() {
return getPojos();
}
@GetMapping("/pojoB")
public Mono<List<EntityModel<Pojo>>> getAllPojosAsHAL() {
return getAllPojosAsHALStream().collectList();
}
@GetMapping(value="/pojoC", produces = MediaType.APPLICATION_NDJSON_VALUE)
public Flux<EntityModel<Pojo>> getAllPojosAsHALStream() {
return getPojos().map(p -> EntityModel.of(p));
}
}
Calling for Flux of Pojo
curl -X 'GET' 'http://localhost:8080/pojoA' -H 'accept: application/x-ndjson'
Works like a charm:
{"id":1,"name":"alpha"}
{"id":2,"name":"beta"}
{"id":3,"name":"gamma"}
Calling for Mono of List of EntityModel of Pojo
curl -X 'GET' 'http://localhost:8080/pojoB' -H 'accept: */*'
Another gem:
[
{
"id": 1,
"name": "alpha",
"links": []
},
{
"id": 2,
"name": "beta",
"links": []
},
{
"id": 3,
"name": "gamma",
"links": []
}
]
But calling for Flux of EntityModel of Pojo
curl -X 'GET' 'http://localhost:8080/pojoC' -H 'accept: application/x-ndjson'
Fails with an exception:
org.springframework.http.converter.HttpMessageNotWritableException: No Encoder for [org.springframework.hateoas.EntityModel<my.package.Pojo>] with preset Content-Type 'null'
(Full stacktrace can be provided if needed)
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the /pojoC example with a Flux<EntityModel> and the application/x-ndjson Accept header, then compare it with the working /pojoA and /pojoB endpoints. Trace the WebFlux message-writing path for EntityModel and identify the missing encoder integration; done means the streaming HAL response is encoded successfully without the reported exception.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring, spring-boot
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100