@@ -274,7 +274,9 @@ public ValueDeserializer<Object> buildBeanDeserializer(DeserializationContext ct
274274 addObjectIdReader (ctxt , beanDescRef , builder );
275275
276276 // managed/back reference fields/setters need special handling... first part
277- addBackReferenceProperties (ctxt , beanDescRef , builder );
277+ // [databind#2686]: targetType For Builder pattern, this method is not using.
278+ // So this value is null.
279+ addBackReferenceProperties (ctxt , beanDescRef , builder , null );
278280 addInjectables (ctxt , beanDescRef , builder );
279281
280282 final DeserializationConfig config = ctxt .getConfig ();
@@ -334,7 +336,8 @@ protected ValueDeserializer<Object> buildBuilderBasedDeserializer(
334336 addObjectIdReader (ctxt , builderDescRef , builder );
335337
336338 // managed/back reference fields/setters need special handling... first part
337- addBackReferenceProperties (ctxt , builderDescRef , builder );
339+ // [databind#2686]: For Builder pattern, pass target type so that back-reference
340+ addBackReferenceProperties (ctxt , builderDescRef , builder , valueType );
338341 addInjectables (ctxt , builderDescRef , builder );
339342
340343 JsonPOJOBuilder .Value builderConfig = ctxt .getAnnotationIntrospector ()
@@ -736,7 +739,8 @@ && isIgnorableType(ctxt, property, rawPropertyType, ignoredTypes)) {
736739 * and if so add them to bean, to be linked during resolution phase.
737740 */
738741 protected void addBackReferenceProperties (DeserializationContext ctxt ,
739- BeanDescription .Supplier beanDescRef , BeanDeserializerBuilder builder )
742+ BeanDescription .Supplier beanDescRef , BeanDeserializerBuilder builder ,
743+ JavaType targetType )
740744 {
741745 // and then back references, not necessarily found as regular properties
742746 List <BeanPropertyDefinition > refProps = beanDescRef .get ().findBackReferences ();
@@ -764,8 +768,31 @@ protected void addBackReferenceProperties(DeserializationContext ctxt,
764768 refProp .getName ());
765769 }
766770 String refName = refProp .findReferenceName ();
767- builder .addBackReferenceProperty (refName , constructSettableProperty (ctxt ,
768- beanDescRef , refProp , refProp .getPrimaryType ()));
771+ SettableBeanProperty backRefProp ;
772+
773+ if (targetType != null ) {
774+ // [databind#2686]: Handle Builder
775+ backRefProp = constructBuilderBackRefProperty (ctxt ,
776+ targetType , refProp );
777+ } else {
778+ // normal
779+ backRefProp = constructSettableProperty (ctxt ,
780+ beanDescRef , refProp , refProp .getPrimaryType ());
781+ }
782+
783+ if (backRefProp != null ) {
784+ builder .addBackReferenceProperty (refName , backRefProp );
785+ } else {
786+ if (targetType != null ) {
787+ ctxt .reportBadTypeDefinition (beanDescRef ,
788+ "Cannot find back-reference field '%s' in target type '%s' for Builder-based deserialization" ,
789+ refProp .getName (), targetType .getRawClass ().getName ());
790+ } else {
791+ ctxt .reportBadTypeDefinition (beanDescRef ,
792+ "Cannot resolve back-reference property '%s'" ,
793+ refProp .getName ());
794+ }
795+ }
769796 }
770797 }
771798 }
@@ -1068,4 +1095,28 @@ protected void _validateSubType(DeserializationContext ctxt, JavaType type,
10681095 {
10691096 SubTypeValidator .instance ().validateSubType (ctxt , type , beanDescRef );
10701097 }
1098+
1099+ /**
1100+ * Helper method for constructing back-reference property when using Builder pattern.
1101+ *
1102+ * @since 3.1
1103+ */
1104+ protected SettableBeanProperty constructBuilderBackRefProperty (DeserializationContext ctxt ,
1105+ JavaType targetType , BeanPropertyDefinition builderRefProp )
1106+ {
1107+ BeanDescription .Supplier targetDescRef = ctxt .lazyIntrospectBeanDescription (targetType );
1108+ BeanDescription targetDesc = targetDescRef .get ();
1109+
1110+ // find back reference with same field
1111+ String propName = builderRefProp .getName ();
1112+ for (BeanPropertyDefinition propDef : targetDesc .findProperties ()) {
1113+ if (propName .equals (propDef .getName ()) && propDef .hasField ()) {
1114+ AnnotatedField field = propDef .getField ();
1115+ JavaType propertyType = field .getType ();
1116+ return constructSettableProperty (ctxt , targetDescRef , propDef , propertyType );
1117+ }
1118+ }
1119+
1120+ return null ;
1121+ }
10711122}
0 commit comments