7
7
import com .fasterxml .jackson .databind .jsonFormatVisitors .JsonFormatVisitorWrapper ;
8
8
import com .fasterxml .jackson .databind .jsontype .TypeSerializer ;
9
9
import com .fasterxml .jackson .databind .ser .ContextualSerializer ;
10
+ import com .fasterxml .jackson .databind .ser .impl .PropertySerializerMap ;
10
11
import com .fasterxml .jackson .databind .ser .std .StdSerializer ;
11
12
import com .fasterxml .jackson .databind .type .TypeFactory ;
13
+ import com .fasterxml .jackson .databind .util .NameTransformer ;
12
14
import com .google .common .base .Optional ;
13
15
14
16
@ SuppressWarnings ("serial" )
@@ -17,43 +19,61 @@ public final class GuavaOptionalSerializer
17
19
implements ContextualSerializer
18
20
{
19
21
/**
20
- * Declared type for the property being serialized with
21
- * this serializer instance.
22
+ * Declared type parameter for Optional.
22
23
*/
23
- protected final JavaType _optionalType ;
24
+ protected final JavaType _referredType ;
24
25
26
+ protected final BeanProperty _property ;
27
+
25
28
protected final JsonSerializer <Object > _valueSerializer ;
26
29
27
- public GuavaOptionalSerializer (JavaType type ) {
28
- this (type , null );
30
+ /**
31
+ * To support unwrapped values of dynamic types, will need this:
32
+ */
33
+ protected final NameTransformer _unwrapper ;
34
+
35
+ /**
36
+ * If element type can not be statically determined, mapping from
37
+ * runtime type to serializer is handled using this object
38
+ *
39
+ * @since 2.6
40
+ */
41
+ protected transient PropertySerializerMap _dynamicSerializers ;
42
+
43
+ /*
44
+ /**********************************************************
45
+ /* Life-cycle
46
+ /**********************************************************
47
+ */
48
+
49
+ public GuavaOptionalSerializer (JavaType optionalType ) {
50
+ super (optionalType );
51
+ _referredType = _valueType (optionalType );
52
+ _property = null ;
53
+ _valueSerializer = null ;
54
+ _unwrapper = null ;
55
+ _dynamicSerializers = PropertySerializerMap .emptyForProperties ();
29
56
}
30
57
31
58
@ SuppressWarnings ("unchecked" )
32
- protected GuavaOptionalSerializer (JavaType type , JsonSerializer <?> valueSer )
59
+ protected GuavaOptionalSerializer (GuavaOptionalSerializer base ,
60
+ BeanProperty property , JsonSerializer <?> valueSer , NameTransformer unwrapper )
33
61
{
34
- super (type );
35
- _optionalType = type ;
62
+ super (base );
63
+ _referredType = base ._referredType ;
64
+ _dynamicSerializers = base ._dynamicSerializers ;
65
+ _property = property ;
36
66
_valueSerializer = (JsonSerializer <Object >) valueSer ;
67
+ _unwrapper = unwrapper ;
37
68
}
38
69
39
- protected GuavaOptionalSerializer withResolved (BeanProperty property ,
40
- JsonSerializer <?> ser )
70
+ protected GuavaOptionalSerializer withResolved (BeanProperty prop ,
71
+ JsonSerializer <?> ser , NameTransformer unwrapper )
41
72
{
42
- if (_valueSerializer == ser ) {
73
+ if (( _property == prop ) && ( _valueSerializer == ser ) && ( _unwrapper == unwrapper ) ) {
43
74
return this ;
44
75
}
45
- return new GuavaOptionalSerializer (_optionalType , ser );
46
- }
47
-
48
- @ Override
49
- @ Deprecated
50
- public boolean isEmpty (Optional <?> value ) {
51
- return isEmpty (null , value );
52
- }
53
-
54
- @ Override
55
- public boolean isEmpty (SerializerProvider prov , Optional <?> value ) {
56
- return (value == null ) || !value .isPresent ();
76
+ return new GuavaOptionalSerializer (this , prop , ser , unwrapper );
57
77
}
58
78
59
79
@ Override
@@ -63,78 +83,145 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
63
83
JsonSerializer <?> ser = _valueSerializer ;
64
84
if (ser == null ) {
65
85
// we'll have type parameter available due to GuavaTypeModifier making sure it is, so:
66
- JavaType valueType = _valueType ();
67
- boolean realType = !valueType .hasRawClass (Object .class );
86
+ boolean realType = !_referredType .hasRawClass (Object .class );
68
87
/* Can only assign serializer statically if the declared type is final,
69
88
* or if we are to use static typing (and type is not "untyped")
70
89
*/
71
90
if (realType &&
72
91
(provider .isEnabled (MapperFeature .USE_STATIC_TYPING )
73
- || valueType .isFinal ())) {
92
+ || _referredType .isFinal ())) {
74
93
return withResolved (property ,
75
- provider .findPrimaryPropertySerializer (valueType , property ));
94
+ provider .findPrimaryPropertySerializer (_referredType , property ),
95
+ _unwrapper );
76
96
}
77
97
} else {
78
98
// not sure if/when this should occur but proper way to deal would be:
79
99
return withResolved (property ,
80
- provider .handlePrimaryContextualization (ser , property ));
100
+ provider .handlePrimaryContextualization (ser , property ),
101
+ _unwrapper );
81
102
}
82
103
return this ;
83
104
}
84
105
85
106
@ Override
86
- public void serialize (Optional <?> value , JsonGenerator jgen , SerializerProvider provider )
107
+ public JsonSerializer <Optional <?>> unwrappingSerializer (NameTransformer transformer ) {
108
+ JsonSerializer <Object > ser = _valueSerializer ;
109
+ if (ser != null ) {
110
+ ser = ser .unwrappingSerializer (transformer );
111
+ }
112
+ NameTransformer unwrapper = (_unwrapper == null ) ? transformer
113
+ : NameTransformer .chainedTransformer (transformer , _unwrapper );
114
+ return withResolved (_property , ser , unwrapper );
115
+ }
116
+
117
+ /*
118
+ /**********************************************************
119
+ /* API overrides
120
+ /**********************************************************
121
+ */
122
+
123
+ @ Override
124
+ @ Deprecated
125
+ public boolean isEmpty (Optional <?> value ) {
126
+ return isEmpty (null , value );
127
+ }
128
+
129
+ @ Override
130
+ public boolean isEmpty (SerializerProvider prov , Optional <?> value ) {
131
+ return (value == null ) || !value .isPresent ();
132
+ }
133
+
134
+ public boolean isUnwrappingSerializer () {
135
+ return (_unwrapper != null );
136
+ }
137
+
138
+ /*
139
+ /**********************************************************
140
+ /* Serialization methods
141
+ /**********************************************************
142
+ */
143
+
144
+ @ Override
145
+ public void serialize (Optional <?> opt , JsonGenerator gen , SerializerProvider provider )
87
146
throws IOException
88
147
{
89
- if (value .isPresent ()) {
90
- if ( _valueSerializer != null ) {
91
- _valueSerializer . serialize ( value . get (), jgen , provider ) ;
92
- } else {
93
- provider . defaultSerializeValue ( value .get (), jgen );
148
+ if (opt .isPresent ()) {
149
+ Object value = opt . get ();
150
+ JsonSerializer < Object > ser = _valueSerializer ;
151
+ if ( ser == null ) {
152
+ ser = _findSerializer ( provider , value .getClass () );
94
153
}
154
+ ser .serialize (value , gen , provider );
95
155
} else {
96
- provider .defaultSerializeNull (jgen );
156
+ provider .defaultSerializeNull (gen );
97
157
}
98
158
}
99
159
100
160
@ Override
101
- public void serializeWithType (Optional <?> value ,
102
- JsonGenerator jgen , SerializerProvider provider ,
161
+ public void serializeWithType (Optional <?> opt ,
162
+ JsonGenerator gen , SerializerProvider provider ,
103
163
TypeSerializer typeSer ) throws IOException
104
164
{
105
- if (value .isPresent ()) {
165
+ if (opt .isPresent ()) {
166
+ Object value = opt .get ();
106
167
JsonSerializer <Object > ser = _valueSerializer ;
107
168
if (ser == null ) {
108
- // note: could improve by retaining property... needed?
109
- ser = provider .findValueSerializer (_valueType (), null );
169
+ ser = _findSerializer (provider , value .getClass ());
110
170
}
111
- ser .serializeWithType (value . get (), jgen , provider , typeSer );
171
+ ser .serializeWithType (value , gen , provider , typeSer );
112
172
} else {
113
- provider .defaultSerializeNull (jgen );
173
+ provider .defaultSerializeNull (gen );
114
174
}
115
175
}
116
176
177
+ /*
178
+ /**********************************************************
179
+ /* Introspection support
180
+ /**********************************************************
181
+ */
182
+
117
183
@ Override
118
184
public void acceptJsonFormatVisitor (JsonFormatVisitorWrapper visitor , JavaType typeHint ) throws JsonMappingException
119
185
{
120
- JavaType valueType = _valueType ();
121
- if (valueType != null ) {
122
- JsonSerializer <?> ser = _valueSerializer ;
123
- if (ser == null ) {
124
- ser = visitor .getProvider ().findValueSerializer (valueType , null );
125
- }
126
- ser .acceptJsonFormatVisitor (visitor , valueType );
127
- } else {
128
- super .acceptJsonFormatVisitor (visitor , typeHint );
186
+ JsonSerializer <?> ser = _valueSerializer ;
187
+ if (ser == null ) {
188
+ ser = _findSerializer (visitor .getProvider (), _referredType .getRawClass ());
129
189
}
190
+ ser .acceptJsonFormatVisitor (visitor , _referredType );
130
191
}
131
192
132
- protected JavaType _valueType () {
133
- JavaType valueType = _optionalType .containedType (0 );
193
+ /*
194
+ /**********************************************************
195
+ /* Misc other
196
+ /**********************************************************
197
+ */
198
+
199
+ protected static JavaType _valueType (JavaType optionalType ) {
200
+ JavaType valueType = optionalType .containedType (0 );
134
201
if (valueType == null ) {
135
202
valueType = TypeFactory .unknownType ();
136
203
}
137
204
return valueType ;
138
205
}
206
+
207
+ /**
208
+ * Helper method that encapsulates logic of retrieving and caching required
209
+ * serializer.
210
+ */
211
+ protected final JsonSerializer <Object > _findSerializer (SerializerProvider provider , Class <?> type )
212
+ throws JsonMappingException
213
+ {
214
+ PropertySerializerMap .SerializerAndMapResult result = _dynamicSerializers
215
+ .findAndAddPrimarySerializer (type , provider , _property );
216
+ if (_dynamicSerializers != result .map ) {
217
+ _dynamicSerializers = result .map ;
218
+ }
219
+ JsonSerializer <Object > ser = result .serializer ;
220
+ // 26-Jun-2015, tatu: Sub-optimal if we do not cache unwrapped instance; but on plus side
221
+ // construction is a cheap operation, so won't add huge overhead
222
+ if (_unwrapper != null ) {
223
+ ser = ser .unwrappingSerializer (_unwrapper );
224
+ }
225
+ return ser ;
226
+ }
139
227
}
140
-
0 commit comments