• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.fasterxml.jackson.databind.ser;
2 
3 import com.fasterxml.jackson.annotation.JsonInclude;
4 
5 import com.fasterxml.jackson.core.JsonGenerator;
6 
7 import com.fasterxml.jackson.databind.*;
8 import com.fasterxml.jackson.databind.cfg.MapperConfig;
9 import com.fasterxml.jackson.databind.introspect.*;
10 import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
11 import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
12 import com.fasterxml.jackson.databind.util.Annotations;
13 
14 /**
15  * {@link BeanPropertyWriter} implementation used with
16  * {@link com.fasterxml.jackson.databind.annotation.JsonAppend}
17  * to add "virtual" properties in addition to regular ones.
18  *
19  * @since 2.5
20  *
21  * @see com.fasterxml.jackson.databind.ser.impl.AttributePropertyWriter
22  */
23 public abstract class VirtualBeanPropertyWriter
24     extends BeanPropertyWriter
25     implements java.io.Serializable
26 {
27     private static final long serialVersionUID = 1L;
28 
29     /**
30      * Constructor used by most sub-types.
31      */
VirtualBeanPropertyWriter(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType)32     protected VirtualBeanPropertyWriter(BeanPropertyDefinition propDef,
33             Annotations contextAnnotations, JavaType declaredType)
34     {
35         this(propDef, contextAnnotations, declaredType, null, null, null,
36                 propDef.findInclusion());
37     }
38 
39     /**
40      * Constructor that may be used by sub-classes for constructing a "blue-print" instance;
41      * one that will only become (or create) actual usable instance when its
42      * {@link #withConfig} method is called.
43      */
VirtualBeanPropertyWriter()44     protected VirtualBeanPropertyWriter() {
45         super();
46     }
47 
48     /**
49      * Pass-through constructor that may be used by sub-classes that
50      * want full control over implementation.
51      */
VirtualBeanPropertyWriter(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType, JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType, JsonInclude.Value inclusion, Class<?>[] includeInViews)52     protected VirtualBeanPropertyWriter(BeanPropertyDefinition propDef,
53             Annotations contextAnnotations, JavaType declaredType,
54             JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType,
55             JsonInclude.Value inclusion, Class<?>[] includeInViews)
56     {
57         super(propDef, propDef.getPrimaryMember(), contextAnnotations, declaredType,
58                 ser, typeSer, serType,
59                 _suppressNulls(inclusion), _suppressableValue(inclusion),
60                 includeInViews);
61     }
62 
63     @Deprecated // since 2.8
VirtualBeanPropertyWriter(BeanPropertyDefinition propDef, Annotations contextAnnotations, JavaType declaredType, JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType, JsonInclude.Value inclusion)64     protected VirtualBeanPropertyWriter(BeanPropertyDefinition propDef,
65             Annotations contextAnnotations, JavaType declaredType,
66             JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType,
67             JsonInclude.Value inclusion)
68     {
69         this(propDef, contextAnnotations, declaredType, ser, typeSer, serType, inclusion, null);
70     }
71 
VirtualBeanPropertyWriter(VirtualBeanPropertyWriter base)72     protected VirtualBeanPropertyWriter(VirtualBeanPropertyWriter base) {
73         super(base);
74     }
75 
VirtualBeanPropertyWriter(VirtualBeanPropertyWriter base, PropertyName name)76     protected VirtualBeanPropertyWriter(VirtualBeanPropertyWriter base, PropertyName name) {
77         super(base, name);
78     }
79 
_suppressNulls(JsonInclude.Value inclusion)80     protected static boolean _suppressNulls(JsonInclude.Value inclusion) {
81         if (inclusion == null) {
82             return false;
83         }
84         JsonInclude.Include incl = inclusion.getValueInclusion();
85         return (incl != JsonInclude.Include.ALWAYS) && (incl != JsonInclude.Include.USE_DEFAULTS);
86     }
87 
_suppressableValue(JsonInclude.Value inclusion)88     protected static Object _suppressableValue(JsonInclude.Value inclusion) {
89         if (inclusion == null) {
90             return false;
91         }
92         JsonInclude.Include incl = inclusion.getValueInclusion();
93         if ((incl == JsonInclude.Include.ALWAYS)
94                 || (incl == JsonInclude.Include.NON_NULL)
95                 || (incl == JsonInclude.Include.USE_DEFAULTS)) {
96             return null;
97         }
98         return MARKER_FOR_EMPTY;
99     }
100 
101     /*
102     /**********************************************************
103     /* Standard accessor overrides
104     /**********************************************************
105      */
106 
107     @Override
isVirtual()108     public boolean isVirtual() { return true; }
109 
110     /*
111     /**********************************************************
112     /* Abstract methods for sub-classes to define
113     /**********************************************************
114      */
115 
116     /**
117      * Method called to figure out the value to serialize. For simple sub-types
118      * (such as {@link com.fasterxml.jackson.databind.ser.impl.AttributePropertyWriter})
119      * this may be one of few methods to define, although more advanced implementations
120      * may choose to not even use this method (by overriding {@link #serializeAsField})
121      * and define a bogus implementation.
122      */
value(Object bean, JsonGenerator gen, SerializerProvider prov)123     protected abstract Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception;
124 
125     /**
126      * Contextualization method called on a newly constructed virtual bean property.
127      * Usually a new intance needs to be created due to finality of some of configuration
128      * members; otherwise while recommended, creating a new instance is not strictly-speaking
129      * mandatory because calls are made in thread-safe manner, as part of initialization
130      * before use.
131      *
132      * @param config Currenct configuration; guaranteed to be {@link SerializationConfig}
133      *   (just not typed since caller does not have dependency to serialization-specific types)
134      * @param declaringClass Class that contains this property writer
135      * @param propDef Nominal property definition to use
136      * @param type Declared type for the property
137      */
withConfig(MapperConfig<?> config, AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type)138     public abstract VirtualBeanPropertyWriter withConfig(MapperConfig<?> config,
139             AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type);
140 
141     /*
142     /**********************************************************
143     /* PropertyWriter serialization method overrides
144     /**********************************************************
145      */
146 
147     @Override
serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov)148     public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception
149     {
150         // NOTE: mostly copied from base class, but off-lined get() access
151         final Object value = value(bean, gen, prov);
152 
153         if (value == null) {
154             if (_nullSerializer != null) {
155                 gen.writeFieldName(_name);
156                 _nullSerializer.serialize(null, gen, prov);
157             }
158             return;
159         }
160         JsonSerializer<Object> ser = _serializer;
161         if (ser == null) {
162             Class<?> cls = value.getClass();
163             PropertySerializerMap m = _dynamicSerializers;
164             ser = m.serializerFor(cls);
165             if (ser == null) {
166                 ser = _findAndAddDynamic(m, cls, prov);
167             }
168         }
169         if (_suppressableValue != null) {
170             if (MARKER_FOR_EMPTY == _suppressableValue) {
171                 if (ser.isEmpty(prov, value)) {
172                     return;
173                 }
174             } else if (_suppressableValue.equals(value)) {
175                 return;
176             }
177         }
178         if (value == bean) { // simple check for direct cycles
179             // four choices: exception; handled by call; or pass-through; write null
180             if (_handleSelfReference(bean, gen, prov, ser)) {
181                 return;
182             }
183         }
184         gen.writeFieldName(_name);
185         if (_typeSerializer == null) {
186             ser.serialize(value, gen, prov);
187         } else {
188             ser.serializeWithType(value, gen, prov, _typeSerializer);
189         }
190     }
191 
192     // This one's fine as-is from base class
193     //public void serializeAsOmittedField(Object bean, JsonGenerator jgen, SerializerProvider prov) throws Exception
194 
195     @Override
serializeAsElement(Object bean, JsonGenerator gen, SerializerProvider prov)196     public void serializeAsElement(Object bean, JsonGenerator gen, SerializerProvider prov)
197         throws Exception
198     {
199         // NOTE: mostly copied from base class, but off-lined get() access
200         final Object value = value(bean, gen, prov);
201 
202         if (value == null) {
203             if (_nullSerializer != null) {
204                 _nullSerializer.serialize(null, gen, prov);
205             } else {
206                 gen.writeNull();
207             }
208             return;
209         }
210         JsonSerializer<Object> ser = _serializer;
211         if (ser == null) {
212             Class<?> cls = value.getClass();
213             PropertySerializerMap map = _dynamicSerializers;
214             ser = map.serializerFor(cls);
215             if (ser == null) {
216                 ser = _findAndAddDynamic(map, cls, prov);
217             }
218         }
219         if (_suppressableValue != null) {
220             if (MARKER_FOR_EMPTY == _suppressableValue) {
221                 if (ser.isEmpty(prov, value)) {
222                     serializeAsPlaceholder(bean, gen, prov);
223                     return;
224                 }
225             } else if (_suppressableValue.equals(value)) {
226                 serializeAsPlaceholder(bean, gen, prov);
227                 return;
228             }
229         }
230         if (value == bean) {
231             if (_handleSelfReference(bean, gen, prov, ser)) {
232                 return;
233             }
234         }
235         if (_typeSerializer == null) {
236             ser.serialize(value, gen, prov);
237         } else {
238             ser.serializeWithType(value, gen, prov, _typeSerializer);
239         }
240     }
241 
242     // This one's fine as-is from base class
243     //public void serializeAsPlaceholder(Object bean, JsonGenerator jgen, SerializerProvider prov)
244 }
245