diff --git a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java index aea47243a02fc..6d2107a8c2978 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/recording/BytecodeRecorderImpl.java @@ -1103,8 +1103,8 @@ private DeferredParameter loadComplexObject(Object param, Map setupSteps = new ArrayList<>(); - List ctorSetupSteps = new ArrayList<>(); + List setupSteps = new ArrayList<>(); + List ctorSetupSteps = new ArrayList<>(); boolean relaxedOk = false; if (param instanceof Collection) { @@ -1113,7 +1113,7 @@ private DeferredParameter loadComplexObject(Object param, Map context.loadDeferred(m)) .toArray(ResultHandle[]::new)); } else { - try { - param.getClass().getDeclaredConstructor(); - out = method.newInstance(ofConstructor(param.getClass())); - } catch (NoSuchMethodException e) { - //fallback for collection types, such as unmodifiableMap - if (SortedMap.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(TreeMap.class)); - } else if (Map.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(LinkedHashMap.class)); - } else if (List.class.isAssignableFrom(expectedType)) { + if (List.class.isAssignableFrom(param.getClass())) { + // list is a common special case, so let's handle it + List listParam = (List) param; + if (listParam.isEmpty()) { out = method.newInstance(ofConstructor(ArrayList.class)); - } else if (SortedSet.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(TreeSet.class)); - } else if (Set.class.isAssignableFrom(expectedType)) { - out = method.newInstance(ofConstructor(LinkedHashSet.class)); } else { - throw new RuntimeException("Unable to serialize objects of type " + param.getClass() - + " to bytecode as it has no default constructor"); + out = method.newInstance(ofConstructor(ArrayList.class, int.class), method.load(listParam.size())); + } + } else { + try { + param.getClass().getDeclaredConstructor(); + out = method.newInstance(ofConstructor(param.getClass())); + } catch (NoSuchMethodException e) { + //fallback for collection types, such as unmodifiableMap + if (SortedMap.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(TreeMap.class)); + } else if (Map.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(LinkedHashMap.class)); + } else if (List.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(ArrayList.class)); + } else if (SortedSet.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(TreeSet.class)); + } else if (Set.class.isAssignableFrom(expectedType)) { + out = method.newInstance(ofConstructor(LinkedHashSet.class)); + } else { + throw new RuntimeException("Unable to serialize objects of type " + param.getClass() + + " to bytecode as it has no default constructor"); + } } } } @@ -1477,15 +1487,15 @@ ResultHandle createValue(MethodContext context, MethodCreator method, ResultHand void doPrepare(MethodContext context) { //this is where the object construction happens //first create the actial object - for (SerialzationStep i : ctorSetupSteps) { + for (SerializationStep i : ctorSetupSteps) { i.prepare(context); } objectValue.prepare(context); - for (SerialzationStep i : setupSteps) { + for (SerializationStep i : setupSteps) { //then prepare the steps (i.e. creating the values to be placed into this object) i.prepare(context); } - for (SerialzationStep i : setupSteps) { + for (SerializationStep i : setupSteps) { //now actually run the steps (i.e. actually stick the values into the object) context.writeInstruction(new InstructionGroup() { @Override @@ -1792,7 +1802,7 @@ final ResultHandle doLoad(MethodContext context, MethodCreator method, ResultHan /** * A step that must be executed to serialize a complex object */ - interface SerialzationStep { + interface SerializationStep { void handle(MethodContext context, MethodCreator method, DeferredArrayStoreParameter out);