Reputation: 63
I trying to learn Quarkus, so feel free to correct me if I made any mistakes.
So now to the problem.
I have a server that sends SSE responses. I want to write a quarkus client to make calls to that server endpoint.
The problem is that, even though I have mapped correctly the response to a java record the quarkus app fails with error: ERROR [io.qua.ver.cor.run.VertxCoreRecorder] (vert.x-eventloop-thread-1) Uncaught exception received by Vert.x: jakarta.ws.rs.ProcessingException: Response could not be mapped to type class TestDTO for response with media type null
The actual server response is this:
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Content-Type: text/event-stream
< Cache-Control: no-cache
< Connection: keep-open
< Transfer-Encoding: chunked
<
event: success
data: {"a":"str_value_1","date":"1970-01-01T02:00:00.000Z","b":1}
event: success
data: {"a":"str_value_2","date":"1970-01-01T02:00:00.000Z","b":2}
@Path("/api")
@RegisterRestClient(configKey = "service-api")
public interface TestClient {
@GET
@Path("test")
@Produces(MediaType.SERVER_SENT_EVENTS)
Multi<TestDTO> getTest();
}
@JsonIgnoreProperties(ignoreUnknown = true)
public record TestDTO(String a, LocalDate date, int b) {
private static final ObjectWriter WRITER = new ObjectMapper()
.writerWithDefaultPrettyPrinter()
.withoutAttribute("jacksonObjectMapper");
@Override
public String toString() {
try {
return WRITER.writeValueAsString(this);
} catch (Exception e) {
return String.format("IssueComment[id=%s]", id);
}
}
}
@Path("/test")
@ApplicationScoped
public class testResource {
@RestClient
GitHubServiceClient client;
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public Multi<TestDTO> hello() {
return client.getTest().onItem().invoke(item -> System.out.println(item));
}
}
Now when I chenge thre TestDTO to TestDTO(String a)
the client doesn't throw mapping error. the result I get might indicate where is the problem:
{
"a" : "{\"a\":\"str_value_1\",\"date\":\"1970-01-01T02:00:00.000Z\",\"b\":1}"
}
{
"a" : "{\"a\":\"str_value_2\",\"date\":\"1970-01-01T02:00:00.000Z\",\"b\":2}"
}
It seems that the obeject mapper instead of trying to map the data to the record, it interprets the SSE data as a string.
One way I found to bypass this error is doing the mapping process manually.
I change the client interface method to return Multi(ie Multi<String> getTest()
), and use com.fasterxml.jackson.databind.ObjectMapper;
in TestResource
like this:
@Path("/test")
@ApplicationScoped
public class TestResource{
@RestClient
GitHubServiceClient client;
@GET
@Produces(MediaType.SERVER_SENT_EVENTS)
public Multi<TestDTO> hello() {
ObjectMapper objectMapper = new ObjectMapper();
return client.getTest()
.map(Unchecked.function(s -> {
try {
return objectMapper.readValue(s, TestDTO.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
})).onItem().invoke(item -> System.out.println(item));
}
}
Upvotes: 0
Views: 116
Reputation: 64059
I created a simplified version of your example and everything works as expected
DTO:
public record Greet(String message) {
}
Client:
@RegisterRestClient(baseUri = "http://localhost:8080/sse")
public interface Client {
@GET
@RestStreamElementType(MediaType.APPLICATION_JSON)
Multi<Greet> greet();
}
Endpoint returning the actual data:
@Path("/sse")
public class SseResource {
@GET
@RestStreamElementType(MediaType.APPLICATION_JSON)
public Multi<Greet> greet() {
return Multi.createFrom().items(new Greet("Hello"), new Greet("World"));
}
}
Endpoint that calls the REST Client:
@Path("/client")
public class ClientResource {
@RestClient
Client client;
@GET
@RestStreamElementType(MediaType.APPLICATION_JSON)
public Multi<Greet> greet() {
return client.greet()
.onItem().invoke(i -> System.out.println(i));
}
}
Upvotes: 1