View Javadoc
1   package top.infra.jackson2.ser;
2   
3   import com.fasterxml.jackson.core.JsonGenerator;
4   import com.fasterxml.jackson.databind.AnnotationIntrospector;
5   import com.fasterxml.jackson.databind.BeanProperty;
6   import com.fasterxml.jackson.databind.JavaType;
7   import com.fasterxml.jackson.databind.JsonMappingException;
8   import com.fasterxml.jackson.databind.JsonSerializer;
9   import com.fasterxml.jackson.databind.SerializerProvider;
10  import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
11  import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
12  import com.fasterxml.jackson.databind.ser.ContextualSerializer;
13  import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
14  import com.fasterxml.jackson.databind.ser.std.StdSerializer;
15  
16  import org.apache.commons.lang3.tuple.Pair;
17  
18  import java.io.IOException;
19  import java.util.Map;
20  
21  /**
22   * see: {@link com.fasterxml.jackson.databind.ser.impl.MapEntrySerializer}.
23   */
24  public class PairSerializer extends StdSerializer<Pair<?, ?>> implements ContextualSerializer {
25  
26      /**
27       * property being serialized with this instance
28       */
29      protected final BeanProperty _property;
30  
31      /**
32       * Whether static types should be used for serialization of values
33       * or not (if not, dynamic runtime type is used)
34       */
35      protected final boolean _staticTyping;
36  
37      protected final JavaType _entryType, _keyType, _valueType;
38      /**
39       * keyTypeSerializer, Type identifier serializer used for keys, if any.
40       */
41      protected final TypeSerializer _kts;
42      /**
43       * valueTypeSerializer, Type identifier serializer used for values, if any.
44       */
45      protected final TypeSerializer _vts;
46      /**
47       * Key serializer to use, if it can be statically determined
48       */
49      protected JsonSerializer<Object> _ks;
50      /**
51       * Value serializer to use, if it can be statically determined
52       */
53      protected JsonSerializer<Object> _vs;
54      /**
55       * dynamicKeySerializers, If key type can not be statically determined, mapping from
56       * runtime key types to serializers are stored in this object.
57       */
58      protected PropertySerializerMap _dks;
59      /**
60       * dynamicValueSerializers, If value type can not be statically determined, mapping from
61       * runtime value types to serializers are stored in this object.
62       */
63      protected PropertySerializerMap _dvs;
64  
65      public PairSerializer(
66          final JavaType type, final JavaType keyType, final JavaType valueType,
67          final boolean staticTyping,
68          final TypeSerializer kts, final TypeSerializer vts,
69          final BeanProperty property
70      ) {
71          super(type);
72          this._entryType = type;
73          this._keyType = keyType;
74          this._valueType = valueType;
75          this._staticTyping = staticTyping;
76          this._kts = kts;
77          this._vts = vts;
78          this._dks = PropertySerializerMap.emptyForProperties();
79          this._dvs = PropertySerializerMap.emptyForProperties();
80          this._property = property;
81      }
82  
83      @SuppressWarnings("unchecked")
84      protected PairSerializer(
85          final PairSerializer src,
86          final BeanProperty property,
87          final TypeSerializer vts,
88          final JsonSerializer<?> keySer,
89          final JsonSerializer<?> valueSer
90      ) {
91          super(Map.class, false);
92          this._entryType = src._entryType;
93          this._keyType = src._keyType;
94          this._valueType = src._valueType;
95          this._staticTyping = src._staticTyping;
96          this._kts = src._kts;
97          this._vts = src._vts;
98          this._ks = (JsonSerializer<Object>) keySer;
99          this._vs = (JsonSerializer<Object>) valueSer;
100         this._dks = src._dks;
101         this._dvs = src._dvs;
102         this._property = src._property;
103     }
104 
105     @Override
106     public JsonSerializer<?> createContextual(final SerializerProvider provider, final BeanProperty property) throws JsonMappingException {
107         JsonSerializer<?> vs = null;
108         JsonSerializer<?> ks = null;
109 
110         final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
111         final AnnotatedMember propertyAcc = (property == null) ? null : property.getMember();
112 
113         // First: if we have a property, may have property-annotation overrides
114         if (propertyAcc != null && intr != null) {
115             Object serDef = intr.findKeySerializer(propertyAcc);
116             if (serDef != null) {
117                 ks = provider.serializerInstance(propertyAcc, serDef);
118             }
119             serDef = intr.findContentSerializer(propertyAcc);
120             if (serDef != null) {
121                 vs = provider.serializerInstance(propertyAcc, serDef);
122             }
123         }
124 
125         if (vs == null) {
126             vs = this._vs;
127         }
128         // [databind#124]: May have a content converter
129         vs = findConvertingContentSerializer(provider, property, vs);
130         if (vs == null) {
131             // 30-Sep-2012, tatu: One more thing -- if explicit content type is annotated,
132             //   we can consider it a static case as well.
133             // 20-Aug-2013, tatu: Need to avoid trying to access serializer for java.lang.Object tho
134             if (this._staticTyping && !this._valueType.isJavaLangObject()) {
135                 vs = provider.findValueSerializer(this._valueType, property);
136             }
137         } else {
138             vs = provider.handleSecondaryContextualization(vs, property);
139         }
140 
141         if (ks == null) {
142             ks = this._ks;
143         }
144         ks = findConvertingContentSerializer(provider, property, ks);
145         if (ks == null) {
146             if (this._staticTyping && !this._valueType.isJavaLangObject()) {
147                 ks = provider.findValueSerializer(this._valueType, property);
148             }
149         } else {
150             ks = provider.handleSecondaryContextualization(ks, property);
151         }
152 
153         PairSerializer mser = withResolved(property, ks, vs);
154         // but note: no filtering, ignored entries or sorting (unlike Maps)
155         return mser;
156     }
157 
158     public PairSerializer withResolved(BeanProperty property, JsonSerializer<?> ks, JsonSerializer<?> vs) {
159         return new PairSerializer(this, property, this._vts, ks, vs);
160     }
161 
162     @Override
163     public void serialize(
164         final Pair<?, ?> value, final JsonGenerator gen, final SerializerProvider provider
165     ) throws IOException {
166         gen.writeStartObject(value);
167         //if (this._vs != null) {
168         //    serializeUsing(value, gen, provider, _vs);
169         //} else {
170         serializeDynamic(value, gen, provider);
171         //}
172         gen.writeEndObject();
173     }
174 
175     @Override
176     public void serializeWithType(
177         final Pair<?, ?> value, final JsonGenerator gen, final SerializerProvider provider, final TypeSerializer typeSer
178     ) throws IOException {
179         typeSer.writeTypePrefixForObject(value, gen);
180         // [databind#631]: Assign current value, to be accessible by custom serializers
181         gen.setCurrentValue(value);
182         //if (this._vs != null) {
183         //    serializeUsing(value, gen, provider, _vs);
184         //} else {
185         serializeDynamic(value, gen, provider);
186         //}
187         typeSer.writeTypeSuffixForObject(value, gen);
188     }
189 
190     protected void serializeDynamic(
191         final Pair<?, ?> value, final JsonGenerator jgen, final SerializerProvider provider
192     ) throws IOException {
193         //final JsonSerializer<Object> keySerializer = this._ks;
194         //final boolean skipNulls = !provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES);
195         final TypeSerializer vts = this._vts;
196         final TypeSerializer kts = this._kts;
197 
198         PropertySerializerMap dvs = this._dvs;
199         PropertySerializerMap dks = this._dks;
200 
201         Object valueElem = value.getValue();
202         Object keyElem = value.getKey();
203 
204         jgen.writeFieldName("left");
205         if (keyElem == null) {
206             provider.defaultSerializeNull(jgen);
207         } else {
208             Class<?> cc = keyElem.getClass();
209             JsonSerializer<Object> ser = dks.serializerFor(cc);
210             if (ser == null) {
211                 if (this._valueType.hasGenericTypes()) {
212                     ser = _findAndAddDynamicKeySerializer(dks, provider.constructSpecializedType(this._keyType, cc), provider);
213                 } else {
214                     ser = _findAndAddDynamicKeySerializer(dks, cc, provider);
215                 }
216                 dks = this._dks;
217             }
218             try {
219                 if (kts == null) {
220                     ser.serialize(keyElem, jgen, provider);
221                 } else {
222                     ser.serializeWithType(keyElem, jgen, provider, kts);
223                 }
224             } catch (final Exception e) {
225                 // [JACKSON-55] Need to add reference information
226                 String keyDesc = "" + keyElem;
227                 wrapAndThrow(provider, e, value, keyDesc);
228             }
229         }
230 
231         // And then value
232         jgen.writeFieldName("right");
233         if (valueElem == null) {
234             provider.defaultSerializeNull(jgen);
235         } else {
236             Class<?> cc = valueElem.getClass();
237             JsonSerializer<Object> ser = dvs.serializerFor(cc);
238             if (ser == null) {
239                 if (this._valueType.hasGenericTypes()) {
240                     ser = _findAndAddDynamicValueSerializer(dvs, provider.constructSpecializedType(this._valueType, cc), provider);
241                 } else {
242                     ser = _findAndAddDynamicValueSerializer(dvs, cc, provider);
243                 }
244                 dvs = this._dvs;
245             }
246             try {
247                 if (vts == null) {
248                     ser.serialize(valueElem, jgen, provider);
249                 } else {
250                     ser.serializeWithType(valueElem, jgen, provider, vts);
251                 }
252             } catch (final Exception e) {
253                 // [JACKSON-55] Need to add reference information
254                 String keyDesc = "" + keyElem;
255                 wrapAndThrow(provider, e, value, keyDesc);
256             }
257         }
258     }
259 
260 
261     protected final JsonSerializer<Object> _findAndAddDynamicKeySerializer(
262         final PropertySerializerMap map,
263         final Class<?> type,
264         final SerializerProvider provider
265     ) throws JsonMappingException {
266         final PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, this._property);
267         if (map != result.map) {
268             this._dks = result.map;
269         }
270         return result.serializer;
271     }
272 
273     protected final JsonSerializer<Object> _findAndAddDynamicKeySerializer(
274         final PropertySerializerMap map,
275         final JavaType type,
276         final SerializerProvider provider
277     ) throws JsonMappingException {
278         final PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, this._property);
279         if (map != result.map) {
280             this._dks = result.map;
281         }
282         return result.serializer;
283     }
284 
285     protected final JsonSerializer<Object> _findAndAddDynamicValueSerializer(
286         final PropertySerializerMap map,
287         final Class<?> type,
288         final SerializerProvider provider
289     ) throws JsonMappingException {
290         final PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, this._property);
291         if (map != result.map) {
292             this._dvs = result.map;
293         }
294         return result.serializer;
295     }
296 
297     protected final JsonSerializer<Object> _findAndAddDynamicValueSerializer(
298         final PropertySerializerMap map,
299         final JavaType type,
300         final SerializerProvider provider
301     ) throws JsonMappingException {
302         final PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, this._property);
303         if (map != result.map) {
304             this._dvs = result.map;
305         }
306         return result.serializer;
307     }
308 }