From 6f4f48ea1eb6a3c36c1a9403b8bed73e80bbd830 Mon Sep 17 00:00:00 2001 From: Thomas Deblock Date: Tue, 30 Jan 2018 09:40:35 +0100 Subject: [PATCH 1/2] Fix #1912 Remove usage of _neitherNull on findProperty to get custom property if possible. --- .../databind/deser/BeanDeserializerBase.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 2315960bef..cefa096e6e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java @@ -261,7 +261,7 @@ protected BeanDeserializerBase(BeanDeserializerBase src, boolean ignoreAllUnknow _vanillaProcessing = src._vanillaProcessing; } - + protected BeanDeserializerBase(BeanDeserializerBase src, NameTransformer unwrapper) { super(src._beanType); @@ -415,7 +415,7 @@ public BeanDeserializerBase withBeanProperties(BeanPropertyMap props) { * Fluent factory for creating a variant that can handle * POJO output as a JSON Array. Implementations may ignore this request * if no such input is possible. - * + * * @since 2.1 */ protected abstract BeanDeserializerBase asArrayDeserializer(); @@ -644,7 +644,7 @@ private JsonDeserializer _findDelegateDeserializer(DeserializationContex *

* NOTE: returned deserializer is NOT yet contextualized, caller needs to take * care to do that. - * + * * @since 2.2 */ protected JsonDeserializer findConvertingDeserializer(DeserializationContext ctxt, @@ -665,7 +665,7 @@ protected JsonDeserializer findConvertingDeserializer(DeserializationCon } return null; } - + /** * Although most of post-processing is done in resolve(), we only get * access to referring property's annotations here; and this is needed @@ -1026,7 +1026,7 @@ public Iterator properties() * Accessor for finding properties that represents values to pass * through property-based creator method (constructor or * factory method) - * + * * @since 2.0 */ public Iterator creatorProperties() @@ -1047,14 +1047,14 @@ public SettableBeanProperty findProperty(PropertyName propertyName) * Accessor for finding the property with given name, if POJO * has one. Name used is the external name, i.e. name used * in external data representation (JSON). - * + * * @since 2.0 */ public SettableBeanProperty findProperty(String propertyName) { SettableBeanProperty prop = (_beanProperties == null) ? null : _beanProperties.find(propertyName); - if (_neitherNull(prop, _propertyBasedCreator)) { + if (prop == null && _propertyBasedCreator != null) { prop = _propertyBasedCreator.findCreatorProperty(propertyName); } return prop; @@ -1067,14 +1067,14 @@ public SettableBeanProperty findProperty(String propertyName) * since properties are not directly indexable; however, for most * instances difference is not significant as number of properties * is low. - * + * * @since 2.3 */ public SettableBeanProperty findProperty(int propertyIndex) { SettableBeanProperty prop = (_beanProperties == null) ? null : _beanProperties.find(propertyIndex); - if (_neitherNull(prop, _propertyBasedCreator)) { + if (prop == null && _propertyBasedCreator != null) { prop = _propertyBasedCreator.findCreatorProperty(propertyIndex); } return prop; @@ -1113,7 +1113,7 @@ public ValueInstantiator getValueInstantiator() { * * @param original Property to replace * @param replacement Property to replace it with - * + * * @since 2.1 */ public void replaceProperty(SettableBeanProperty original, @@ -1585,7 +1585,7 @@ protected void handleUnknownProperty(JsonParser p, DeserializationContext ctxt, /** * Method called when an explicitly ignored property (one specified with a * name to match, either by property annotation or class annotation) is encountered. - * + * * @since 2.3 */ protected void handleIgnoredProperty(JsonParser p, DeserializationContext ctxt, From 5071f960c7055600e209075aecd810e4d68aa4ef Mon Sep 17 00:00:00 2001 From: Thomas Deblock Date: Wed, 31 Jan 2018 12:19:27 +0100 Subject: [PATCH 2/2] [#1912] add unit test --- .../databind/deser/TestBeanDeserializer.java | 99 ++++++++++++++++++- 1 file changed, 95 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java b/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java index ae221094d8..988ece38d2 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/TestBeanDeserializer.java @@ -3,11 +3,10 @@ import java.io.IOException; import java.util.*; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; -import com.fasterxml.jackson.databind.deser.BeanDeserializer; -import com.fasterxml.jackson.databind.deser.BeanDeserializerBuilder; -import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; @@ -139,7 +138,92 @@ public void setupModule(SetupContext context) { context.addBeanDeserializerModifier(new Issue476DeserializerModifier()); } } - + + public static class Issue1912Bean { + public Issue1912SubBean subBean; + + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) // This is need to populate _propertyBasedCreator on BeanDeserializerBase + public Issue1912Bean(@JsonProperty("subBean") Issue1912SubBean subBean) { + this.subBean = subBean; + } + } + public static class Issue1912SubBean { + public String a; + + public Issue1912SubBean() { } + + public Issue1912SubBean(String a) { + this.a = a; + } + } + + public static class Issue1912CustomBeanDeserializer extends JsonDeserializer { + private BeanDeserializer defaultDeserializer; + + public Issue1912CustomBeanDeserializer(BeanDeserializer defaultDeserializer) { + this.defaultDeserializer = defaultDeserializer; + } + + @Override + public Issue1912Bean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + // this is need on some cases, this populate _propertyBasedCreator + defaultDeserializer.resolve(ctxt); + + p.nextFieldName(); // read subBean + p.nextToken(); // read start object + + Issue1912SubBean subBean = (Issue1912SubBean) defaultDeserializer.findProperty("subBean").deserialize(p, ctxt); + + return new Issue1912Bean(subBean); + } + } + + public static class Issue1912CustomPropertyDeserializer extends JsonDeserializer { + + @Override + public Issue1912SubBean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + p.nextFieldName(); // read "a" + Issue1912SubBean object = new Issue1912SubBean(p.nextTextValue() + "_custom"); + p.nextToken(); + return object; + } + } + public static class Issue1912UseAddOrReplacePropertyDeserializerModifier extends BeanDeserializerModifier { + + @Override + public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer deserializer) { + if (beanDesc.getBeanClass() == Issue1912Bean.class) { + return new Issue1912CustomBeanDeserializer((BeanDeserializer) deserializer); + } + return super.modifyDeserializer(config, beanDesc, deserializer); + } + + @Override + public BeanDeserializerBuilder updateBuilder(DeserializationConfig config, BeanDescription beanDesc, BeanDeserializerBuilder builder) { + if (beanDesc.getBeanClass() == Issue1912Bean.class) { + Iterator props = builder.getProperties(); + while (props.hasNext()) { + SettableBeanProperty prop = props.next(); + SettableBeanProperty propWithCustomDeserializer = prop.withValueDeserializer(new Issue1912CustomPropertyDeserializer()); + builder.addOrReplaceProperty(propWithCustomDeserializer, true); + } + } + + return builder; + } + } + public class Issue1912Module extends SimpleModule { + + public Issue1912Module() { + super("Issue1912Module", Version.unknownVersion()); + } + + @Override + public void setupModule(SetupContext context) { + context.addBeanDeserializerModifier(new Issue1912UseAddOrReplacePropertyDeserializerModifier()); + } + } + // [Issue#121], arrays, collections, maps enum EnumABC { A, B, C; } @@ -380,4 +464,11 @@ public JsonDeserializer modifyDeserializer(DeserializationConfig config, assertEquals("ABCDEF", result); } + public void testAddOrReplacePropertyIsUsedOnDeserialization() throws Exception { + ObjectMapper mapper = new ObjectMapper(); + mapper.registerModule(new Issue1912Module()); + + Issue1912Bean result = mapper.readValue("{\"subBean\": {\"a\":\"foo\"}}", Issue1912Bean.class); + assertEquals("foo_custom", result.subBean.a); + } }