Skip to content

Commit 8de9cef

Browse files
committed
Fix #1575
1 parent c0c8817 commit 8de9cef

File tree

4 files changed

+64
-67
lines changed

4 files changed

+64
-67
lines changed

release-notes/VERSION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Project: jackson-databind
99
#1533: `AsPropertyTypeDeserializer` ignores `DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT`
1010
#1543: JsonFormat.Shape.NUMBER_INT does not work when defined on enum type in 2.8
1111
(reported by Alex P)
12+
#1575: Problem with `@JsonIgnoreProperties` on recursive property (regression in 2.8)
13+
(reported by anujkumar04@github)
1214
- Minor fix to creation of `PropertyMetadata`, had one path that could lead to NPE
1315

1416
2.8.7 (21-Feb-2017)

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

Lines changed: 57 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,6 @@ public BeanDeserializerBase(BeanDeserializerBase src, ObjectIdReader oir)
356356
public BeanDeserializerBase(BeanDeserializerBase src, Set<String> ignorableProps)
357357
{
358358
super(src._beanType);
359-
360359
_classAnnotations = src._classAnnotations;
361360
_beanType = src._beanType;
362361

@@ -461,55 +460,35 @@ public void resolve(DeserializationContext ctxt)
461460

462461
if (_valueInstantiator.canCreateFromObjectWith()) {
463462
creatorProps = _valueInstantiator.getFromObjectArguments(ctxt.getConfig());
464-
465-
// 21-Jun-2015, tatu: This resolution was duplicated later on and seems like
466-
// it really should be only done at a later point. So commented out in 2.8.
467-
// However, just in case there was a reason for it, leaving commented out
468-
// here instead of immediately removing.
469-
470-
/*
471-
// also: need to try to resolve 'external' type ids...
472-
for (SettableBeanProperty prop : creatorProps) {
473-
if (prop.hasValueTypeDeserializer()) {
474-
TypeDeserializer typeDeser = prop.getValueTypeDeserializer();
475-
if (typeDeser.getTypeInclusion() == JsonTypeInfo.As.EXTERNAL_PROPERTY) {
476-
if (extTypes == null) {
477-
extTypes = new ExternalTypeHandler.Builder();
478-
}
479-
extTypes.addExternal(prop, typeDeser);
480-
}
481-
}
482-
}
483-
*/
484463
} else {
485464
creatorProps = null;
486465
}
487-
488466
UnwrappedPropertyHandler unwrapped = null;
489467

490-
for (SettableBeanProperty origProp : _beanProperties) {
491-
SettableBeanProperty prop = origProp;
468+
// 24-Mar-2017, tatu: Looks like we may have to iterate over
469+
// properties twice, to handle potential issues with recursive
470+
// types (see [databind#1575] f.ex).
492471

493-
// May already have deserializer from annotations, if so, skip:
472+
// First loop: find deserializer if not yet known, but do not yet
473+
// contextualize (since that can lead to problems with self-references)
474+
for (SettableBeanProperty prop : _beanProperties) {
494475
if (!prop.hasValueDeserializer()) {
495476
// [databind#125]: allow use of converters
496477
JsonDeserializer<?> deser = findConvertingDeserializer(ctxt, prop);
497478
if (deser == null) {
498-
deser = findDeserializer(ctxt, prop.getType(), prop);
499-
}
500-
prop = prop.withValueDeserializer(deser);
501-
} else { // may need contextual version
502-
JsonDeserializer<Object> deser = prop.getValueDeserializer();
503-
/* Important! This is the only place where actually handle "primary"
504-
* property deserializers -- call is different from other places.
505-
*/
506-
JsonDeserializer<?> cd = ctxt.handlePrimaryContextualization(deser, prop,
507-
prop.getType());
508-
if (cd != deser) {
509-
prop = prop.withValueDeserializer(cd);
479+
deser = ctxt.findNonContextualValueDeserializer(prop.getType());
510480
}
481+
SettableBeanProperty newProp = prop.withValueDeserializer(deser);
482+
_replaceProperty(_beanProperties, creatorProps, prop, newProp);
511483
}
484+
}
512485

486+
// Second loop: contextualize, find other pieces
487+
for (SettableBeanProperty origProp : _beanProperties) {
488+
SettableBeanProperty prop = origProp;
489+
JsonDeserializer<?> deser = prop.getValueDeserializer();
490+
deser = ctxt.handlePrimaryContextualization(deser, prop, prop.getType());
491+
prop = prop.withValueDeserializer(deser);
513492
// Need to link managed references with matching back references
514493
prop = _resolveManagedReferenceProperty(ctxt, prop);
515494

@@ -525,36 +504,18 @@ public void resolve(DeserializationContext ctxt)
525504
unwrapped = new UnwrappedPropertyHandler();
526505
}
527506
unwrapped.addProperty(prop);
528-
/* 12-Dec-2014, tatu: As per [databind#647], we will have problems if
529-
* the original property is left in place. So let's remove it now.
530-
*/
507+
// 12-Dec-2014, tatu: As per [databind#647], we will have problems if
508+
// the original property is left in place. So let's remove it now.
509+
// 25-Mar-2017, tatu: Wonder if this could be problematic wrt creators?
531510
_beanProperties.remove(prop);
532511
continue;
533512
}
534513
// non-static inner classes too:
535514
prop = _resolveInnerClassValuedProperty(ctxt, prop);
536515
if (prop != origProp) {
537-
_beanProperties.replace(prop);
538-
// [databind#795]: Make sure PropertyBasedCreator's properties stay in sync
539-
if (creatorProps != null) {
540-
// 18-May-2015, tatu: _Should_ start with consistent set. But can we really
541-
// fully count on this? May need to revisit in future; seems to hold for now.
542-
for (int i = 0, len = creatorProps.length; i < len; ++i) {
543-
if (creatorProps[i] == origProp) {
544-
creatorProps[i] = prop;
545-
break;
546-
}
547-
// ... as per above, it is possible we'd need to add this as fallback
548-
// if (but only if) identity check fails?
549-
/*
550-
if (creatorProps[i].getName().equals(prop.getName())) {
551-
creatorProps[i] = prop;
552-
break;
553-
}
554-
*/
555-
}
556-
}
516+
_replaceProperty(_beanProperties, creatorProps, origProp, prop);
557517
}
518+
558519
// one more thing: if this property uses "external property" type inclusion,
559520
// it needs different handling altogether
560521
if (prop.hasValueTypeDeserializer()) {
@@ -616,11 +577,38 @@ public void resolve(DeserializationContext ctxt)
616577
if (unwrapped != null) { // we consider this non-standard, to offline handling
617578
_nonStandardCreation = true;
618579
}
619-
620580
// may need to disable vanilla processing, if unwrapped handling was enabled...
621581
_vanillaProcessing = _vanillaProcessing && !_nonStandardCreation;
622582
}
623583

584+
/**
585+
* @since 2.8.8
586+
*/
587+
protected void _replaceProperty(BeanPropertyMap props, SettableBeanProperty[] creatorProps,
588+
SettableBeanProperty origProp, SettableBeanProperty newProp)
589+
{
590+
props.replace(newProp);
591+
// [databind#795]: Make sure PropertyBasedCreator's properties stay in sync
592+
if (creatorProps != null) {
593+
// 18-May-2015, tatu: _Should_ start with consistent set. But can we really
594+
// fully count on this? May need to revisit in future; seems to hold for now.
595+
for (int i = 0, len = creatorProps.length; i < len; ++i) {
596+
if (creatorProps[i] == origProp) {
597+
creatorProps[i] = newProp;
598+
return;
599+
}
600+
}
601+
// ... as per above, it is possible we'd need to add this as fallback
602+
// if (but only if) identity check fails?
603+
/*
604+
if (creatorProps[i].getName().equals(prop.getName())) {
605+
creatorProps[i] = prop;
606+
break;
607+
}
608+
*/
609+
}
610+
}
611+
624612
private JsonDeserializer<Object> _findDelegateDeserializer(DeserializationContext ctxt, JavaType delegateType,
625613
AnnotatedWithParams delegateCreator) throws JsonMappingException {
626614
// Need to create a temporary property to allow contextual deserializers:
@@ -645,6 +633,9 @@ private JsonDeserializer<Object> _findDelegateDeserializer(DeserializationContex
645633
* Helper method that can be used to see if specified property is annotated
646634
* to indicate use of a converter for property value (in case of container types,
647635
* it is container type itself, not key or content type).
636+
*<p>
637+
* NOTE: returned deserializer is NOT yet contextualized, caller needs to take
638+
* care to do that.
648639
*
649640
* @since 2.2
650641
*/
@@ -658,8 +649,10 @@ protected JsonDeserializer<Object> findConvertingDeserializer(DeserializationCon
658649
if (convDef != null) {
659650
Converter<Object,Object> conv = ctxt.converterInstance(prop.getMember(), convDef);
660651
JavaType delegateType = conv.getInputType(ctxt.getTypeFactory());
661-
JsonDeserializer<?> ser = ctxt.findContextualValueDeserializer(delegateType, prop);
662-
return new StdDelegatingDeserializer<Object>(conv, delegateType, ser);
652+
// 25-Mar-2017, tatu: should not yet contextualize
653+
// JsonDeserializer<?> deser = ctxt.findContextualValueDeserializer(delegateType, prop);
654+
JsonDeserializer<?> deser = ctxt.findNonContextualValueDeserializer(delegateType);
655+
return new StdDelegatingDeserializer<Object>(conv, delegateType, deser);
663656
}
664657
}
665658
return null;
@@ -677,7 +670,7 @@ public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
677670
BeanProperty property) throws JsonMappingException
678671
{
679672
ObjectIdReader oir = _objectIdReader;
680-
673+
681674
// First: may have an override for Object Id:
682675
final AnnotationIntrospector intr = ctxt.getAnnotationIntrospector();
683676
final AnnotatedMember accessor = (property == null || intr == null)

src/main/java/com/fasterxml/jackson/databind/deser/std/StdDelegatingDeserializer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ protected StdDelegatingDeserializer<T> withDelegate(Converter<Object,T> converte
104104
/**********************************************************
105105
*/
106106

107+
// Note: unlikely to get called since most likely instances explicitly constructed;
108+
// if so, caller must ensure delegating deserializer is properly resolve()d.
107109
@Override
108110
public void resolve(DeserializationContext ctxt)
109111
throws JsonMappingException

src/test/java/com/fasterxml/jackson/databind/convert/ConvertingAbstractSerializer795Test.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public static class AbstractCustomTypeUser {
3434
@JsonDeserialize(converter = AbstractCustomTypeDeserializationConverter.class)
3535
private final AbstractCustomType customField;
3636

37-
@JsonCreator AbstractCustomTypeUser(@JsonProperty("customField")
38-
AbstractCustomType customField) {
39-
this.customField = customField;
37+
@JsonCreator
38+
AbstractCustomTypeUser(@JsonProperty("customField") AbstractCustomType cf) {
39+
this.customField = cf;
4040
}
4141
}
4242

0 commit comments

Comments
 (0)