1 package com.fasterxml.jackson.databind.ser;
2
3 import java.io.IOException;
4 import java.util.*;
5 import java.util.concurrent.atomic.AtomicReference;
6
7 import com.fasterxml.jackson.annotation.ObjectIdGenerator;
8 import com.fasterxml.jackson.core.JsonGenerator;
9 import com.fasterxml.jackson.databind.*;
10 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
11 import com.fasterxml.jackson.databind.introspect.Annotated;
12 import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
13 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
14 import com.fasterxml.jackson.databind.jsonschema.SchemaAware;
15 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
16 import com.fasterxml.jackson.databind.node.ObjectNode;
17 import com.fasterxml.jackson.databind.ser.impl.WritableObjectId;
18 import com.fasterxml.jackson.databind.util.ClassUtil;
19
20 /**
21 * Standard implementation used by {@link ObjectMapper}:
22 * adds methods only exposed to {@link ObjectMapper},
23 * as well as constructors.
24 *<p>
25 * Note that class is abstract just because it does not
26 * define {@link #createInstance} method.
27 *<p>
28 * Also note that all custom {@link SerializerProvider}
29 * implementations must sub-class this class: {@link ObjectMapper}
30 * requires this type, not basic provider type.
31 */
32 public abstract class DefaultSerializerProvider
33 extends SerializerProvider
34 implements java.io.Serializable // since 2.1; only because ObjectWriter needs it
35 {
36 private static final long serialVersionUID = 1L;
37
38 /*
39 /**********************************************************
40 /* State, for non-blueprint instances
41 /**********************************************************
42 */
43
44 /**
45 * Per-serialization map Object Ids that have seen so far, iff
46 * Object Id handling is enabled.
47 */
48 protected transient Map<Object, WritableObjectId> _seenObjectIds;
49
50 protected transient ArrayList<ObjectIdGenerator<?>> _objectIdGenerators;
51
52 /**
53 * Generator used for serialization. Needed mostly for error reporting
54 * purposes.
55 *
56 * @since 2.8
57 */
58 protected transient JsonGenerator _generator;
59
60 /*
61 /**********************************************************
62 /* Life-cycle
63 /**********************************************************
64 */
65
66 protected DefaultSerializerProvider() { super(); }
67
68 protected DefaultSerializerProvider(SerializerProvider src,
69 SerializationConfig config,SerializerFactory f) {
70 super(src, config, f);
71 }
72
73 protected DefaultSerializerProvider(DefaultSerializerProvider src) {
74 super(src);
75 }
76
77 /**
78 * Method that sub-classes need to implement: used to create a non-blueprint instances
79 * from the blueprint.
80 * This is needed to retain state during serialization.
81 */
82 public abstract DefaultSerializerProvider createInstance(SerializationConfig config,
83 SerializerFactory jsf);
84
85 /**
86 * Method needed to ensure that {@link ObjectMapper#copy} will work
87 * properly; specifically, that caches are cleared, but settings
88 * will otherwise remain identical; and that no sharing of state
89 * occurs.
90 *
91 * @since 2.5
92 */
93 public DefaultSerializerProvider copy() {
94 throw new IllegalStateException("DefaultSerializerProvider sub-class not overriding copy()");
95 }
96
97 /*
98 /**********************************************************
99 /* Abstract method impls, factory methods
100 /**********************************************************
101 */
102
103 @Override
104 public JsonSerializer<Object> serializerInstance(Annotated annotated, Object serDef)
105 throws JsonMappingException
106 {
107 if (serDef == null) {
108 return null;
109 }
110 JsonSerializer<?> ser;
111
112 if (serDef instanceof JsonSerializer) {
113 ser = (JsonSerializer<?>) serDef;
114 } else {
115 // Alas, there's no way to force return type of "either class
116 // X or Y" -- need to throw an exception after the fact
117 if (!(serDef instanceof Class)) {
118 reportBadDefinition(annotated.getType(),
119 "AnnotationIntrospector returned serializer definition of type "
120 +serDef.getClass().getName()+"; expected type JsonSerializer or Class<JsonSerializer> instead");
121 }
122 Class<?> serClass = (Class<?>)serDef;
123 // there are some known "no class" markers to consider too:
124 if (serClass == JsonSerializer.None.class || ClassUtil.isBogusClass(serClass)) {
125 return null;
126 }
127 if (!JsonSerializer.class.isAssignableFrom(serClass)) {
128 reportBadDefinition(annotated.getType(),
129 "AnnotationIntrospector returned Class "
130 +serClass.getName()+"; expected Class<JsonSerializer>");
131 }
132 HandlerInstantiator hi = _config.getHandlerInstantiator();
133 ser = (hi == null) ? null : hi.serializerInstance(_config, annotated, serClass);
134 if (ser == null) {
135 ser = (JsonSerializer<?>) ClassUtil.createInstance(serClass,
136 _config.canOverrideAccessModifiers());
137 }
138 }
139 return (JsonSerializer<Object>) _handleResolvable(ser);
140 }
141
142 @Override
143 public Object includeFilterInstance(BeanPropertyDefinition forProperty,
144 Class<?> filterClass)
145 {
146 if (filterClass == null) {
147 return null;
148 }
149 HandlerInstantiator hi = _config.getHandlerInstantiator();
150 Object filter = (hi == null) ? null : hi.includeFilterInstance(_config, forProperty, filterClass);
151 if (filter == null) {
152 filter = ClassUtil.createInstance(filterClass,
153 _config.canOverrideAccessModifiers());
154 }
155 return filter;
156 }
157
158 @Override
159 public boolean includeFilterSuppressNulls(Object filter) throws JsonMappingException
160 {
161 if (filter == null) {
162 return true;
163 }
164 // should let filter decide what to do with nulls:
165 // But just case, let's handle unexpected (from our perspective) problems explicitly
166 try {
167 return filter.equals(null);
168 } catch (Throwable t) {
169 String msg = String.format(
170 "Problem determining whether filter of type '%s' should filter out `null` values: (%s) %s",
171 filter.getClass().getName(), t.getClass().getName(), ClassUtil.exceptionMessage(t));
172 reportBadDefinition(filter.getClass(), msg, t);
173 return false; // never gets here
174 }
175 }
176
177 /*
178 /**********************************************************
179 /* Object Id handling
180 /**********************************************************
181 */
182
183 @Override
184 public WritableObjectId findObjectId(Object forPojo, ObjectIdGenerator<?> generatorType)
185 {
186 if (_seenObjectIds == null) {
187 _seenObjectIds = _createObjectIdMap();
188 } else {
189 WritableObjectId oid = _seenObjectIds.get(forPojo);
190 if (oid != null) {
191 return oid;
192 }
193 }
194 // Not seen yet; must add an entry, return it. For that, we need generator
195 ObjectIdGenerator<?> generator = null;
196
197 if (_objectIdGenerators == null) {
198 _objectIdGenerators = new ArrayList<ObjectIdGenerator<?>>(8);
199 } else {
200 for (int i = 0, len = _objectIdGenerators.size(); i < len; ++i) {
201 ObjectIdGenerator<?> gen = _objectIdGenerators.get(i);
202 if (gen.canUseFor(generatorType)) {
203 generator = gen;
204 break;
205 }
206 }
207 }
208 if (generator == null) {
209 generator = generatorType.newForSerialization(this);
210 _objectIdGenerators.add(generator);
211 }
212 WritableObjectId oid = new WritableObjectId(generator);
213 _seenObjectIds.put(forPojo, oid);
214 return oid;
215 }
216
217 /**
218 * Overridable helper method used for creating {@link java.util.Map}
219 * used for storing mappings from serializable objects to their
220 * Object Ids.
221 *
222 * @since 2.3
223 */
224 protected Map<Object,WritableObjectId> _createObjectIdMap()
225 {
226 /* 06-Aug-2013, tatu: We may actually want to use equality,
227 * instead of identity... so:
228 */
229 if (isEnabled(SerializationFeature.USE_EQUALITY_FOR_OBJECT_ID)) {
230 return new HashMap<Object,WritableObjectId>();
231 }
232 return new IdentityHashMap<Object,WritableObjectId>();
233 }
234
235 /*
236 /**********************************************************
237 /* Extended API: simple accesors
238 /**********************************************************
239 */
240
241 /**
242 * Method that can be called to see if this serializer provider
243 * can find a serializer for an instance of given class.
244 *<p>
245 * Note that no Exceptions are thrown, including unchecked ones:
246 * implementations are to swallow exceptions if necessary.
247 */
248 public boolean hasSerializerFor(Class<?> cls, AtomicReference<Throwable> cause)
249 {
250 // 07-Nov-2015, tatu: One special case, Object.class; will work only if
251 // empty beans are allowed or custom serializer registered. Easiest to
252 // check here.
253 if (cls == Object.class) {
254 if (!_config.isEnabled(SerializationFeature.FAIL_ON_EMPTY_BEANS)) {
255 return true;
256 }
257 }
258
259 try {
260 JsonSerializer<?> ser = _findExplicitUntypedSerializer(cls);
261 return (ser != null);
262 } catch (JsonMappingException e) {
263 if (cause != null) {
264 cause.set(e);
265 }
266 } catch (RuntimeException e) {
267 if (cause == null) { // earlier behavior
268 throw e;
269 }
270 cause.set(e);
271 }
272 return false;
273 }
274
275 /**
276 * Accessor for the {@link JsonGenerator} currently in use for serializing
277 * content. Null for blueprint instances; non-null for actual active
278 * provider instances.
279 *
280 * @since 2.8
281 */
282 @Override
283 public JsonGenerator getGenerator() {
284 return _generator;
285 }
286
287 /*
288 /**********************************************************
289 /* Extended API called by ObjectMapper: value serialization
290 /**********************************************************
291 */
292
293 /**
294 * The method to be called by {@link ObjectMapper} and {@link ObjectWriter}
295 * for serializing given value, using serializers that
296 * this provider has access to (via caching and/or creating new serializers
297 * as need be).
298 */
299 public void serializeValue(JsonGenerator gen, Object value) throws IOException
300 {
301 _generator = gen;
302 if (value == null) {
303 _serializeNull(gen);
304 return;
305 }
306 final Class<?> cls = value.getClass();
307 // true, since we do want to cache root-level typed serializers (ditto for null property)
308 final JsonSerializer<Object> ser = findTypedValueSerializer(cls, true, null);
309 PropertyName rootName = _config.getFullRootName();
310 if (rootName == null) { // not explicitly specified
311 if (_config.isEnabled(SerializationFeature.WRAP_ROOT_VALUE)) {
312 _serialize(gen, value, ser, _config.findRootName(cls));
313 return;
314 }
315 } else if (!rootName.isEmpty()) {
316 _serialize(gen, value, ser, rootName);
317 return;
318 }
319 _serialize(gen, value, ser);
320 }
321
322 /**
323 * The method to be called by {@link ObjectMapper} and {@link ObjectWriter}
324 * for serializing given value (assumed to be of specified root type,
325 * instead of runtime type of value),
326 * using serializers that
327 * this provider has access to (via caching and/or creating new serializers
328 * as need be),
329 *
330 * @param rootType Type to use for locating serializer to use, instead of actual
331 * runtime type. Must be actual type, or one of its super types
332 */
333 public void serializeValue(JsonGenerator gen, Object value, JavaType rootType) throws IOException
334 {
335 _generator = gen;
336 if (value == null) {
337 _serializeNull(gen);
338 return;
339 }
340 // Let's ensure types are compatible at this point
341 if (!rootType.getRawClass().isAssignableFrom(value.getClass())) {
342 _reportIncompatibleRootType(value, rootType);
343 }
344 // root value, not reached via property:
345 JsonSerializer<Object> ser = findTypedValueSerializer(rootType, true, null);
346 PropertyName rootName = _config.getFullRootName();
347 if (rootName == null) { // not explicitly specified
348 if (_config.isEnabled(SerializationFeature.WRAP_ROOT_VALUE)) {
349 _serialize(gen, value, ser, _config.findRootName(rootType));
350 return;
351 }
352 } else if (!rootName.isEmpty()) {
353 _serialize(gen, value, ser, rootName);
354 return;
355 }
356 _serialize(gen, value, ser);
357 }
358
359 /**
360 * The method to be called by {@link ObjectWriter}
361 * for serializing given value (assumed to be of specified root type,
362 * instead of runtime type of value), when it may know specific
363 * {@link JsonSerializer} to use.
364 *
365 * @param rootType Type to use for locating serializer to use, instead of actual
366 * runtime type, if no serializer is passed
367 * @param ser Root Serializer to use, if not null
368 *
369 * @since 2.1
370 */
371 public void serializeValue(JsonGenerator gen, Object value, JavaType rootType,
372 JsonSerializer<Object> ser) throws IOException
373 {
374 _generator = gen;
375 if (value == null) {
376 _serializeNull(gen);
377 return;
378 }
379 // Let's ensure types are compatible at this point
380 if ((rootType != null) && !rootType.getRawClass().isAssignableFrom(value.getClass())) {
381 _reportIncompatibleRootType(value, rootType);
382 }
383 // root value, not reached via property:
384 if (ser == null) {
385 ser = findTypedValueSerializer(rootType, true, null);
386 }
387 PropertyName rootName = _config.getFullRootName();
388 if (rootName == null) { // not explicitly specified
389 if (_config.isEnabled(SerializationFeature.WRAP_ROOT_VALUE)) {
390 rootName = (rootType == null)
391 ? _config.findRootName(value.getClass())
392 : _config.findRootName(rootType);
393 _serialize(gen, value, ser, rootName);
394 return;
395 }
396 } else if (!rootName.isEmpty()) {
397 _serialize(gen, value, ser, rootName);
398 return;
399 }
400 _serialize(gen, value, ser);
401 }
402
403 /**
404 * Alternate serialization call used for polymorphic types, when {@link TypeSerializer}
405 * is already known, but the actual serializer may or may not be.
406 *
407 * @since 2.6
408 */
409 public void serializePolymorphic(JsonGenerator gen, Object value, JavaType rootType,
410 JsonSerializer<Object> valueSer, TypeSerializer typeSer)
411 throws IOException
412 {
413 _generator = gen;
414 if (value == null) {
415 _serializeNull(gen);
416 return;
417 }
418 // Let's ensure types are compatible at this point
419 if ((rootType != null) && !rootType.getRawClass().isAssignableFrom(value.getClass())) {
420 _reportIncompatibleRootType(value, rootType);
421 }
422 /* 12-Jun-2015, tatu: nominal root type is necessary for Maps at least;
423 * possibly collections, but can cause problems for other polymorphic
424 * types. We really need to distinguish between serialization type,
425 * base type; but right we don't. Hence this check
426 */
427 if (valueSer == null) {
428 if ((rootType != null) && rootType.isContainerType()) {
429 valueSer = findValueSerializer(rootType, null);
430 } else {
431 valueSer = findValueSerializer(value.getClass(), null);
432 }
433 }
434
435 final boolean wrap;
436 PropertyName rootName = _config.getFullRootName();
437 if (rootName == null) {
438 wrap = _config.isEnabled(SerializationFeature.WRAP_ROOT_VALUE);
439 if (wrap) {
440 gen.writeStartObject();
441 PropertyName pname = _config.findRootName(value.getClass());
442 gen.writeFieldName(pname.simpleAsEncoded(_config));
443 }
444 } else if (rootName.isEmpty()) {
445 wrap = false;
446 } else {
447 wrap = true;
448 gen.writeStartObject();
449 gen.writeFieldName(rootName.getSimpleName());
450 }
451 try {
452 valueSer.serializeWithType(value, gen, this, typeSer);
453 if (wrap) {
454 gen.writeEndObject();
455 }
456 } catch (Exception e) {
457 throw _wrapAsIOE(gen, e);
458 }
459 }
460
461 private final void _serialize(JsonGenerator gen, Object value,
462 JsonSerializer<Object> ser, PropertyName rootName)
463 throws IOException
464 {
465 try {
466 gen.writeStartObject();
467 gen.writeFieldName(rootName.simpleAsEncoded(_config));
468 ser.serialize(value, gen, this);
469 gen.writeEndObject();
470 } catch (Exception e) {
471 throw _wrapAsIOE(gen, e);
472 }
473 }
474
475 private final void _serialize(JsonGenerator gen, Object value,
476 JsonSerializer<Object> ser)
477 throws IOException
478 {
479 try {
480 ser.serialize(value, gen, this);
481 } catch (Exception e) {
482 throw _wrapAsIOE(gen, e);
483 }
484 }
485
486 /**
487 * Helper method called when root value to serialize is null
488 *
489 * @since 2.3
490 */
491 protected void _serializeNull(JsonGenerator gen) throws IOException
492 {
493 JsonSerializer<Object> ser = getDefaultNullValueSerializer();
494 try {
495 ser.serialize(null, gen, this);
496 } catch (Exception e) {
497 throw _wrapAsIOE(gen, e);
498 }
499 }
500
501 private IOException _wrapAsIOE(JsonGenerator g, Exception e) {
502 if (e instanceof IOException) {
503 return (IOException) e;
504 }
505 String msg = ClassUtil.exceptionMessage(e);
506 if (msg == null) {
507 msg = "[no message for "+e.getClass().getName()+"]";
508 }
509 return new JsonMappingException(g, msg, e);
510 }
511
512 /*
513 /********************************************************
514 /* Access to caching details
515 /********************************************************
516 */
517
518 /**
519 * Method that can be used to determine how many serializers this
520 * provider is caching currently
521 * (if it does caching: default implementation does)
522 * Exact count depends on what kind of serializers get cached;
523 * default implementation caches all serializers, including ones that
524 * are eagerly constructed (for optimal access speed)
525 *<p>
526 * The main use case for this method is to allow conditional flushing of
527 * serializer cache, if certain number of entries is reached.
528 */
529 public int cachedSerializersCount() {
530 return _serializerCache.size();
531 }
532
533 /**
534 * Method that will drop all serializers currently cached by this provider.
535 * This can be used to remove memory usage (in case some serializers are
536 * only used once or so), or to force re-construction of serializers after
537 * configuration changes for mapper than owns the provider.
538 */
539 public void flushCachedSerializers() {
540 _serializerCache.flush();
541 }
542
543 /*
544 /**********************************************************
545 /* Extended API called by ObjectMapper: other
546 /**********************************************************
547 */
548
549 /**
550 * The method to be called by {@link ObjectMapper} and {@link ObjectWriter}
551 * to to expose the format of the given to to the given visitor
552 *
553 * @param javaType The type for which to generate format
554 * @param visitor the visitor to accept the format
555 */
556 public void acceptJsonFormatVisitor(JavaType javaType, JsonFormatVisitorWrapper visitor)
557 throws JsonMappingException
558 {
559 if (javaType == null) {
560 throw new IllegalArgumentException("A class must be provided");
561 }
562 /* no need for embedded type information for JSON schema generation (all
563 * type information it needs is accessible via "untyped" serializer)
564 */
565 visitor.setProvider(this);
566 findValueSerializer(javaType, null).acceptJsonFormatVisitor(visitor, javaType);
567 }
568
569 /**
570 * The method to be called by {@link ObjectMapper}
571 * to generate <a href="http://json-schema.org/">JSON schema</a> for
572 * given type.
573 *
574 * @param type The type for which to generate schema
575 *
576 * @deprecated Should not be used any more
577 */
578 @Deprecated // since 2.6
579 public com.fasterxml.jackson.databind.jsonschema.JsonSchema generateJsonSchema(Class<?> type)
580 throws JsonMappingException
581 {
582 /* no need for embedded type information for JSON schema generation (all
583 * type information it needs is accessible via "untyped" serializer)
584 */
585 JsonSerializer<Object> ser = findValueSerializer(type, null);
586 JsonNode schemaNode = (ser instanceof SchemaAware) ?
587 ((SchemaAware) ser).getSchema(this, null) : com.fasterxml.jackson.databind.jsonschema.JsonSchema.getDefaultSchemaNode();
588 if (!(schemaNode instanceof ObjectNode)) {
589 throw new IllegalArgumentException("Class " + type.getName()
590 +" would not be serialized as a JSON object and therefore has no schema");
591 }
592 return new com.fasterxml.jackson.databind.jsonschema.JsonSchema((ObjectNode) schemaNode);
593 }
594
595
596 /*
597 /**********************************************************
598 /* Helper classes
599 /**********************************************************
600 */
601
602 /**
603 * Concrete implementation that defines factory method(s),
604 * defined as final.
605 */
606 public final static class Impl extends DefaultSerializerProvider {
607 private static final long serialVersionUID = 1L;
608
609 public Impl() { super(); }
610 public Impl(Impl src) { super(src); }
611
612 protected Impl(SerializerProvider src, SerializationConfig config,
613 SerializerFactory f) {
614 super(src, config, f);
615 }
616
617 @Override
618 public DefaultSerializerProvider copy()
619 {
620 if (getClass() != Impl.class) {
621 return super.copy();
622 }
623 return new Impl(this);
624 }
625
626 @Override
627 public Impl createInstance(SerializationConfig config, SerializerFactory jsf) {
628 return new Impl(this, config, jsf);
629 }
630 }
631 }
632