diff options
author | Tatu Saloranta <tatu.saloranta@iki.fi> | 2016-10-23 20:35:26 -0700 |
---|---|---|
committer | Tatu Saloranta <tatu.saloranta@iki.fi> | 2016-10-23 20:35:26 -0700 |
commit | 55f3086e0402de0754ae236d6ad42aa6b8d1004a (patch) | |
tree | beb87b29db9063b7154fb46c02ae09af372a2076 | |
parent | 0185aefae0b319002ed1f01e61412261b38c4628 (diff) | |
download | jackson-databind-55f3086e0402de0754ae236d6ad42aa6b8d1004a.tar.gz |
yet more work on merging; avoid unnecessary set
19 files changed, 265 insertions, 38 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java index 068c83d9c..f2806835a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java @@ -331,6 +331,29 @@ public abstract class JsonDeserializer<T> +"': type: value deserializer of type "+getClass().getName()+" does not support them"); } + /** + * Introspection method that may be called to see whether deserializer supports + * update of an existing value (aka "merging") or not. Return value should either + * be {@link Boolean#FALSE} if update is not supported at all (immutable values); + * {@link Boolean#TRUE} if update should usually work (regular POJOs, for example), + * or <code>null</code> if this is either not known, or may sometimes work. + *<p> + * Information gathered is typically used to either prevent merging update for + * property (either by skipping, if based on global defaults; or by exception during + * deserialization construction if explicit attempt made) if {@link Boolean#FALSE} + * returned, or inclusion if {@link Boolean#TRUE} is specified. If "unknown" case + * (<code>null</code> returned) behavior is to exclude property if global defaults + * used; or to allow if explicit per-type or property merging is defined. + *<p> + * Default implementation returns <code>null</code> to allow explicit per-type + * or per-property attempts. + * + * @since 2.9 + */ + public Boolean supportsUpdate(DeserializationConfig config) { + return null; + } + /* /********************************************************** /* Deprecated methods diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/AbstractDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/AbstractDeserializer.java index d00a9318f..c6cfeb37e 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/AbstractDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/AbstractDeserializer.java @@ -82,7 +82,17 @@ public class AbstractDeserializer @Override public boolean isCachable() { return true; } - + + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + /* 23-Oct-2016, tatu: Not exactly sure what to do with this; polymorphic + * type handling seems bit risky so for now claim it "may or may not be" + * possible, which does allow explicit per-type/per-property merging attempts, + * but avoids general-configuration merges + */ + return null; + } + /** * Overridden to return true for those instances that are * handling value for which Object Identity handling is enabled 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 9df98f52e..cc43b53ed 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java @@ -881,6 +881,14 @@ public abstract class BeanDeserializerBase @Override public boolean isCachable() { return true; } + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + // although with possible caveats, yes, values can be updated + // 23-Oct-2016, tatu: Perhaps in future could and should verify from + // bean settings... + return Boolean.TRUE; + } + @Override public Class<?> handledType() { return _beanType.getRawClass(); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java index 0db8c4c7c..9df6742bd 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/FailingDeserializer.java @@ -1,5 +1,7 @@ package com.fasterxml.jackson.databind.deser.impl; +import java.io.IOException; + import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonMappingException; @@ -23,7 +25,7 @@ public class FailingDeserializer extends StdDeserializer<Object> } @Override - public Object deserialize(JsonParser p, DeserializationContext ctxt) throws JsonMappingException{ + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { ctxt.reportInputMismatch(this, _message); return null; } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/MergingSettableBeanProperty.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/MergingSettableBeanProperty.java index 37fa2f55e..133f67180 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/MergingSettableBeanProperty.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/MergingSettableBeanProperty.java @@ -66,13 +66,40 @@ public class MergingSettableBeanProperty public void deserializeAndSet(JsonParser p, DeserializationContext ctxt, Object instance) throws IOException { - delegate.set(instance, _deserialize(p, ctxt, instance)); + Object oldValue = _accessor.getValue(instance); + Object newValue; + // 20-Oct-2016, tatu: Couple of possibilities of how to proceed; for + // now, default to "normal" handling without merging + if (oldValue == null) { + newValue = delegate.deserialize(p, ctxt); + } else { + newValue = delegate.deserializeWith(p, ctxt, oldValue); + } + if (newValue != oldValue) { + delegate.set(instance, newValue); + } } @Override public Object deserializeSetAndReturn(JsonParser p, - DeserializationContext ctxt, Object instance) throws IOException { - return delegate.setAndReturn(instance, _deserialize(p, ctxt, instance)); + DeserializationContext ctxt, Object instance) throws IOException + { + Object oldValue = _accessor.getValue(instance); + Object newValue; + // 20-Oct-2016, tatu: Couple of possibilities of how to proceed; for + // now, default to "normal" handling without merging + if (oldValue == null) { + newValue = delegate.deserialize(p, ctxt); + } else { + newValue = delegate.deserializeWith(p, ctxt, oldValue); + } + // 23-Oct-2016, tatu: One possible complication here; should we always + // try calling setter on builder? Presumably should not be required, + // but may need to revise + if (newValue != oldValue) { + return delegate.setAndReturn(instance, newValue); + } + return instance; } @Override @@ -86,19 +113,4 @@ public class MergingSettableBeanProperty { return delegate.setAndReturn(instance, value); } - - protected Object _deserialize(JsonParser p, DeserializationContext ctxt, - Object instance) throws IOException - { - Object value = _accessor.getValue(instance); - // 20-Oct-2016, tatu: Couple of possibilities of how to proceed; for - // now, default to "normal" handling without merging - if (value == null) { - return delegate.deserialize(p, ctxt); - } - Object result = delegate.deserializeWith(p, ctxt, value); - // 20-Oct-2016, tatu: Similarly, we may get same object or different one; - // whether to return original or new is an open question. - return result; - } } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/impl/TypeWrappedDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/impl/TypeWrappedDeserializer.java index 0f23fd1ac..8d5039de6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/impl/TypeWrappedDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/impl/TypeWrappedDeserializer.java @@ -37,6 +37,11 @@ public final class TypeWrappedDeserializer return _deserializer.handledType(); } + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return _deserializer.supportsUpdate(config); + } + @Override public JsonDeserializer<?> getDelegatee() { return _deserializer.getDelegatee(); @@ -58,13 +63,13 @@ public final class TypeWrappedDeserializer } @Override - public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - return _deserializer.deserializeWithType(jp, ctxt, _typeDeserializer); + return _deserializer.deserializeWithType(p, ctxt, _typeDeserializer); } @Override - public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, + public Object deserializeWithType(JsonParser p, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException { // should never happen? (if it can, could call on that object) @@ -72,12 +77,12 @@ public final class TypeWrappedDeserializer } @Override - public Object deserialize(JsonParser jp, DeserializationContext ctxt, + public Object deserialize(JsonParser p, DeserializationContext ctxt, Object intoValue) throws IOException { /* 01-Mar-2013, tatu: Hmmh. Tough call as to what to do... need * to delegate, but will this work reliably? Let's just hope so: */ - return _deserializer.deserialize(jp, ctxt, intoValue); + return _deserializer.deserialize(p, ctxt, intoValue); } -}
\ No newline at end of file +} diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/AtomicReferenceDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/AtomicReferenceDeserializer.java index 7fe40402b..b7d00300f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/AtomicReferenceDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/AtomicReferenceDeserializer.java @@ -25,7 +25,7 @@ public class AtomicReferenceDeserializer { super(fullType, inst, typeDeser, deser); } - + /* /********************************************************** /* Abstract method implementations diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/ContainerDeserializerBase.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/ContainerDeserializerBase.java index 6b53a29c0..0860a2662 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/ContainerDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/ContainerDeserializerBase.java @@ -3,6 +3,7 @@ package com.fasterxml.jackson.databind.deser.std; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.JsonMappingException; @@ -27,6 +28,13 @@ public abstract class ContainerDeserializerBase<T> /********************************************************** */ + @Override // since 2.9 + public final Boolean supportsUpdate(DeserializationConfig config) { + // 23-Oct-2016, tatu: Most if not all containers should support merges + // so let's default to that: + return Boolean.TRUE; + } + @Override public SettableBeanProperty findBackReference(String refName) { JsonDeserializer<Object> valueDeser = getContentDeserializer(); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumSetDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumSetDeserializer.java index 213621098..3f1af30bb 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumSetDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/EnumSetDeserializer.java @@ -96,7 +96,12 @@ public class EnumSetDeserializer } return true; } - + + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return Boolean.TRUE; + } + @Override public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException @@ -118,15 +123,32 @@ public class EnumSetDeserializer /********************************************************** */ - @SuppressWarnings("unchecked") @Override public EnumSet<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + EnumSet result = constructSet(); // Ok: must point to START_ARRAY (or equivalent) if (!p.isExpectedStartArrayToken()) { - return handleNonArray(p, ctxt); + return handleNonArray(p, ctxt, result); } - EnumSet result = constructSet(); + return _deserialize(p, ctxt, result); + } + + @Override + public EnumSet<?> deserialize(JsonParser p, DeserializationContext ctxt, + EnumSet<?> result) throws IOException + { + // Ok: must point to START_ARRAY (or equivalent) + if (!p.isExpectedStartArrayToken()) { + return handleNonArray(p, ctxt, result); + } + return _deserialize(p, ctxt, result); + } + + @SuppressWarnings("unchecked") + protected final EnumSet<?> _deserialize(JsonParser p, DeserializationContext ctxt, + EnumSet result) throws IOException + { JsonToken t; try { @@ -164,12 +186,12 @@ public class EnumSetDeserializer @SuppressWarnings("unchecked") private EnumSet constructSet() { - // superbly ugly... but apparently necessary return EnumSet.noneOf(_enumClass); } @SuppressWarnings("unchecked") - protected EnumSet<?> handleNonArray(JsonParser p, DeserializationContext ctxt) + protected EnumSet<?> handleNonArray(JsonParser p, DeserializationContext ctxt, + EnumSet result) throws IOException { boolean canWrap = (_unwrapSingle == Boolean.TRUE) || @@ -179,8 +201,6 @@ public class EnumSetDeserializer if (!canWrap) { return (EnumSet<?>) ctxt.handleUnexpectedToken(EnumSet.class, p); } - - EnumSet result = constructSet(); // First: since `null`s not allowed, slightly simpler... if (p.hasToken(JsonToken.VALUE_NULL)) { return (EnumSet<?>) ctxt.handleUnexpectedToken(_enumClass, p); diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/FactoryBasedEnumDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/FactoryBasedEnumDeserializer.java index cf4096b66..b840ff0aa 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/FactoryBasedEnumDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/FactoryBasedEnumDeserializer.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonToken; import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; @@ -99,6 +100,11 @@ class FactoryBasedEnumDeserializer return this; } + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return Boolean.FALSE; + } + @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java index 71e19003c..4a3e60365 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java @@ -158,6 +158,14 @@ abstract class BaseNodeDeserializer<T extends JsonNode> @Override public boolean isCachable() { return true; } + /* 23-Oct-2016, tatu: Certain subtypes (Array, Object) actually do support + * updates, but default to false; can be improved in future. + */ + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return Boolean.FALSE; + } + /* /********************************************************** /* Overridable methods diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/NullifyingDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/NullifyingDeserializer.java index 04535951d..e2d1b8ad8 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/NullifyingDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/NullifyingDeserializer.java @@ -26,7 +26,12 @@ public class NullifyingDeserializer /* Deserializer API /********************************************************** */ - + + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return Boolean.FALSE; + } + @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java index 109303e0e..381bdc723 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/PrimitiveArrayDeserializers.java @@ -72,6 +72,12 @@ public abstract class PrimitiveArrayDeserializers<T> extends StdDeserializer<T> throw new IllegalStateException(); } + // !!! TODO: should support, is doable (logically); but not yet supported so: + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return Boolean.FALSE; + } + /** * @since 2.7 */ diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/ReferenceTypeDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/ReferenceTypeDeserializer.java index 1f56aaf68..f3bc2b419 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/ReferenceTypeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/ReferenceTypeDeserializer.java @@ -121,6 +121,16 @@ public abstract class ReferenceTypeDeserializer<T> @Override public JavaType getValueType() { return _fullType; } + /** + * By default we assume that updateability mostly relies on value + * deserializer; if it supports updates, typically that's what + * matters. So let's just delegate. + */ + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return _valueDeserializer.supportsUpdate(config); + } + /* /********************************************************** /* Deserialization diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDelegatingDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDelegatingDeserializer.java index 4f9cd74bd..6bea8c471 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDelegatingDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdDelegatingDeserializer.java @@ -148,6 +148,11 @@ public class StdDelegatingDeserializer<T> return _delegateDeserializer.handledType(); } + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return _delegateDeserializer.supportsUpdate(config); + } + /* /********************************************************** /* Serialization diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdScalarDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdScalarDeserializer.java index a88bda3bf..a6d7318a4 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StdScalarDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StdScalarDeserializer.java @@ -3,6 +3,7 @@ package com.fasterxml.jackson.databind.deser.std; import java.io.IOException; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; @@ -34,4 +35,14 @@ public abstract class StdScalarDeserializer<T> extends StdDeserializer<T> public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue) throws IOException { return deserialize(p, ctxt); } + + /** + * By default assumption is that scalar types can not be updated: many are immutable + * values (such as primitives and wrappers) + */ + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + return Boolean.FALSE; + } + } diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java index 38f319f0e..ecaa243f6 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/StringArrayDeserializer.java @@ -49,6 +49,13 @@ public final class StringArrayDeserializer _unwrapSingle = unwrapSingle; } + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + // 23-Oct-2016, tatu: In theory could support some specific cases; and there's + // question of logical vs physical update. But for now, claim we can't do it. + return Boolean.FALSE; + } + /** * Contextualization is needed to see whether we can "inline" deserialization * of String values, or if we have to use separate value deserializer. diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java index cff1cdcae..4dcfc4c53 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/UntypedObjectDeserializer.java @@ -5,6 +5,7 @@ import java.util.*; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.DeserializationConfig; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JavaType; @@ -204,6 +205,13 @@ public class UntypedObjectDeserializer return true; } + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + // 23-Oct-2016, tatu: In theory, some values would be updateable (Maps, Collections), + // but seems very error prone, so for now declare that we do not support it. + return Boolean.FALSE; + } + @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { @@ -475,6 +483,13 @@ public class UntypedObjectDeserializer public Vanilla() { super(Object.class); } + @Override // since 2.9 + public Boolean supportsUpdate(DeserializationConfig config) { + // 23-Oct-2016, tatu: In theory, some values would be updateable (Maps, Collections), + // but seems very error prone, so for now declare that we do not support it. + return Boolean.FALSE; + } + @Override public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { diff --git a/src/test/java/com/fasterxml/jackson/databind/deser/PropertyMergeTest.java b/src/test/java/com/fasterxml/jackson/databind/deser/PropertyMergeTest.java index eed8a06b0..37817cff9 100644 --- a/src/test/java/com/fasterxml/jackson/databind/deser/PropertyMergeTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/deser/PropertyMergeTest.java @@ -50,15 +50,39 @@ public class PropertyMergeTest extends BaseMapTest } } + static class MergedMap + { + @JsonSetter(merge=OptBoolean.TRUE) + public Map<String,String> values = new LinkedHashMap<>(); + { + values.put("a", "x"); + } + } + + static class MergedList + { + @JsonSetter(merge=OptBoolean.TRUE) + public List<String> values = new ArrayList<>(); + { + values.add("a"); + } + } + + static class MergedEnumSet + { + @JsonSetter(merge=OptBoolean.TRUE) + public EnumSet<ABC> abc = EnumSet.of(ABC.B); + } + static class MergedReference { @JsonSetter(merge=OptBoolean.TRUE) public StringReference value = new StringReference("default"); } - + /* /******************************************************** - /* Test methods + /* Test methods, POJO merging /******************************************************** */ @@ -100,6 +124,12 @@ public class PropertyMergeTest extends BaseMapTest assertEquals(2, config.loc.b); // original, merged } + /* + /******************************************************** + /* Test methods, Collection merging + /******************************************************** + */ + public void testCollectionMerging() throws Exception { CollectionWrapper w = MAPPER.readValue(aposToQuotes("{'bag':['b']}"), CollectionWrapper.class); @@ -108,6 +138,42 @@ public class PropertyMergeTest extends BaseMapTest assertTrue(w.bag.contains("b")); } + public void testListMerging() throws Exception + { + MergedList w = MAPPER.readValue(aposToQuotes("{'values':['x']}"), MergedList.class); + assertEquals(2, w.values.size()); + assertTrue(w.values.contains("a")); + assertTrue(w.values.contains("x")); + } + + public void testEnumSetMerging() throws Exception + { + MergedEnumSet result = MAPPER.readValue(aposToQuotes("{'abc':['A']}"), MergedEnumSet.class); + assertEquals(2, result.abc.size()); + assertTrue(result.abc.contains(ABC.B)); // original + assertTrue(result.abc.contains(ABC.A)); // added + } + + /* + /******************************************************** + /* Test methods, Map merging + /******************************************************** + */ + + public void testMapMerging() throws Exception + { + MergedMap v = MAPPER.readValue(aposToQuotes("{'values':{'c':'y'}}"), MergedMap.class); + assertEquals(2, v.values.size()); + assertEquals("y", v.values.get("c")); + assertEquals("x", v.values.get("a")); + } + + /* + /******************************************************** + /* Test methods, reference types + /******************************************************** + */ + public void testReferenceMerging() throws Exception { MergedReference result = MAPPER.readValue(aposToQuotes("{'value':'override'}"), |