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