I have an endpoint that when called gives this error:
2024-10-23 12:21:14,135 SEVERE [org.ecl.yas.int.SerializationContextImpl] (executor-thread-3) Generating incomplete JSON
2024-10-23 12:21:14,136 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-3) HTTP Request to /api/contacts/scores/compound/gambit-digital.com failed, error id: 971b0a13-4991-45ff-b720-dfb50644855f-20: jakarta.json.bind.JsonbException: Unable to serialize property 'finalScores' from at.hksolutions.gambit.boundary.jaxrs.FinalScoreResponse
The endpoint looks like this:
@GET
@Path("mypath")
@Produces(MediaType.APPLICATION_JSON)
public FinalScoreResponse getFinalScores() {
.....
// Some logic
// Serialization fails:
return new FinalScoreResponse(finalScores, cache.lastUpdated);
}
A FinalScoreResponse
looks like this:
public record FinalScoreResponse(
List<FinalScore> finalScores,
Date lastUpdated
) {
}
What I have tried:
FinalScoreResponse
just contain lastUpdated
- WORKSList<FinalScore>
directly - WORKSSo the issue is clearly related to List<FinalScore>
not being able to be serialized within the FinalScoreResponse. It is weird though, because on its own, it can be serialized.
A FinalScore
looks like this:
public record FinalScore(
String id,
String name,
double score,
int normalizedScore,
String lifecycleStage
) {
}
Any solutions to having it serialized within the FinalScoreResponse
?
Note: I can confirm the logic and endpoint gets called properly, it's solely are serialization issue.
The issue was that my List<FinalScore> finalScores
was being incorrectly deserialized with objectMapper.readValue(json)
before it was used in the response. Instead of getting a list of FinalScore
objects, I ended up with a raw List
of objects with unknown types. Interestingly, this didn't throw an error during deserialization:
List<FinalScore> finalScores = cacheService.fromJson(json);
This occurred due to Java's type erasure, which strips away generic type information at runtime, causing the JSON to be deserialized into a raw List<Object>
. Without specifying the target type, the deserialization framework couldn’t infer that the list should contain FinalScore
objects.
To fix this, I needed to provide the correct type information explicitly by using a TypeReference
. Here's the updated fromJson
method:
objectMapper.readValue(json, new TypeReference<List<FinalScore>>() {});
This ensures that the JSON is correctly deserialized into a List<FinalScore>
, avoiding the type erasure issue and preventing any unexpected runtime behavior.