99
1010/**
1111 * Property writer sub-class used for handling element wrapping needed for serializing
12- * collection (array, Collection; possibly Map) types.
12+ * collection (array, Collection; not Map) types.
1313 */
1414public class XmlBeanPropertyWriter
1515 extends BeanPropertyWriter
1616{
17- private static final long serialVersionUID = 1L ;
18-
1917 /*
2018 /**********************************************************************
2119 /* Config settings
@@ -32,24 +30,60 @@ public class XmlBeanPropertyWriter
3230 */
3331 protected final QName _wrappedQName ;
3432
33+ /**
34+ * Whether wrapping should be checked dynamically based on the runtime value type.
35+ * When {@code true}, wrapping is only applied if the runtime value is actually
36+ * a Collection, Iterable, or array. Used for properties declared as {@code Object}
37+ * that may or may not contain a collection at runtime.
38+ *
39+ * @since 3.2
40+ */
41+ protected final boolean _dynamicWrapping ;
42+
3543 /*
3644 /**********************************************************************
3745 /* Life-cycle: construction, configuration
3846 /**********************************************************************
3947 */
4048
49+ /**
50+ * @deprecated Since 3.2
51+ */
52+ @ Deprecated
4153 public XmlBeanPropertyWriter (BeanPropertyWriter wrapped ,
4254 PropertyName wrapperName , PropertyName wrappedName ) {
43- this (wrapped , wrapperName , wrappedName , null );
55+ this (wrapped , wrapperName , wrappedName , null , false );
4456 }
4557
58+ /**
59+ * @deprecated Since 3.2
60+ */
61+ @ Deprecated
4662 public XmlBeanPropertyWriter (BeanPropertyWriter wrapped ,
4763 PropertyName wrapperName , PropertyName wrappedName ,
4864 ValueSerializer <Object > serializer )
65+ {
66+ this (wrapped , wrapperName , wrappedName , serializer , false );
67+ }
68+
69+ /**
70+ * @since 3.2
71+ */
72+ public XmlBeanPropertyWriter (BeanPropertyWriter wrapped ,
73+ PropertyName wrapperName , PropertyName wrappedName ,
74+ boolean dynamicWrapping )
75+ {
76+ this (wrapped , wrapperName , wrappedName , null , dynamicWrapping );
77+ }
78+
79+ private XmlBeanPropertyWriter (BeanPropertyWriter wrapped ,
80+ PropertyName wrapperName , PropertyName wrappedName ,
81+ ValueSerializer <Object > serializer , boolean dynamicWrapping )
4982 {
5083 super (wrapped );
5184 _wrapperQName = _qname (wrapperName );
5285 _wrappedQName = _qname (wrappedName );
86+ _dynamicWrapping = dynamicWrapping ;
5387
5488 if (serializer != null ) {
5589 assignSerializer (serializer );
@@ -64,7 +98,7 @@ private QName _qname(PropertyName n)
6498 }
6599 return new QName (ns , n .getSimpleName ());
66100 }
67-
101+
68102 /*
69103 /**********************************************************************
70104 /* Overridden methods
@@ -81,10 +115,17 @@ public void serializeAsProperty(Object bean, JsonGenerator g, SerializationConte
81115 {
82116 Object value = get (bean );
83117
118+ // [dataformat-xml#8]: For dynamic wrapping (Object-typed properties),
119+ // check runtime type and delegate to standard handling if not a collection
120+ if (_dynamicWrapping && (value == null || !_isIndexedValue (value ))) {
121+ super .serializeAsProperty (bean , g , ctxt );
122+ return ;
123+ }
124+
84125 /* 13-Feb-2014, tatu: As per [#103], default handling does not really
85126 * work here. Rather, we need just a wrapping and should NOT call
86127 * null handler, as it does not know what to do...
87- *
128+ *
88129 * Question, however, is what should it be serialized as. We have two main
89130 * choices; equivalent empty List, and "nothing" (missing). Let's start with
90131 * empty List? But producing missing entry is non-trivial...
@@ -102,7 +143,7 @@ public void serializeAsProperty(Object bean, JsonGenerator g, SerializationConte
102143 }
103144 */
104145 // but for missing thing, well, just output nothing
105-
146+
106147 return ;
107148 }
108149
@@ -150,4 +191,14 @@ public void serializeAsProperty(Object bean, JsonGenerator g, SerializationConte
150191 xmlGen .finishWrappedValue (_wrapperQName , _wrappedQName );
151192 }
152193 }
194+
195+ /**
196+ * Check if the runtime value is a Collection, array, or Iterable
197+ * (i.e. something that should get wrapper element handling).
198+ */
199+ private static boolean _isIndexedValue (Object value ) {
200+ return (value instanceof java .util .Collection <?>)
201+ || (value instanceof Iterable <?>)
202+ || value .getClass ().isArray ();
203+ }
153204}
0 commit comments