• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.ser;
2 
3 import java.io.IOException;
4 import java.lang.annotation.Annotation;
5 import java.lang.reflect.Field;
6 import java.lang.reflect.Method;
7 import java.lang.reflect.Type;
8 import java.util.HashMap;
9 
10 import com.fasterxml.jackson.annotation.JsonInclude;
11 import com.fasterxml.jackson.core.JsonGenerator;
12 import com.fasterxml.jackson.core.SerializableString;
13 import com.fasterxml.jackson.core.io.SerializedString;
14 import com.fasterxml.jackson.databind.*;
15 import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
16 import com.fasterxml.jackson.databind.introspect.*;
17 import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
18 import com.fasterxml.jackson.databind.jsonschema.SchemaAware;
19 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
20 import com.fasterxml.jackson.databind.node.ObjectNode;
21 import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
22 import com.fasterxml.jackson.databind.ser.impl.UnwrappingBeanPropertyWriter;
23 import com.fasterxml.jackson.databind.ser.std.BeanSerializerBase;
24 import com.fasterxml.jackson.databind.util.Annotations;
25 import com.fasterxml.jackson.databind.util.ClassUtil;
26 import com.fasterxml.jackson.databind.util.NameTransformer;
27 
28 /**
29  * Base bean property handler class, which implements common parts of
30  * reflection-based functionality for accessing a property value and serializing
31  * it.
32  * <p>
33  * Note that current design tries to keep instances immutable (semi-functional
34  * style); mostly because these instances are exposed to application code and
35  * this is to reduce likelihood of data corruption and synchronization issues.
36  */
37 @JacksonStdImpl
38 // since 2.6. NOTE: sub-classes typically are not
39 public class BeanPropertyWriter extends PropertyWriter // which extends
40                                                        // `ConcreteBeanPropertyBase`
41         implements java.io.Serializable // since 2.6
42 {
43     // As of 2.7
44     private static final long serialVersionUID = 1L;
45 
46     /**
47      * Marker object used to indicate "do not serialize if empty"
48      */
49     public final static Object MARKER_FOR_EMPTY = JsonInclude.Include.NON_EMPTY;
50 
51     /*
52     /***********************************************************
53     /* Basic property metadata: name, type, other
54     /***********************************************************
55      */
56 
57     /**
58      * Logical name of the property; will be used as the field name under which
59      * value for the property is written.
60      * <p>
61      * NOTE: do NOT change name of this field; it is accessed by Afterburner
62      * module (until 2.4; not directly from 2.5) ALSO NOTE: ... and while it
63      * really ought to be `SerializableString`, changing that is also
64      * binary-incompatible change. So nope.
65      */
66     protected final SerializedString _name;
67 
68     /**
69      * Wrapper name to use for this element, if any
70      *
71      * @since 2.2
72      */
73     protected final PropertyName _wrapperName;
74 
75     /**
76      * Type property is declared to have, either in class definition or
77      * associated annotations.
78      */
79     protected final JavaType _declaredType;
80 
81     /**
82      * Type to use for locating serializer; normally same as return type of the
83      * accessor method, but may be overridden by annotations.
84      */
85     protected final JavaType _cfgSerializationType;
86 
87     /**
88      * Base type of the property, if the declared type is "non-trivial"; meaning
89      * it is either a structured type (collection, map, array), or
90      * parameterized. Used to retain type information about contained type,
91      * which is mostly necessary if type meta-data is to be included.
92      */
93     protected JavaType _nonTrivialBaseType;
94 
95     /**
96      * Annotations from context (most often, class that declares property, or in
97      * case of sub-class serializer, from that sub-class)
98      * <p>
99      * NOTE: transient just to support JDK serializability; Annotations do not
100      * serialize. At all.
101      */
102     protected final transient Annotations _contextAnnotations;
103 
104     /*
105     /***********************************************************
106     /* Settings for accessing property value to serialize
107     /***********************************************************
108      */
109 
110     /**
111      * Member (field, method) that represents property and allows access to
112      * associated annotations.
113      */
114     protected final AnnotatedMember _member;
115 
116     /**
117      * Accessor method used to get property value, for method-accessible
118      * properties. Null if and only if {@link #_field} is null.
119      * <p>
120      * `transient` (and non-final) only to support JDK serializability.
121      */
122     protected transient Method _accessorMethod;
123 
124     /**
125      * Field that contains the property value for field-accessible properties.
126      * Null if and only if {@link #_accessorMethod} is null.
127      * <p>
128      * `transient` (and non-final) only to support JDK serializability.
129      */
130     protected transient Field _field;
131 
132     /*
133     /***********************************************************
134     /* Serializers needed
135     /***********************************************************
136      */
137 
138     /**
139      * Serializer to use for writing out the value: null if it cannot be known
140      * statically; non-null if it can.
141      */
142     protected JsonSerializer<Object> _serializer;
143 
144     /**
145      * Serializer used for writing out null values, if any: if null, null values
146      * are to be suppressed.
147      */
148     protected JsonSerializer<Object> _nullSerializer;
149 
150     /**
151      * If property being serialized needs type information to be included this
152      * is the type serializer to use. Declared type (possibly augmented with
153      * annotations) of property is used for determining exact mechanism to use
154      * (compared to actual runtime type used for serializing actual state).
155      */
156     protected TypeSerializer _typeSerializer;
157 
158     /**
159      * In case serializer is not known statically (i.e. <code>_serializer</code>
160      * is null), we will use a lookup structure for storing dynamically resolved
161      * mapping from type(s) to serializer(s).
162      */
163     protected transient PropertySerializerMap _dynamicSerializers;
164 
165     /*
166     /***********************************************************
167     /* Filtering
168     /***********************************************************
169      */
170 
171     /**
172      * Whether null values are to be suppressed (nothing written out if value is
173      * null) or not. Note that this is a configuration value during
174      * construction, and actual handling relies on setting (or not) of
175      * {@link #_nullSerializer}.
176      */
177     protected final boolean _suppressNulls;
178 
179     /**
180      * Value that is considered default value of the property; used for
181      * default-value-suppression if enabled.
182      */
183     protected final Object _suppressableValue;
184 
185     /**
186      * Alternate set of property writers used when view-based filtering is
187      * available for the Bean.
188      */
189     protected final Class<?>[] _includeInViews;
190 
191     /*
192     /**********************************************************
193     /* Opaqueinternal data that bean serializer factory and
194     /* bean serializers can add.
195     /**********************************************************
196      */
197 
198     protected transient HashMap<Object, Object> _internalSettings;
199 
200     /*
201     /***********************************************************
202     /* Construction, configuration
203     /***********************************************************
204      */
205 
206     /**
207      * @since 2.9 (added `includeInViews` since 2.8)
208      */
209     @SuppressWarnings("unchecked")
BeanPropertyWriter(BeanPropertyDefinition propDef, AnnotatedMember member, Annotations contextAnnotations, JavaType declaredType, JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType, boolean suppressNulls, Object suppressableValue, Class<?>[] includeInViews)210     public BeanPropertyWriter(BeanPropertyDefinition propDef,
211             AnnotatedMember member, Annotations contextAnnotations,
212             JavaType declaredType,
213             JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType,
214             boolean suppressNulls, Object suppressableValue,
215             Class<?>[] includeInViews)
216     {
217         super(propDef);
218         _member = member;
219         _contextAnnotations = contextAnnotations;
220 
221         _name = new SerializedString(propDef.getName());
222         _wrapperName = propDef.getWrapperName();
223 
224         _declaredType = declaredType;
225         _serializer = (JsonSerializer<Object>) ser;
226         _dynamicSerializers = (ser == null) ? PropertySerializerMap
227                 .emptyForProperties() : null;
228         _typeSerializer = typeSer;
229         _cfgSerializationType = serType;
230 
231         if (member instanceof AnnotatedField) {
232             _accessorMethod = null;
233             _field = (Field) member.getMember();
234         } else if (member instanceof AnnotatedMethod) {
235             _accessorMethod = (Method) member.getMember();
236             _field = null;
237         } else {
238             // 01-Dec-2014, tatu: Used to be illegal, but now explicitly allowed
239             // for virtual props
240             _accessorMethod = null;
241             _field = null;
242         }
243         _suppressNulls = suppressNulls;
244         _suppressableValue = suppressableValue;
245 
246         // this will be resolved later on, unless nulls are to be suppressed
247         _nullSerializer = null;
248         _includeInViews = includeInViews;
249     }
250 
251     @Deprecated // Since 2.9
BeanPropertyWriter(BeanPropertyDefinition propDef, AnnotatedMember member, Annotations contextAnnotations, JavaType declaredType, JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType, boolean suppressNulls, Object suppressableValue)252     public BeanPropertyWriter(BeanPropertyDefinition propDef,
253             AnnotatedMember member, Annotations contextAnnotations,
254             JavaType declaredType,
255             JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType,
256             boolean suppressNulls, Object suppressableValue)
257     {
258         this(propDef, member, contextAnnotations, declaredType,
259                 ser, typeSer, serType, suppressNulls, suppressableValue,
260                 null);
261     }
262 
263     /**
264      * Constructor that may be of use to virtual properties, when there is need
265      * for the zero-arg ("default") constructor, and actual initialization is
266      * done after constructor call.
267      *
268      * @since 2.5
269      */
BeanPropertyWriter()270     protected BeanPropertyWriter() {
271         super(PropertyMetadata.STD_REQUIRED_OR_OPTIONAL);
272         _member = null;
273         _contextAnnotations = null;
274 
275         _name = null;
276         _wrapperName = null;
277         _includeInViews = null;
278 
279         _declaredType = null;
280         _serializer = null;
281         _dynamicSerializers = null;
282         _typeSerializer = null;
283         _cfgSerializationType = null;
284 
285         _accessorMethod = null;
286         _field = null;
287         _suppressNulls = false;
288         _suppressableValue = null;
289 
290         _nullSerializer = null;
291     }
292 
293     /**
294      * "Copy constructor" to be used by filtering sub-classes
295      */
BeanPropertyWriter(BeanPropertyWriter base)296     protected BeanPropertyWriter(BeanPropertyWriter base) {
297         this(base, base._name);
298     }
299 
300     /**
301      * @since 2.5
302      */
BeanPropertyWriter(BeanPropertyWriter base, PropertyName name)303     protected BeanPropertyWriter(BeanPropertyWriter base, PropertyName name) {
304         super(base);
305         /*
306          * 02-Dec-2014, tatu: This is a big mess, alas, what with dependency to
307          * MapperConfig to encode, and Afterburner having heartburn for
308          * SerializableString (vs SerializedString). Hope it can be
309          * resolved/reworked in 2.6 timeframe, if not for 2.5
310          */
311         _name = new SerializedString(name.getSimpleName());
312         _wrapperName = base._wrapperName;
313 
314         _contextAnnotations = base._contextAnnotations;
315         _declaredType = base._declaredType;
316 
317         _member = base._member;
318         _accessorMethod = base._accessorMethod;
319         _field = base._field;
320 
321         _serializer = base._serializer;
322         _nullSerializer = base._nullSerializer;
323         // one more thing: copy internal settings, if any
324         if (base._internalSettings != null) {
325             _internalSettings = new HashMap<Object, Object>(
326                     base._internalSettings);
327         }
328         _cfgSerializationType = base._cfgSerializationType;
329         _dynamicSerializers = base._dynamicSerializers;
330         _suppressNulls = base._suppressNulls;
331         _suppressableValue = base._suppressableValue;
332         _includeInViews = base._includeInViews;
333         _typeSerializer = base._typeSerializer;
334         _nonTrivialBaseType = base._nonTrivialBaseType;
335     }
336 
BeanPropertyWriter(BeanPropertyWriter base, SerializedString name)337     protected BeanPropertyWriter(BeanPropertyWriter base, SerializedString name) {
338         super(base);
339         _name = name;
340         _wrapperName = base._wrapperName;
341 
342         _member = base._member;
343         _contextAnnotations = base._contextAnnotations;
344         _declaredType = base._declaredType;
345         _accessorMethod = base._accessorMethod;
346         _field = base._field;
347         _serializer = base._serializer;
348         _nullSerializer = base._nullSerializer;
349         if (base._internalSettings != null) {
350             _internalSettings = new HashMap<Object, Object>(
351                     base._internalSettings);
352         }
353         _cfgSerializationType = base._cfgSerializationType;
354         _dynamicSerializers = base._dynamicSerializers;
355         _suppressNulls = base._suppressNulls;
356         _suppressableValue = base._suppressableValue;
357         _includeInViews = base._includeInViews;
358         _typeSerializer = base._typeSerializer;
359         _nonTrivialBaseType = base._nonTrivialBaseType;
360     }
361 
rename(NameTransformer transformer)362     public BeanPropertyWriter rename(NameTransformer transformer) {
363         String newName = transformer.transform(_name.getValue());
364         if (newName.equals(_name.toString())) {
365             return this;
366         }
367         return _new(PropertyName.construct(newName));
368     }
369 
370     /**
371      * Overridable factory method used by sub-classes
372      *
373      * @since 2.6
374      */
_new(PropertyName newName)375     protected BeanPropertyWriter _new(PropertyName newName) {
376         return new BeanPropertyWriter(this, newName);
377     }
378 
379     /**
380      * Method called to set, reset or clear the configured type serializer for
381      * property.
382      *
383      * @since 2.6
384      */
assignTypeSerializer(TypeSerializer typeSer)385     public void assignTypeSerializer(TypeSerializer typeSer) {
386         _typeSerializer = typeSer;
387     }
388 
389     /**
390      * Method called to assign value serializer for property
391      */
assignSerializer(JsonSerializer<Object> ser)392     public void assignSerializer(JsonSerializer<Object> ser) {
393         // may need to disable check in future?
394         if ((_serializer != null) && (_serializer != ser)) {
395             throw new IllegalStateException(String.format(
396                     "Cannot override _serializer: had a %s, trying to set to %s",
397                     ClassUtil.classNameOf(_serializer), ClassUtil.classNameOf(ser)));
398         }
399         _serializer = ser;
400     }
401 
402     /**
403      * Method called to assign null value serializer for property
404      */
assignNullSerializer(JsonSerializer<Object> nullSer)405     public void assignNullSerializer(JsonSerializer<Object> nullSer) {
406         // may need to disable check in future?
407         if ((_nullSerializer != null) && (_nullSerializer != nullSer)) {
408             throw new IllegalStateException(String.format(
409                     "Cannot override _nullSerializer: had a %s, trying to set to %s",
410                     ClassUtil.classNameOf(_nullSerializer), ClassUtil.classNameOf(nullSer)));
411         }
412         _nullSerializer = nullSer;
413     }
414 
415     /**
416      * Method called create an instance that handles details of unwrapping
417      * contained value.
418      */
unwrappingWriter(NameTransformer unwrapper)419     public BeanPropertyWriter unwrappingWriter(NameTransformer unwrapper) {
420         return new UnwrappingBeanPropertyWriter(this, unwrapper);
421     }
422 
423     /**
424      * Method called to define type to consider as "non-trivial" basetype,
425      * needed for dynamic serialization resolution for complex (usually
426      * container) types
427      */
setNonTrivialBaseType(JavaType t)428     public void setNonTrivialBaseType(JavaType t) {
429         _nonTrivialBaseType = t;
430     }
431 
432     /**
433      * Method called to ensure that the mutator has proper access rights to
434      * be called, as per configuration. Overridden by implementations that
435      * have mutators that require access, fields and setters.
436      *
437      * @since 2.8.3
438      */
fixAccess(SerializationConfig config)439     public void fixAccess(SerializationConfig config) {
440         _member.fixAccess(config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
441     }
442 
443     /*
444     /***********************************************************
445     /* JDK Serializability
446     /***********************************************************
447      */
448 
449     /*
450      * Ideally would not require mutable state, and instead would re-create with
451      * final settings. However, as things are, with sub-types and all, simplest
452      * to just change Field/Method value directly.
453      */
readResolve()454     Object readResolve() {
455         if (_member instanceof AnnotatedField) {
456             _accessorMethod = null;
457             _field = (Field) _member.getMember();
458         } else if (_member instanceof AnnotatedMethod) {
459             _accessorMethod = (Method) _member.getMember();
460             _field = null;
461         }
462         if (_serializer == null) {
463             _dynamicSerializers = PropertySerializerMap.emptyForProperties();
464         }
465         return this;
466     }
467 
468     /*
469     /************************************************************
470     /* BeanProperty impl
471     /***********************************************************
472      */
473 
474     // Note: also part of 'PropertyWriter'
475     @Override
getName()476     public String getName() {
477         return _name.getValue();
478     }
479 
480     // Note: also part of 'PropertyWriter'
481     @Override
getFullName()482     public PropertyName getFullName() { // !!! TODO: impl properly
483         return new PropertyName(_name.getValue());
484     }
485 
486     @Override
getType()487     public JavaType getType() {
488         return _declaredType;
489     }
490 
491     @Override
getWrapperName()492     public PropertyName getWrapperName() {
493         return _wrapperName;
494     }
495 
496     // Note: also part of 'PropertyWriter'
497     @Override
getAnnotation(Class<A> acls)498     public <A extends Annotation> A getAnnotation(Class<A> acls) {
499         return (_member == null) ? null : _member.getAnnotation(acls);
500     }
501 
502     // Note: also part of 'PropertyWriter'
503     @Override
getContextAnnotation(Class<A> acls)504     public <A extends Annotation> A getContextAnnotation(Class<A> acls) {
505         return (_contextAnnotations == null) ? null : _contextAnnotations
506                 .get(acls);
507     }
508 
509     @Override
getMember()510     public AnnotatedMember getMember() {
511         return _member;
512     }
513 
514     // @since 2.3 -- needed so it can be overridden by unwrapping writer
_depositSchemaProperty(ObjectNode propertiesNode, JsonNode schemaNode)515     protected void _depositSchemaProperty(ObjectNode propertiesNode,
516             JsonNode schemaNode) {
517         propertiesNode.set(getName(), schemaNode);
518     }
519 
520     /*
521     /***********************************************************
522     /* Managing and accessing of opaque internal settings
523     /* (used by extensions)
524     /***********************************************************
525      */
526 
527     /**
528      * Method for accessing value of specified internal setting.
529      *
530      * @return Value of the setting, if any; null if none.
531      */
getInternalSetting(Object key)532     public Object getInternalSetting(Object key) {
533         return (_internalSettings == null) ? null : _internalSettings.get(key);
534     }
535 
536     /**
537      * Method for setting specific internal setting to given value
538      *
539      * @return Old value of the setting, if any (null if none)
540      */
setInternalSetting(Object key, Object value)541     public Object setInternalSetting(Object key, Object value) {
542         if (_internalSettings == null) {
543             _internalSettings = new HashMap<Object, Object>();
544         }
545         return _internalSettings.put(key, value);
546     }
547 
548     /**
549      * Method for removing entry for specified internal setting.
550      *
551      * @return Existing value of the setting, if any (null if none)
552      */
removeInternalSetting(Object key)553     public Object removeInternalSetting(Object key) {
554         Object removed = null;
555         if (_internalSettings != null) {
556             removed = _internalSettings.remove(key);
557             // to reduce memory usage, let's also drop the Map itself, if empty
558             if (_internalSettings.size() == 0) {
559                 _internalSettings = null;
560             }
561         }
562         return removed;
563     }
564 
565     /*
566     /***********************************************************
567     /* Accessors
568     /***********************************************************
569      */
570 
getSerializedName()571     public SerializableString getSerializedName() {
572         return _name;
573     }
574 
hasSerializer()575     public boolean hasSerializer() {
576         return _serializer != null;
577     }
578 
hasNullSerializer()579     public boolean hasNullSerializer() {
580         return _nullSerializer != null;
581     }
582 
583     /**
584      * @since 2.6
585      */
getTypeSerializer()586     public TypeSerializer getTypeSerializer() {
587         return _typeSerializer;
588     }
589 
590     /**
591      * Accessor that will return true if this bean property has to support
592      * "unwrapping"; ability to replace POJO structural wrapping with optional
593      * name prefix and/or suffix (or in some cases, just removal of wrapper
594      * name).
595      * <p>
596      * Default implementation simply returns false.
597      *
598      * @since 2.3
599      */
isUnwrapping()600     public boolean isUnwrapping() {
601         return false;
602     }
603 
willSuppressNulls()604     public boolean willSuppressNulls() {
605         return _suppressNulls;
606     }
607 
608     /**
609      * Method called to check to see if this property has a name that would
610      * conflict with a given name.
611      *
612      * @since 2.6
613      */
wouldConflictWithName(PropertyName name)614     public boolean wouldConflictWithName(PropertyName name) {
615         if (_wrapperName != null) {
616             return _wrapperName.equals(name);
617         }
618         // Bit convoluted since our support for namespaces is spotty but:
619         return name.hasSimpleName(_name.getValue()) && !name.hasNamespace();
620     }
621 
622     // Needed by BeanSerializer#getSchema
getSerializer()623     public JsonSerializer<Object> getSerializer() {
624         return _serializer;
625     }
626 
getSerializationType()627     public JavaType getSerializationType() {
628         return _cfgSerializationType;
629     }
630 
631     @Deprecated // since 2.9
getRawSerializationType()632     public Class<?> getRawSerializationType() {
633         return (_cfgSerializationType == null) ? null : _cfgSerializationType
634                 .getRawClass();
635     }
636 
637     /**
638      * @deprecated Since 2.7, to be removed from 2.9, use {@link #getType()} instead.
639      */
640     @Deprecated
getPropertyType()641     public Class<?> getPropertyType() {
642         if (_accessorMethod != null) {
643             return _accessorMethod.getReturnType();
644         }
645         if (_field != null) {
646             return _field.getType();
647         }
648         return null;
649     }
650 
651     /**
652      * Get the generic property type of this property writer.
653      *
654      * @return The property type, or null if not found.
655      *
656      * @deprecated Since 2.7, to be removed from 2.9, use {@link #getType()} instead.
657      */
658     @Deprecated
getGenericPropertyType()659     public Type getGenericPropertyType() {
660         if (_accessorMethod != null) {
661             return _accessorMethod.getGenericReturnType();
662         }
663         if (_field != null) {
664             return _field.getGenericType();
665         }
666         return null;
667     }
668 
getViews()669     public Class<?>[] getViews() {
670         return _includeInViews;
671     }
672 
673     /*
674     /***********************************************************
675     /* PropertyWriter methods (serialization)
676     /***********************************************************
677      */
678 
679     /**
680      * Method called to access property that this bean stands for, from within
681      * given bean, and to serialize it as a JSON Object field using appropriate
682      * serializer.
683      */
684     @Override
serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov)685     public void serializeAsField(Object bean, JsonGenerator gen,
686             SerializerProvider prov) throws Exception {
687         // inlined 'get()'
688         final Object value = (_accessorMethod == null) ? _field.get(bean)
689                 : _accessorMethod.invoke(bean, (Object[]) null);
690 
691         // Null handling is bit different, check that first
692         if (value == null) {
693             if (_nullSerializer != null) {
694                 gen.writeFieldName(_name);
695                 _nullSerializer.serialize(null, gen, prov);
696             }
697             return;
698         }
699         // then find serializer to use
700         JsonSerializer<Object> ser = _serializer;
701         if (ser == null) {
702             Class<?> cls = value.getClass();
703             PropertySerializerMap m = _dynamicSerializers;
704             ser = m.serializerFor(cls);
705             if (ser == null) {
706                 ser = _findAndAddDynamic(m, cls, prov);
707             }
708         }
709         // and then see if we must suppress certain values (default, empty)
710         if (_suppressableValue != null) {
711             if (MARKER_FOR_EMPTY == _suppressableValue) {
712                 if (ser.isEmpty(prov, value)) {
713                     return;
714                 }
715             } else if (_suppressableValue.equals(value)) {
716                 return;
717             }
718         }
719         // For non-nulls: simple check for direct cycles
720         if (value == bean) {
721             // four choices: exception; handled by call; pass-through or write null
722             if (_handleSelfReference(bean, gen, prov, ser)) {
723                 return;
724             }
725         }
726         gen.writeFieldName(_name);
727         if (_typeSerializer == null) {
728             ser.serialize(value, gen, prov);
729         } else {
730             ser.serializeWithType(value, gen, prov, _typeSerializer);
731         }
732     }
733 
734     /**
735      * Method called to indicate that serialization of a field was omitted due
736      * to filtering, in cases where backend data format does not allow basic
737      * omission.
738      *
739      * @since 2.3
740      */
741     @Override
serializeAsOmittedField(Object bean, JsonGenerator gen, SerializerProvider prov)742     public void serializeAsOmittedField(Object bean, JsonGenerator gen,
743             SerializerProvider prov) throws Exception {
744         if (!gen.canOmitFields()) {
745             gen.writeOmittedField(_name.getValue());
746         }
747     }
748 
749     /**
750      * Alternative to {@link #serializeAsField} that is used when a POJO is
751      * serialized as JSON Array; the difference is that no field names are
752      * written.
753      *
754      * @since 2.3
755      */
756     @Override
serializeAsElement(Object bean, JsonGenerator gen, SerializerProvider prov)757     public void serializeAsElement(Object bean, JsonGenerator gen,
758             SerializerProvider prov) throws Exception {
759         // inlined 'get()'
760         final Object value = (_accessorMethod == null) ? _field.get(bean)
761                 : _accessorMethod.invoke(bean, (Object[]) null);
762         if (value == null) { // nulls need specialized handling
763             if (_nullSerializer != null) {
764                 _nullSerializer.serialize(null, gen, prov);
765             } else { // can NOT suppress entries in tabular output
766                 gen.writeNull();
767             }
768             return;
769         }
770         // otherwise find serializer to use
771         JsonSerializer<Object> ser = _serializer;
772         if (ser == null) {
773             Class<?> cls = value.getClass();
774             PropertySerializerMap map = _dynamicSerializers;
775             ser = map.serializerFor(cls);
776             if (ser == null) {
777                 ser = _findAndAddDynamic(map, cls, prov);
778             }
779         }
780         // and then see if we must suppress certain values (default, empty)
781         if (_suppressableValue != null) {
782             if (MARKER_FOR_EMPTY == _suppressableValue) {
783                 if (ser.isEmpty(prov, value)) { // can NOT suppress entries in
784                                                 // tabular output
785                     serializeAsPlaceholder(bean, gen, prov);
786                     return;
787                 }
788             } else if (_suppressableValue.equals(value)) { // can NOT suppress
789                                                            // entries in tabular
790                                                            // output
791                 serializeAsPlaceholder(bean, gen, prov);
792                 return;
793             }
794         }
795         // For non-nulls: simple check for direct cycles
796         if (value == bean) {
797             if (_handleSelfReference(bean, gen, prov, ser)) {
798                 return;
799             }
800         }
801         if (_typeSerializer == null) {
802             ser.serialize(value, gen, prov);
803         } else {
804             ser.serializeWithType(value, gen, prov, _typeSerializer);
805         }
806     }
807 
808     /**
809      * Method called to serialize a placeholder used in tabular output when real
810      * value is not to be included (is filtered out), but when we need an entry
811      * so that field indexes will not be off. Typically this should output null
812      * or empty String, depending on datatype.
813      *
814      * @since 2.1
815      */
816     @Override
serializeAsPlaceholder(Object bean, JsonGenerator gen, SerializerProvider prov)817     public void serializeAsPlaceholder(Object bean, JsonGenerator gen,
818             SerializerProvider prov) throws Exception {
819         if (_nullSerializer != null) {
820             _nullSerializer.serialize(null, gen, prov);
821         } else {
822             gen.writeNull();
823         }
824     }
825 
826     /*
827     /***********************************************************
828     /* PropertyWriter methods (schema generation)
829     /***********************************************************
830      */
831 
832     // Also part of BeanProperty implementation
833     @Override
depositSchemaProperty(JsonObjectFormatVisitor v, SerializerProvider provider)834     public void depositSchemaProperty(JsonObjectFormatVisitor v,
835             SerializerProvider provider) throws JsonMappingException {
836         if (v != null) {
837             if (isRequired()) {
838                 v.property(this);
839             } else {
840                 v.optionalProperty(this);
841             }
842         }
843     }
844 
845     // // // Legacy support for JsonFormatVisitable
846 
847     /**
848      * Attempt to add the output of the given {@link BeanPropertyWriter} in the
849      * given {@link ObjectNode}. Otherwise, add the default schema
850      * {@link JsonNode} in place of the writer's output
851      *
852      * @param propertiesNode
853      *            Node which the given property would exist within
854      * @param provider
855      *            Provider that can be used for accessing dynamic aspects of
856      *            serialization processing
857      */
858     @Override
859     @Deprecated
depositSchemaProperty(ObjectNode propertiesNode, SerializerProvider provider)860     public void depositSchemaProperty(ObjectNode propertiesNode,
861             SerializerProvider provider) throws JsonMappingException {
862         JavaType propType = getSerializationType();
863         // 03-Dec-2010, tatu: SchemaAware REALLY should use JavaType, but alas
864         // it doesn't...
865         Type hint = (propType == null) ? getType() : propType.getRawClass();
866         JsonNode schemaNode;
867         // Maybe it already has annotated/statically configured serializer?
868         JsonSerializer<Object> ser = getSerializer();
869         if (ser == null) { // nope
870             ser = provider.findValueSerializer(getType(), this);
871         }
872         boolean isOptional = !isRequired();
873         if (ser instanceof SchemaAware) {
874             schemaNode = ((SchemaAware) ser).getSchema(provider, hint,
875                     isOptional);
876         } else {
877             schemaNode = com.fasterxml.jackson.databind.jsonschema.JsonSchema
878                     .getDefaultSchemaNode();
879         }
880         _depositSchemaProperty(propertiesNode, schemaNode);
881     }
882 
883     /*
884     /**********************************************************
885     /* Helper methods
886     /**********************************************************
887      */
888 
_findAndAddDynamic( PropertySerializerMap map, Class<?> type, SerializerProvider provider)889     protected JsonSerializer<Object> _findAndAddDynamic(
890             PropertySerializerMap map, Class<?> type,
891             SerializerProvider provider) throws JsonMappingException {
892         PropertySerializerMap.SerializerAndMapResult result;
893         if (_nonTrivialBaseType != null) {
894             JavaType t = provider.constructSpecializedType(_nonTrivialBaseType,
895                     type);
896             result = map.findAndAddPrimarySerializer(t, provider, this);
897         } else {
898             result = map.findAndAddPrimarySerializer(type, provider, this);
899         }
900         // did we get a new map of serializers? If so, start using it
901         if (map != result.map) {
902             _dynamicSerializers = result.map;
903         }
904         return result.serializer;
905     }
906 
907     /**
908      * Method that can be used to access value of the property this Object
909      * describes, from given bean instance.
910      * <p>
911      * Note: method is final as it should not need to be overridden -- rather,
912      * calling method(s) ({@link #serializeAsField}) should be overridden to
913      * change the behavior
914      */
get(Object bean)915     public final Object get(Object bean) throws Exception {
916         return (_accessorMethod == null) ? _field.get(bean) : _accessorMethod
917                 .invoke(bean, (Object[]) null);
918     }
919 
920     /**
921      * Method called to handle a direct self-reference through this property.
922      * Method can choose to indicate an error by throwing
923      * {@link JsonMappingException}; fully handle serialization (and return
924      * true); or indicate that it should be serialized normally (return false).
925      * <p>
926      * Default implementation will throw {@link JsonMappingException} if
927      * {@link SerializationFeature#FAIL_ON_SELF_REFERENCES} is enabled; or
928      * return <code>false</code> if it is disabled.
929      *
930      * @return True if method fully handled self-referential value; false if not
931      *         (caller is to handle it) or {@link JsonMappingException} if there
932      *         is no way handle it
933      */
_handleSelfReference(Object bean, JsonGenerator gen, SerializerProvider prov, JsonSerializer<?> ser)934     protected boolean _handleSelfReference(Object bean, JsonGenerator gen,
935             SerializerProvider prov, JsonSerializer<?> ser)
936             throws IOException
937     {
938         if (!ser.usesObjectId()) {
939             if (prov.isEnabled(SerializationFeature.FAIL_ON_SELF_REFERENCES)) {
940                 // 05-Feb-2013, tatu: Usually a problem, but NOT if we are handling
941                 // object id; this may be the case for BeanSerializers at least.
942                 // 13-Feb-2014, tatu: another possible ok case: custom serializer
943                 // (something OTHER than {@link BeanSerializerBase}
944                 if (ser instanceof BeanSerializerBase) {
945                     prov.reportBadDefinition(getType(), "Direct self-reference leading to cycle");
946                 }
947             } else if (prov.isEnabled(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL)) {
948                 if (_nullSerializer != null) {
949                     // 23-Oct-2019, tatu: Tricky part -- caller does not specify if it's
950                     //   "as property" (in JSON Object) or "as element" (JSON array, via
951                     //   'POJO-as-array'). And since Afterburner calls method can not easily
952                     //   start passing info either. So check generator to see...
953                     //   (note: not considering ROOT context as possibility, does not seem legal)
954                     if (!gen.getOutputContext().inArray()) {
955                         gen.writeFieldName(_name);
956                     }
957                     _nullSerializer.serialize(null, gen, prov);
958                 }
959                 return true;
960             }
961         }
962         return false;
963     }
964 
965     @Override
toString()966     public String toString() {
967         StringBuilder sb = new StringBuilder(40);
968         sb.append("property '").append(getName()).append("' (");
969         if (_accessorMethod != null) {
970             sb.append("via method ")
971                     .append(_accessorMethod.getDeclaringClass().getName())
972                     .append("#").append(_accessorMethod.getName());
973         } else if (_field != null) {
974             sb.append("field \"").append(_field.getDeclaringClass().getName())
975                     .append("#").append(_field.getName());
976         } else {
977             sb.append("virtual");
978         }
979         if (_serializer == null) {
980             sb.append(", no static serializer");
981         } else {
982             sb.append(", static serializer of type "
983                     + _serializer.getClass().getName());
984         }
985         sb.append(')');
986         return sb.toString();
987     }
988 }
989