diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java index 13d9c10f93201..9159f02e2deb1 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/main/java/io/quarkus/resteasy/reactive/jackson/deployment/processor/JacksonDeserializerFactory.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -38,8 +37,6 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.deser.ContextualDeserializer; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; -import com.fasterxml.jackson.databind.type.CollectionType; -import com.fasterxml.jackson.databind.type.MapType; import com.fasterxml.jackson.databind.type.TypeFactory; import io.quarkus.deployment.annotations.BuildProducer; @@ -453,12 +450,12 @@ private ResultHandle readValueFromJson(ClassCreator classCreator, BytecodeCreato MethodDescriptor getTypeFactory = ofMethod(DeserializationContext.class, "getTypeFactory", TypeFactory.class); ResultHandle typeFactory = bytecode.invokeVirtualMethod(getTypeFactory, deserializationContext); - MethodDescriptor constructCollectionType = ofMethod(TypeFactory.class, - "constructCollectionType", CollectionType.class, Class.class, Class.class); - Class concreteCollectionType = concreteCollectionType(fieldTypeName, fieldKind); - yield bytecode.invokeVirtualMethod(constructCollectionType, typeFactory, - bytecode.loadClass(concreteCollectionType), - bytecode.loadClass(listType.name().toString())); + MethodDescriptor constructParametricType = ofMethod(TypeFactory.class, + "constructParametricType", JavaType.class, Class.class, Class[].class); + ResultHandle paramTypes = bytecode.newArray(Class.class, 1); + bytecode.writeArrayValue(paramTypes, 0, bytecode.loadClass(listType.name().toString())); + yield bytecode.invokeVirtualMethod(constructParametricType, typeFactory, + bytecode.loadClass(fieldTypeName), paramTypes); } case MAP -> { Type keyType = ((ParameterizedType) fieldType).arguments().get(0); @@ -466,10 +463,13 @@ private ResultHandle readValueFromJson(ClassCreator classCreator, BytecodeCreato MethodDescriptor getTypeFactory = ofMethod(DeserializationContext.class, "getTypeFactory", TypeFactory.class); ResultHandle typeFactory = bytecode.invokeVirtualMethod(getTypeFactory, deserializationContext); - MethodDescriptor constructMapType = ofMethod(TypeFactory.class, "constructMapType", - MapType.class, Class.class, Class.class, Class.class); - yield bytecode.invokeVirtualMethod(constructMapType, typeFactory, bytecode.loadClass(HashMap.class), - bytecode.loadClass(keyType.name().toString()), bytecode.loadClass(valueType.name().toString())); + MethodDescriptor constructParametricType = ofMethod(TypeFactory.class, + "constructParametricType", JavaType.class, Class.class, Class[].class); + ResultHandle paramTypes = bytecode.newArray(Class.class, 2); + bytecode.writeArrayValue(paramTypes, 0, bytecode.loadClass(keyType.name().toString())); + bytecode.writeArrayValue(paramTypes, 1, bytecode.loadClass(valueType.name().toString())); + yield bytecode.invokeVirtualMethod(constructParametricType, typeFactory, + bytecode.loadClass(fieldTypeName), paramTypes); } default -> bytecode.loadClass(fieldTypeName); }; @@ -483,17 +483,6 @@ private ResultHandle readValueFromJson(ClassCreator classCreator, BytecodeCreato return bytecode.invokeVirtualMethod(readTreeAsValue, deserializationContext, valueNode, typeHandle); } - private static Class concreteCollectionType(String fieldTypeName, FieldKind fieldKind) { - try { - Class declared = Class.forName(fieldTypeName); - if (!declared.isInterface() && !Modifier.isAbstract(declared.getModifiers())) { - return declared; - } - } catch (ClassNotFoundException ignored) { - } - return fieldKind == FieldKind.SET ? HashSet.class : ArrayList.class; - } - private void writeValueToObject(ClassInfo classInfo, ResultHandle objHandle, FieldSpecs fieldSpecs, BytecodeCreator bytecode, ResultHandle valueHandle) { if (fieldSpecs.isPublicField()) { diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/AbstractSimpleJsonTest.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/AbstractSimpleJsonTest.java index 8bd22ff14d424..9e32e5c0b6f2d 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/AbstractSimpleJsonTest.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/AbstractSimpleJsonTest.java @@ -1032,6 +1032,19 @@ void testShouldDeserializePolymorphicItems() { .body("values", CoreMatchers.is("world")); } + @Test + void testShouldDeserializeAbstractList() { + RestAssured + .with() + .body("{\"items\": [{\"name\": \"world\"}]}") + .contentType("application/json; charset=utf-8") + .post("/simple/deque-batch") + .then() + .statusCode(200) + .contentType("application/json") + .body("values", CoreMatchers.is("world")); + } + @Test void testShouldRejectUnknownFields() { RestAssured diff --git a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java index c4662f18bb34c..3c363b2005793 100644 --- a/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java +++ b/extensions/resteasy-reactive/rest-jackson/deployment/src/test/java/io/quarkus/resteasy/reactive/jackson/deployment/test/SimpleJsonResource.java @@ -4,6 +4,7 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; +import java.util.Deque; import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; @@ -606,6 +607,9 @@ public record GreetingRequest(@JsonProperty("name") String name) { public record LinkedListBatchRequest(@JsonProperty("items") LinkedList items) { } + public record DequeBatchRequest(@JsonProperty("items") Deque items) { + } + @POST @Path("/linkedlist-batch") @Produces(MediaType.APPLICATION_JSON) @@ -616,6 +620,16 @@ public String linkedListBatch(LinkedListBatchRequest request) { return "{\"values\":\"" + values + "\"}"; } + @POST + @Path("/deque-batch") + @Produces(MediaType.APPLICATION_JSON) + public String dequeBatch(DequeBatchRequest request) { + String values = request.items().stream() + .map(GreetingRequest::name) + .collect(Collectors.joining(",")); + return "{\"values\":\"" + values + "\"}"; + } + @POST @Path("/greeting") public String greeting(GreetingRequest request) {