• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DefaultSerializerProvider()66     protected DefaultSerializerProvider() { super(); }
67 
DefaultSerializerProvider(SerializerProvider src, SerializationConfig config,SerializerFactory f)68     protected DefaultSerializerProvider(SerializerProvider src,
69             SerializationConfig config,SerializerFactory f) {
70         super(src, config, f);
71     }
72 
DefaultSerializerProvider(DefaultSerializerProvider src)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      */
createInstance(SerializationConfig config, SerializerFactory jsf)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      */
copy()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
serializerInstance(Annotated annotated, Object serDef)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
includeFilterInstance(BeanPropertyDefinition forProperty, Class<?> filterClass)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
includeFilterSuppressNulls(Object filter)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
findObjectId(Object forPojo, ObjectIdGenerator<?> generatorType)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      */
_createObjectIdMap()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      */
hasSerializerFor(Class<?> cls, AtomicReference<Throwable> cause)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
getGenerator()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      */
serializeValue(JsonGenerator gen, Object value)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      */
serializeValue(JsonGenerator gen, Object value, JavaType rootType)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      */
serializeValue(JsonGenerator gen, Object value, JavaType rootType, JsonSerializer<Object> ser)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      */
serializePolymorphic(JsonGenerator gen, Object value, JavaType rootType, JsonSerializer<Object> valueSer, TypeSerializer typeSer)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 
_serialize(JsonGenerator gen, Object value, JsonSerializer<Object> ser, PropertyName rootName)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 
_serialize(JsonGenerator gen, Object value, JsonSerializer<Object> ser)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      */
_serializeNull(JsonGenerator gen)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 
_wrapAsIOE(JsonGenerator g, Exception e)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      */
cachedSerializersCount()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      */
flushCachedSerializers()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      */
acceptJsonFormatVisitor(JavaType javaType, JsonFormatVisitorWrapper visitor)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
generateJsonSchema(Class<?> type)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 
Impl()609         public Impl() { super(); }
Impl(Impl src)610         public Impl(Impl src) { super(src); }
611 
Impl(SerializerProvider src, SerializationConfig config, SerializerFactory f)612         protected Impl(SerializerProvider src, SerializationConfig config,
613                 SerializerFactory f) {
614             super(src, config, f);
615         }
616 
617         @Override
copy()618         public DefaultSerializerProvider copy()
619         {
620             if (getClass() != Impl.class) {
621                 return super.copy();
622             }
623             return new Impl(this);
624         }
625 
626         @Override
createInstance(SerializationConfig config, SerializerFactory jsf)627         public Impl createInstance(SerializationConfig config, SerializerFactory jsf) {
628             return new Impl(this, config, jsf);
629         }
630     }
631 }
632