Search code examples
javanativequarkus

Why the same RestApi of Quarkus Application has different response in 'native' or 'jvm' mode?


Description

The simple code below is a demo of quarkus rest api with reactive method:

@Consumes
@Produces(MediaType.APPLICATION_JSON)
@Path("/api/v1/datasource")
public class DatasourceResource {

    @Inject
    DatabaseBoundary databaseBoundary;

    @POST
    @Path("/query")
    public Uni<Response> query(DatasourceQuery param) {
        DatasourceRecordDTO result = new DatasourceRecordDTO();
        result.setId("888");
        List<String> header = Arrays.asList("id", "name", "age");
        DatasourceRecordItem item = new DatasourceRecordItem();
        item.setKey("888");
        item.setValueList(Arrays.asList("123", "wkx", "26"));
        result.setHeader(header);
        result.setRows(List.of(item));

        result.setContent("ok");
        return Uni.createFrom().item(Response.ok(result).build());
    }
}

I tried to run it with two way:

  • 1)run directly in Intelij Idea Or run 'quarkus-run.jar' after building
  • 2)run with the binary executable file 'xxx-SNAPSHOT-runner' or build an image to run in docker/k8s

With The First way, I can have a correct response with content '{xx:xx,xx:xx}':

However, With The Seconde, I can only have an empty response '{}':

Question

Why the response behaved differently in these two running mode?

  • Quarkus version: 2.12.3.Final
  • quarkus-resteasy-reactive-jackson: 2.12.3.Final
  • graalvm version: 22.1.0-java11
  • System: MacOS x86 64

I tried to replace the Return Type 'Uni<Response>' with normal type, they behaved samely. So I wonder how the native feature made the Uni response disappear?


Solution

  • It's different because the serialization of DatasourceRecordDTO requires using reflection, which GraalVM does not enable by default.

    So in your case if you annotate DatasourceRecordDTO with @RegisterForReflection, then everything should work as expected.

    Furthermore, if you use are using RESTEasy Reactive, you can use RestResponse<DatasourceRecordDTO> instead of Response, which will instruct Quarkus to automatically register DatasourceRecordDTO for reflection.

    Just to elaborate a little more on Uni<Response>: Quarkus inspects the return type of a JAX-RS method (among other things) to determine which types to register for reflection. Since Response does not contain a generic type, Quarkus has no way of knowing what type of response was added and therefore cannot automatically register that type for reflection. RestResponse on the other does have a generic type, so Quarkus can determine what to do in that case.