diff --git a/release-notes/CREDITS-2.x b/release-notes/CREDITS-2.x index 7af3dee2de..b5a89511b1 100644 --- a/release-notes/CREDITS-2.x +++ b/release-notes/CREDITS-2.x @@ -842,3 +842,7 @@ Cyril Martin (mcoolive@github.com) * Reported #2303: Deserialize null, when java type is "TypeRef of TypeRef of T", does not provide "Type(Type(null))" (2.9.9) + +Daniil Barvitsky (dbarvitsky@github( + * Reported #2324: `StringCollectionDeserializer` fails with custom collection + (2.9.9) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 720082a718..024d8f209e 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -18,6 +18,8 @@ Project: jackson-databind (contributed by Christoph F) #2303: Deserialize null, when java type is "TypeRef of TypeRef of T", does not provide "Type(Type(null))" (reported by Cyril M) +#2324: `StringCollectionDeserializer` fails with custom collection + (reported byb Daniil B) - Prevent String coercion of `null` in `WritableObjectId` when calling `JsonGenerator.writeObjectId()`, mostly relevant for formats like YAML that have native Object Ids diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java index 321df6f294..0bf2e12a1f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringCollectionDeserializer.java @@ -103,8 +103,12 @@ public JsonDeserializer createContextual(DeserializationContext ctxt, // May need to resolve types for delegate-based creators: JsonDeserializer delegate = null; if (_valueInstantiator != null) { - AnnotatedWithParams delegateCreator = _valueInstantiator.getDelegateCreator(); + // [databind#2324]: check both array-delegating and delegating + AnnotatedWithParams delegateCreator = _valueInstantiator.getArrayDelegateCreator(); if (delegateCreator != null) { + JavaType delegateType = _valueInstantiator.getArrayDelegateType(ctxt.getConfig()); + delegate = findDeserializer(ctxt, delegateType, property); + } else if ((delegateCreator = _valueInstantiator.getDelegateCreator()) != null) { JavaType delegateType = _valueInstantiator.getDelegateType(ctxt.getConfig()); delegate = findDeserializer(ctxt, delegateType, property); } diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingArrayCreator2324Test.java b/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingArrayCreator2324Test.java new file mode 100644 index 0000000000..18882cb490 --- /dev/null +++ b/src/test/java/com/fasterxml/jackson/databind/deser/creators/DelegatingArrayCreator2324Test.java @@ -0,0 +1,70 @@ +package com.fasterxml.jackson.databind.deser.creators; + +import java.util.AbstractCollection; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; + +// for [databind#2324] +public class DelegatingArrayCreator2324Test extends BaseMapTest +{ + @JsonDeserialize(as=ImmutableBag.class) + public interface Bag extends Collection { } + + public static class ImmutableBag extends AbstractCollection implements Bag { + @Override + public Iterator iterator() { return elements.iterator(); } + + @Override + public int size() { return elements.size(); } + + @JsonCreator(mode=JsonCreator.Mode.DELEGATING) + private ImmutableBag(Collection elements ) { + this.elements = Collections.unmodifiableCollection(elements); + } + + private final Collection elements; + } + + static class Value { + public String value; + + public Value(String v) { value = v; } + + @Override + public boolean equals(Object o) { + return value.equals(((Value) o).value); + } + } + + static class WithBagOfStrings { + public Bag getStrings() { return this.bagOfStrings; } + public void setStrings(Bag bagOfStrings) { this.bagOfStrings = bagOfStrings; } + private Bag bagOfStrings; + } + + static class WithBagOfValues { + public Bag getValues() { return this.bagOfValues; } + public void setValues(Bag bagOfValues) { this.bagOfValues = bagOfValues; } + private Bag bagOfValues; + } + + private final ObjectMapper MAPPER = objectMapper(); + + public void testDeserializeBagOfStrings() throws Exception { + WithBagOfStrings result = MAPPER.readerFor(WithBagOfStrings.class) + .readValue("{\"strings\": [ \"a\", \"b\", \"c\"]}"); + assertEquals(3, result.getStrings().size()); + } + + public void testDeserializeBagOfPOJOs() throws Exception { + WithBagOfValues result = MAPPER.readerFor(WithBagOfValues.class) + .readValue("{\"values\": [ \"a\", \"b\", \"c\"]}"); + assertEquals(3, result.getValues().size()); + assertEquals(new Value("a"), result.getValues().iterator().next()); + } +}