Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow JsonObject and JsonArray to be used in any POJO for JSON handling #39615

Merged
merged 2 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ public JsonObject jsonObject(JsonObject input) {
return result;
}

@POST
@Path("jsonObjectWrapper")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public JsonObjectWrapper jsonObjectWrapper(JsonObjectWrapper wrapper) {
var payload = wrapper.payload;
JsonObject result = new JsonObject();
result.put("name", payload.getString("name"));
result.put("age", 50);
result.put("nested", new JsonObject(Collections.singletonMap("foo", "bar")));
result.put("bools", new JsonArray().add(true));
return new JsonObjectWrapper(result);
}

@POST
@Path("jsonArray")
@Produces(MediaType.APPLICATION_JSON)
Expand All @@ -36,4 +50,22 @@ public JsonArray jsonArray(JsonArray input) {
result.add("last");
return result;
}

@POST
@Path("jsonArrayWrapper")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public JsonArrayWrapper jsonArrayWrapper(JsonArrayWrapper wrapper) {
var payload = wrapper.payload;
JsonArray result = payload.copy();
result.add("last");
return new JsonArrayWrapper(result);
}

public record JsonObjectWrapper(JsonObject payload) {
}

public record JsonArrayWrapper(JsonArray payload) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ public void testJsonObject() {
.body("bools[0]", Matchers.equalTo(true));
}

@Test
public void testJsonObjectWrapper() {
RestAssured.with()
.body("{\"payload\": {\"name\": \"Bob\"}}")
.contentType("application/json")
.post("/vertx/jsonObjectWrapper")
.then()
.statusCode(200)
.contentType("application/json")
.body("payload.name", Matchers.equalTo("Bob"))
.body("payload.age", Matchers.equalTo(50))
.body("payload.nested.foo", Matchers.equalTo("bar"))
.body("payload.bools[0]", Matchers.equalTo(true));
}

@Test
public void testJsonArray() {
RestAssured.with()
Expand All @@ -51,4 +66,17 @@ public void testJsonArray() {
.body("[1]", Matchers.equalTo("last"));
}

@Test
public void testJsonArrayWrapper() {
RestAssured.with()
.body("{\"payload\": [\"first\"]}")
.contentType("application/json")
.post("/vertx/jsonArrayWrapper")
.then()
.statusCode(200)
.contentType("application/json")
.body("payload[0]", Matchers.equalTo("first"))
.body("payload[1]", Matchers.equalTo("last"));
}

}
4 changes: 4 additions & 0 deletions extensions/vertx/deployment/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-mutiny-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jackson-spi</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
import io.quarkus.jackson.spi.JacksonModuleBuildItem;
import io.quarkus.vertx.runtime.jackson.JsonArrayDeserializer;
import io.quarkus.vertx.runtime.jackson.JsonArraySerializer;
import io.quarkus.vertx.runtime.jackson.JsonObjectDeserializer;
import io.quarkus.vertx.runtime.jackson.JsonObjectSerializer;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.core.spi.JsonFactory;

public class VertxJsonProcessor {
Expand All @@ -24,4 +31,16 @@ void nativeSupport(List<ReinitializeVertxJsonBuildItem> reinitializeVertxJson,
serviceProviderBuildItemBuildProducer
.produce(ServiceProviderBuildItem.allProvidersFromClassPath(JsonFactory.class.getName()));
}

@BuildStep
JacksonModuleBuildItem registerJacksonSerDeser() {
return new JacksonModuleBuildItem.Builder("VertxTypes")
.add(JsonArraySerializer.class.getName(),
JsonArrayDeserializer.class.getName(),
JsonArray.class.getName())
.add(JsonObjectSerializer.class.getName(),
JsonObjectDeserializer.class.getName(),
JsonObject.class.getName())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
/**
* Copied from {@code io.vertx.core.json.jackson.BufferDeserializer} as that class is package private
*/
class BufferDeserializer extends JsonDeserializer<Buffer> {
public class BufferDeserializer extends JsonDeserializer<Buffer> {

@Override
public Buffer deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
/**
* Copied from {@code io.vertx.core.json.jackson.BufferSerializer} as that class is package private
*/
class BufferSerializer extends JsonSerializer<Buffer> {
public class BufferSerializer extends JsonSerializer<Buffer> {

@Override
public void serialize(Buffer value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.quarkus.vertx.runtime.jackson;

import java.util.List;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer;
import com.fasterxml.jackson.databind.util.Converter;
import com.fasterxml.jackson.databind.util.StdConverter;

import io.vertx.core.json.JsonArray;

public class JsonArrayDeserializer extends StdDelegatingDeserializer<JsonArray> {

public JsonArrayDeserializer() {
super(new StdConverter<List<?>, JsonArray>() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a weird API where that anonymous class should be a method. Two classes for just that, this is class inflation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, what Jackson normally proposes is to not have a subclass, but to just pass the converter as a constructor argument.
We cannot do that however (at least not with some work which is of extremely limited usefulness) due to how the Jackson Module is created - we need a no-args constructor

@Override
public JsonArray convert(List list) {
return new JsonArray(list);
}
});
}

@Override
protected StdDelegatingDeserializer<JsonArray> withDelegate(Converter<Object, JsonArray> converter,
JavaType delegateType,
JsonDeserializer<?> delegateDeserializer) {
return new StdDelegatingDeserializer<>(converter, delegateType, delegateDeserializer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/**
* Copied from {@code io.vertx.core.json.jackson.JsonArraySerializer} as that class is package private
*/
class JsonArraySerializer extends JsonSerializer<JsonArray> {
public class JsonArraySerializer extends JsonSerializer<JsonArray> {
@Override
public void serialize(JsonArray value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeObject(value.getList());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package io.quarkus.vertx.runtime.jackson;

import java.util.Map;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer;
import com.fasterxml.jackson.databind.util.Converter;
import com.fasterxml.jackson.databind.util.StdConverter;

import io.vertx.core.json.JsonObject;

public class JsonObjectDeserializer extends StdDelegatingDeserializer<JsonObject> {

public JsonObjectDeserializer() {
super(new StdConverter<Map<?, ?>, JsonObject>() {
@Override
public JsonObject convert(Map map) {
return new JsonObject(map);
}
});
}

@Override
protected StdDelegatingDeserializer<JsonObject> withDelegate(Converter<Object, JsonObject> converter,
JavaType delegateType,
JsonDeserializer<?> delegateDeserializer) {
return new StdDelegatingDeserializer<>(converter, delegateType, delegateDeserializer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
/**
* Copied from {@code io.vertx.core.json.jackson.JsonObjectSerializer} as that class is package private
*/
class JsonObjectSerializer extends JsonSerializer<JsonObject> {
public class JsonObjectSerializer extends JsonSerializer<JsonObject> {
@Override
public void serialize(JsonObject value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeObject(value.getMap());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ analysis_results.methods.reachable=96465
analysis_results.methods.reachable.tolerance=3
analysis_results.fields.reachable=27025
analysis_results.fields.reachable.tolerance=3
analysis_results.types.reflection=6048
analysis_results.types.reflection=6100
analysis_results.types.reflection.tolerance=3
analysis_results.methods.reflection=4707
analysis_results.methods.reflection.tolerance=3
Expand Down
Loading