quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.54k stars 2.61k forks source link

JsonObject is empty when used with resteasy-reactive #39599

Closed Serkan80 closed 5 months ago

Serkan80 commented 5 months ago

Describe the bug

I have the following code:

    import io.vertx.core.json.JsonObject;

    public class CreateSomethingRequest {
      @NotNull
      public JsonObject payload;

      @Size(max = 10)
       public List<@Valid Attachment> attachements;
   }

@Path ("/path")
public class Controller {
    @POST
    public RestResponse<Map<String, String>> createSomething(@Valid CreateSomethingRequest request) {
        var id = ....
        return RestResponse.status(CREATED, Map.of("somethingID", id));
    }
}

When I make the following POST request:

image

And when I debug it in IntelliJ, then I see that the payload is empty: image

If I replace JsonObject with Map<String, Object>, then it starts working (again):

image

Strangely, the validation is also not happening (or skipped), since the payload field is annotated with @NotNull.

Note that this used to work in Quarkus 3.2.x. Since recently we migrated to 3.8.2 and we see this odd behaviour happening.

And another odd thing is, that our integration test succeeds with RestAssured & Wiremock. This only happens if we startup the application (in dev or prd mode).

Expected behavior

JsonObject should be mapped correctly.

Actual behavior

No response

How to Reproduce?

No response

Output of uname -a or ver

Windows 10

Output of java -version

jdsk 17 Temurin

Quarkus version or git rev

3.8.2

Build tool (ie. output of mvnw --version or gradlew --version)

Maven 3.8.6

Additional information

My pom.xml

<dependencies>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-jwt</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-hibernate-validator</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-openapi</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-rest-client-reactive-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-smallrye-health</artifactId>
        </dependency>
</dependencies>
quarkus-bot[bot] commented 5 months ago

/cc @FroMage (resteasy-reactive), @geoand (resteasy-reactive), @stuartwdouglas (resteasy-reactive)

geoand commented 5 months ago

Thanks a lot for the report.

Do you mind attaching a sample application that does not work in Quarkus 3.8.z but does in 3.2.z as you describe? That will allow us to pinpoint and come up with a fix much easier.

geoand commented 5 months ago

cc @gsmet for the validation part

Serkan80 commented 5 months ago

I've put a reproducer here:

https://github.com/Serkan80/quarkus-issue-reproducers/tree/master/jsonobject-mapping-issue

One correction from my side: it also doesn't work in the previous LTS version. We were using multipart then it used to work, but since we switched to application/json, it doesn't work anymore.

geoand commented 5 months ago

Thanks for the info.

gsmet commented 5 months ago

I don't think there's an issue with Hibernate Validator: the payload field is an empty JsonObject not null.

geoand commented 5 months ago

I am curious to why you expect JsonObject deserialization to work inside a POJO

FroMage commented 5 months ago

For this to have worked in Multipart, it would have been a slightly different body, or parts.

As for whether this should work, I'd say we could provide a Jackson/Jsonb ser/deser for JsonObject and friends, that seems sensible. Especially given that it's very similar to Map<String,Object>, which Jackson/Jsonb support OOTB.

I am curious to why you expect JsonObject deserialization to work inside a POJO

POJO, but I assume a Jackson-deserialised one.

geoand commented 5 months ago

As for whether this should work, I'd say we could provide a Jackson/Jsonb ser/deser for JsonObject and friends, that seems sensible. Especially given that it's very similar to Map<String,Object>, which Jackson/Jsonb support OOTB.

Yeah, I am not saying we should not do this, I am just wondering where the expectation that it does work comes from

FroMage commented 5 months ago

Regularity, I suppose? We do accept it as an http body root, same for multipart roots. Now, agreed, this is different because it's part of a jackson-deserialised body, but perhaps users don't realise that.

It's already hard enough to understand why we have message deserialisers different to header/path/cookie/etc deserialisers.

geoand commented 5 months ago

Indeed

Serkan80 commented 5 months ago

I am curious to why you expect JsonObject deserialization to work inside a POJO

I think it has to do with expectation management :) Why does it work as a root object and not in the case when it is inside a Pojo?

In our case, we have a structured data with predefines fields and there is also 1 payload field inside the Pojo, which is in free format (can contain anything).

If according to Quarkus' guidelines, JsonObject is not the right choice for a free format payload inside a POJO, then I'm happy to replace it to a Map<String,Object>.

And we have also other situations were we work "schemaless", because we are not interested in the payload that is coming in and just pass it through to other clients.

geoand commented 5 months ago

I'll make it work, no worries :)

geoand commented 5 months ago

https://github.com/quarkusio/quarkus/pull/39615 takes care of it