diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 079bf70369..a04cdce909 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -32,6 +32,8 @@ Project: jackson-databind #3736: Try to avoid auto-detecting Fields for Record types #3742: schemaType of `LongSerializer` is wrong (reported by @luozhenyu) +#3748: `DelegatingDeserializer` missing override of `getAbsentValue()` + (and couple of other methods) 2.14.2 (not yet released) diff --git a/src/main/java/com/fasterxml/jackson/databind/deser/std/DelegatingDeserializer.java b/src/main/java/com/fasterxml/jackson/databind/deser/std/DelegatingDeserializer.java index 764e534ce1..d506c4470c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/deser/std/DelegatingDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/databind/deser/std/DelegatingDeserializer.java @@ -10,11 +10,12 @@ import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; import com.fasterxml.jackson.databind.type.LogicalType; import com.fasterxml.jackson.databind.util.AccessPattern; +import com.fasterxml.jackson.databind.util.NameTransformer; /** * Base class that simplifies implementations of {@link JsonDeserializer}s * that mostly delegate functionality to another deserializer implementation - * (possibly forming a chaing of deserializers delegating functionality + * (possibly forming a chaining of deserializers delegating functionality * in some cases) * * @since 2.1 @@ -26,7 +27,7 @@ public abstract class DelegatingDeserializer private static final long serialVersionUID = 1L; protected final JsonDeserializer _delegatee; - + /* /********************************************************************** /* Construction @@ -46,7 +47,7 @@ public DelegatingDeserializer(JsonDeserializer d) */ protected abstract JsonDeserializer newDelegatingInstance(JsonDeserializer newDelegatee); - + /* /********************************************************************** /* Overridden methods for contextualization, resolving @@ -74,6 +75,16 @@ public JsonDeserializer createContextual(DeserializationContext ctxt, return newDelegatingInstance(del); } + @SuppressWarnings("unchecked") + @Override + public JsonDeserializer unwrappingDeserializer(NameTransformer unwrapper) { + JsonDeserializer unwrapping = _delegatee.unwrappingDeserializer(unwrapper); + if (unwrapping == _delegatee) { + return this; + } + return (JsonDeserializer) newDelegatingInstance(unwrapping); + } + @Override public JsonDeserializer replaceDelegatee(JsonDeserializer delegatee) { @@ -138,14 +149,19 @@ public SettableBeanProperty findBackReference(String logicalName) { return _delegatee.findBackReference(logicalName); } + @Override + public Object getNullValue(DeserializationContext ctxt) throws JsonMappingException { + return _delegatee.getNullValue(ctxt); + } + @Override public AccessPattern getNullAccessPattern() { return _delegatee.getNullAccessPattern(); } @Override - public Object getNullValue(DeserializationContext ctxt) throws JsonMappingException { - return _delegatee.getNullValue(ctxt); + public Object getAbsentValue(DeserializationContext ctxt) throws JsonMappingException { + return _delegatee.getAbsentValue(ctxt); } @Override @@ -153,6 +169,11 @@ public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingExcep return _delegatee.getEmptyValue(ctxt); } + @Override + public AccessPattern getEmptyAccessPattern() { + return _delegatee.getEmptyAccessPattern(); + } + @Override // since 2.12 public LogicalType logicalType() { return _delegatee.logicalType(); diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/TestCustomSerializers.java b/src/test/java/com/fasterxml/jackson/databind/ser/TestCustomSerializers.java index cf8b30ddd6..23b8891316 100644 --- a/src/test/java/com/fasterxml/jackson/databind/ser/TestCustomSerializers.java +++ b/src/test/java/com/fasterxml/jackson/databind/ser/TestCustomSerializers.java @@ -15,12 +15,16 @@ import com.fasterxml.jackson.core.io.CharacterEscapes; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; import com.fasterxml.jackson.databind.ser.std.CollectionSerializer; import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer; import com.fasterxml.jackson.databind.ser.std.StdScalarSerializer; +import com.fasterxml.jackson.databind.util.AccessPattern; +import com.fasterxml.jackson.databind.util.NameTransformer; import com.fasterxml.jackson.databind.util.StdConverter; /** @@ -185,13 +189,61 @@ public String getId() { } } + // [databind#3748] + static class BaseDeserializer3748 + extends StdDeserializer + { + public BaseDeserializer3748() { super(String.class); } + + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) { + return null; + } + + @Override + public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException { + return "empty"; + } + + @Override + public AccessPattern getEmptyAccessPattern() { + return AccessPattern.ALWAYS_NULL; + } + + @Override + public Object getAbsentValue(DeserializationContext ctxt) { + return "absent"; + } + + @Override + public JsonDeserializer unwrappingDeserializer(NameTransformer unwrapper) { + return new BaseDeserializer3748(); + } + } + + static class Delegating3748 extends DelegatingDeserializer + { + public Delegating3748() { + this(new BaseDeserializer3748()); + } + + public Delegating3748(JsonDeserializer del) { + super(del); + } + + @Override + protected JsonDeserializer newDelegatingInstance(JsonDeserializer newDelegatee) { + return new Delegating3748(newDelegatee); + } + } + /* /********************************************************** /* Unit tests /********************************************************** */ - private final ObjectMapper MAPPER = new ObjectMapper(); + private final ObjectMapper MAPPER = newJsonMapper(); public void testCustomization() throws Exception { @@ -303,6 +355,17 @@ public void testIssue2475() throws Exception { assertEquals(a2q("{'id':'ID-2','set':[]}"), writer.writeValueAsString(new Item2475(new HashSet(), "ID-2"))); - } + } + // [databind#3748] + public void testBasicDelegatingDeser() throws Exception + { + Delegating3748 deser = new Delegating3748(); + assertEquals("absent", deser.getAbsentValue(null)); + assertEquals("empty", deser.getEmptyValue(null)); + assertEquals(AccessPattern.ALWAYS_NULL, deser.getEmptyAccessPattern()); + JsonDeserializer unwrapping = deser.unwrappingDeserializer(null); + assertNotNull(unwrapping); + assertNotSame(deser, unwrapping); + } }