Skip to content

Commit 0e373fa

Browse files
committed
Fixed #383
1 parent 4b880d2 commit 0e373fa

File tree

5 files changed

+41
-26
lines changed

5 files changed

+41
-26
lines changed

release-notes/VERSION

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Project: jackson-databind
1313
(reported by Starkom@github)
1414
#357: StackOverflowError with contentConverter that returns array type
1515
(reported by Florian S)
16+
#383: Recursive `@JsonUnwrapped` (`child` with same type) fail: "No _valueDeserializer assigned"
17+
(reported by tdavis@github)
1618
#403: Make FAIL_ON_NULL_FOR_PRIMITIVES apply to primitive arrays and other types that wrap primitives
1719
(reported by Harleen S)
1820
#476: Allow "Serialize as POJO" using `@JsonFormat(shape=Shape.OBJECT)` class annotation

src/main/java/com/fasterxml/jackson/databind/SerializerProvider.java

+2
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,8 @@ public JsonSerializer<Object> findValueSerializer(Class<?> valueType, BeanProper
528528
* full generics-aware type instead of raw class.
529529
* This is necessary for accurate handling of external type information,
530530
* to handle polymorphic types.
531+
*<p>
532+
* Note: this call will also contextualize serializer before returning it.
531533
*
532534
* @param property When creating secondary serializers, property for which
533535
* serializer is needed: annotations of the property (or bean that contains it)

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializer.java

+18-6
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,14 @@ public class BeanDeserializer
3939
*/
4040
protected transient Exception _nullFromCreator;
4141

42+
/**
43+
* State marker we need in order to avoid infinite recursion for some cases
44+
* (not very clean, alas, but has to do for now)
45+
*
46+
* @since 2.9
47+
*/
48+
private volatile transient NameTransformer _currentlyTransforming;
49+
4250
/*
4351
/**********************************************************
4452
/* Life-cycle, construction, initialization
@@ -86,18 +94,22 @@ public BeanDeserializer(BeanDeserializerBase src, BeanPropertyMap props) {
8694
}
8795

8896
@Override
89-
public JsonDeserializer<Object> unwrappingDeserializer(NameTransformer unwrapper)
97+
public JsonDeserializer<Object> unwrappingDeserializer(NameTransformer transformer)
9098
{
9199
// bit kludgy but we don't want to accidentally change type; sub-classes
92100
// MUST override this method to support unwrapped properties...
93101
if (getClass() != BeanDeserializer.class) {
94102
return this;
95103
}
96-
/* main thing really is to just enforce ignoring of unknown
97-
* properties; since there may be multiple unwrapped values
98-
* and properties for all may be interleaved...
99-
*/
100-
return new BeanDeserializer(this, unwrapper);
104+
// 25-Mar-2017, tatu: Not clean at all, but for [databind#383] we do need
105+
// to keep track of accidental recursion...
106+
if (_currentlyTransforming == transformer) {
107+
return this;
108+
}
109+
_currentlyTransforming = transformer;
110+
try {
111+
return new BeanDeserializer(this, transformer);
112+
} finally { _currentlyTransforming = null; }
101113
}
102114

103115
@Override

src/main/java/com/fasterxml/jackson/databind/deser/BeanDeserializerBase.java

+18-19
Original file line numberDiff line numberDiff line change
@@ -478,18 +478,23 @@ public void resolve(DeserializationContext ctxt)
478478
prop = _resolvedObjectIdProperty(ctxt, prop);
479479
}
480480
// Support unwrapped values (via @JsonUnwrapped)
481-
SettableBeanProperty u = _resolveUnwrappedProperty(ctxt, prop);
482-
if (u != null) {
483-
prop = u;
484-
if (unwrapped == null) {
485-
unwrapped = new UnwrappedPropertyHandler();
481+
NameTransformer xform = _findPropertyUnwrapper(ctxt, prop);
482+
if (xform != null) {
483+
JsonDeserializer<Object> orig = prop.getValueDeserializer();
484+
JsonDeserializer<Object> unwrapping = orig.unwrappingDeserializer(xform);
485+
if (unwrapping != orig && unwrapping != null) {
486+
prop = prop.withValueDeserializer(unwrapping);
487+
if (unwrapped == null) {
488+
unwrapped = new UnwrappedPropertyHandler();
489+
}
490+
unwrapped.addProperty(prop);
491+
// 12-Dec-2014, tatu: As per [databind#647], we will have problems if
492+
// the original property is left in place. So let's remove it now.
493+
// 25-Mar-2017, tatu: Wonder if this could be problematic wrt creators?
494+
// (that is, should be remove it from creator too)
495+
_beanProperties.remove(prop);
496+
continue;
486497
}
487-
unwrapped.addProperty(prop);
488-
// 12-Dec-2014, tatu: As per [databind#647], we will have problems if
489-
// the original property is left in place. So let's remove it now.
490-
// 25-Mar-2017, tatu: Wonder if this could be problematic wrt creators?
491-
_beanProperties.remove(prop);
492-
continue;
493498
}
494499

495500
// 26-Oct-2016, tatu: Need to have access to value deserializer to know if
@@ -796,7 +801,7 @@ protected SettableBeanProperty _resolvedObjectIdProperty(DeserializationContext
796801
* Helper method called to see if given property might be so-called unwrapped
797802
* property: these require special handling.
798803
*/
799-
protected SettableBeanProperty _resolveUnwrappedProperty(DeserializationContext ctxt,
804+
protected NameTransformer _findPropertyUnwrapper(DeserializationContext ctxt,
800805
SettableBeanProperty prop)
801806
throws JsonMappingException
802807
{
@@ -811,13 +816,7 @@ protected SettableBeanProperty _resolveUnwrappedProperty(DeserializationContext
811816
"Can not define Creator property \"%s\" as `@JsonUnwrapped`: combination not yet supported",
812817
prop.getName()));
813818
}
814-
815-
JsonDeserializer<Object> orig = prop.getValueDeserializer();
816-
JsonDeserializer<Object> unwrapping = orig.unwrappingDeserializer(unwrapper);
817-
if (unwrapping != orig && unwrapping != null) {
818-
// might be cleaner to create new instance; but difficult to do reliably, so:
819-
return prop.withValueDeserializer(unwrapping);
820-
}
819+
return unwrapper;
821820
}
822821
}
823822
return null;

src/test/java/com/fasterxml/jackson/failing/TestUnwrappedRecursive383.java renamed to src/test/java/com/fasterxml/jackson/databind/struct/TestUnwrappedRecursive383.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.fasterxml.jackson.failing;
1+
package com.fasterxml.jackson.databind.struct;
22

33
import com.fasterxml.jackson.annotation.*;
44

0 commit comments

Comments
 (0)