From 4e94c0ed9eca0caccb57feb0ceb252fc91198032 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Tue, 4 Oct 2016 16:07:13 -0700 Subject: [PATCH] Fix #1392 for 2.7.9 / 2.8.4 --- release-notes/VERSION | 5 +++ .../databind/deser/BeanDeserializerBase.java | 1 + .../databind/deser/ValueInstantiator.java | 10 ++++-- .../deser/std/CollectionDeserializer.java | 32 ++++++++++++------- .../deser/std/StdValueInstantiator.java | 16 +++++++--- ...rayDelegatorCreatorForCollectionTest.java} | 4 +-- 6 files changed, 48 insertions(+), 20 deletions(-) rename src/test/java/com/fasterxml/jackson/{failing/UnmodifiableSetTyping1392Test.java => databind/creators/ArrayDelegatorCreatorForCollectionTest.java} (88%) diff --git a/release-notes/VERSION b/release-notes/VERSION index 99d94aee9c..efe4d13922 100644 --- a/release-notes/VERSION +++ b/release-notes/VERSION @@ -4,6 +4,11 @@ Project: jackson-databind === Releases === ------------------------------------------------------------------------ +2.7.9 (not yet released) + +#1392: Custom UnmodifiableSetMixin Fails in Jackson 2.7+ but works in Jackson 2.6 + (reported by Rob W) + 2.7.8 (26-Sep-2016) #877: @JsonIgnoreProperties`: ignoring the "cause" property of `Throwable` on GAE diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java index 48cadfc714..05240d6b2f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java @@ -228,6 +228,7 @@ protected BeanDeserializerBase(BeanDeserializerBuilder builder, _objectIdReader = builder.getObjectIdReader(); _nonStandardCreation = (_unwrappedPropertyHandler != null) || _valueInstantiator.canCreateUsingDelegate() + || _valueInstantiator.canCreateUsingArrayDelegate() // new in 2.7 || _valueInstantiator.canCreateFromObjectWith() || !_valueInstantiator.canCreateUsingDefault() ; diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java b/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java index a0db47e7ff..522faceaf8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/ValueInstantiator.java @@ -53,7 +53,7 @@ public boolean canInstantiate() { || canCreateFromInt() || canCreateFromLong() || canCreateFromDouble() || canCreateFromBoolean(); } - + /** * Method that can be called to check whether a String-based creator * is available for this instantiator @@ -83,7 +83,7 @@ public boolean canInstantiate() { * creator is available to use (to call {@link #createFromDouble}). */ public boolean canCreateFromBoolean() { return false; } - + /** * Method that can be called to check whether a default creator (constructor, * or no-arg static factory method) @@ -102,6 +102,8 @@ public boolean canInstantiate() { * Method that can be called to check whether a array-delegate-based creator * (single-arg constructor or factory method) * is available for this instantiator + * + * @since 2.7 */ public boolean canCreateUsingArrayDelegate() { return false; } @@ -141,9 +143,11 @@ public SettableBeanProperty[] getFromObjectArguments(DeserializationConfig confi * non-null type is returned, deserializer will bind JSON into specified * type (using standard deserializer for that type), and pass that to * instantiator. + * + * @since 2.7 */ public JavaType getArrayDelegateType(DeserializationConfig config) { return null; } - + /* /********************************************************** /* Instantiation methods for JSON Object diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java index 021860310a..33d8878e30 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/CollectionDeserializer.java @@ -172,14 +172,24 @@ public CollectionDeserializer createContextual(DeserializationContext ctxt, { // May need to resolve types for delegate-based creators: JsonDeserializer delegateDeser = null; - if ((_valueInstantiator != null) && _valueInstantiator.canCreateUsingDelegate()) { - JavaType delegateType = _valueInstantiator.getDelegateType(ctxt.getConfig()); - if (delegateType == null) { - throw new IllegalArgumentException("Invalid delegate-creator definition for "+_collectionType - +": value instantiator ("+_valueInstantiator.getClass().getName() - +") returned true for 'canCreateUsingDelegate()', but null for 'getDelegateType()'"); + if (_valueInstantiator != null) { + if (_valueInstantiator.canCreateUsingDelegate()) { + JavaType delegateType = _valueInstantiator.getDelegateType(ctxt.getConfig()); + if (delegateType == null) { + throw new IllegalArgumentException("Invalid delegate-creator definition for "+_collectionType + +": value instantiator ("+_valueInstantiator.getClass().getName() + +") returned true for 'canCreateUsingDelegate()', but null for 'getDelegateType()'"); + } + delegateDeser = findDeserializer(ctxt, delegateType, property); + } else if (_valueInstantiator.canCreateUsingArrayDelegate()) { + JavaType delegateType = _valueInstantiator.getArrayDelegateType(ctxt.getConfig()); + if (delegateType == null) { + throw new IllegalArgumentException("Invalid array-delegate-creator definition for "+_collectionType + +": value instantiator ("+_valueInstantiator.getClass().getName() + +") returned true for 'canCreateUsingArrayDelegate()', but null for 'getArrayDelegateType()'"); + } + delegateDeser = findDeserializer(ctxt, delegateType, property); } - delegateDeser = findDeserializer(ctxt, delegateType, property); } // [databind#1043]: allow per-property allow-wrapping of single overrides: // 11-Dec-2015, tatu: Should we pass basic `Collection.class`, or more refined? Mostly @@ -204,7 +214,7 @@ public CollectionDeserializer createContextual(DeserializationContext ctxt, } return withResolved(delegateDeser, valueDeser, valueTypeDeser, unwrapSingle); } - + /* /********************************************************** /* ContainerDeserializerBase API @@ -236,9 +246,9 @@ public Collection deserialize(JsonParser p, DeserializationContext ctxt) return (Collection) _valueInstantiator.createUsingDelegate(ctxt, _delegateDeserializer.deserialize(p, ctxt)); } - /* [JACKSON-620]: empty String may be ok; bit tricky to check, however, since - * there is also possibility of "auto-wrapping" of single-element arrays. - * Hence we only accept empty String here. + /* Empty String may be ok; bit tricky to check, however, since + * there is also possibility of "auto-wrapping" of single-element arrays. + * Hence we only accept empty String here. */ if (p.hasToken(JsonToken.VALUE_STRING)) { String str = p.getText(); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java index 991d6e3496..b833fe9ea6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdValueInstantiator.java @@ -262,19 +262,27 @@ public Object createFromObjectWith(DeserializationContext ctxt, Object[] args) t @Override public Object createUsingDelegate(DeserializationContext ctxt, Object delegate) throws IOException { + // 04-Oct-2016, tatu: Need delegation to work around [databind#1392]... + if (_delegateCreator == null) { + if (_arrayDelegateCreator != null) { + return _createUsingDelegate(_arrayDelegateCreator, _arrayDelegateArguments, ctxt, delegate); + } + } return _createUsingDelegate(_delegateCreator, _delegateArguments, ctxt, delegate); } @Override public Object createUsingArrayDelegate(DeserializationContext ctxt, Object delegate) throws IOException { - if (_arrayDelegateCreator == null) { // sanity-check; caller should check - // fallback to the classic delegate creator - return createUsingDelegate(ctxt, delegate); + if (_arrayDelegateCreator == null) { + if (_delegateCreator != null) { // sanity-check; caller should check + // fallback to the classic delegate creator + return createUsingDelegate(ctxt, delegate); + } } return _createUsingDelegate(_arrayDelegateCreator, _arrayDelegateArguments, ctxt, delegate); } - + /* /********************************************************** /* Public API implementation; instantiation from JSON scalars diff --git a/src/test/java/com/fasterxml/jackson/failing/UnmodifiableSetTyping1392Test.java b/src/test/java/com/fasterxml/jackson/databind/creators/ArrayDelegatorCreatorForCollectionTest.java similarity index 88% rename from src/test/java/com/fasterxml/jackson/failing/UnmodifiableSetTyping1392Test.java rename to src/test/java/com/fasterxml/jackson/databind/creators/ArrayDelegatorCreatorForCollectionTest.java index 8b371fa206..c0cb961816 100644 --- a/src/test/java/com/fasterxml/jackson/failing/UnmodifiableSetTyping1392Test.java +++ b/src/test/java/com/fasterxml/jackson/databind/creators/ArrayDelegatorCreatorForCollectionTest.java @@ -1,4 +1,4 @@ -package com.fasterxml.jackson.failing; +package com.fasterxml.jackson.databind.creators; import java.util.Collections; import java.util.Set; @@ -7,7 +7,7 @@ import com.fasterxml.jackson.databind.*; -public class UnmodifiableSetTyping1392Test extends BaseMapTest +public class ArrayDelegatorCreatorForCollectionTest extends BaseMapTest { @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY) abstract static class UnmodifiableSetMixin {