| package com.fasterxml.jackson.databind.ser; |
| |
| import com.fasterxml.jackson.annotation.JsonInclude; |
| |
| import com.fasterxml.jackson.core.JsonGenerator; |
| |
| import com.fasterxml.jackson.databind.*; |
| import com.fasterxml.jackson.databind.cfg.MapperConfig; |
| import com.fasterxml.jackson.databind.introspect.*; |
| import com.fasterxml.jackson.databind.jsontype.TypeSerializer; |
| import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap; |
| import com.fasterxml.jackson.databind.util.Annotations; |
| |
| /** |
| * {@link BeanPropertyWriter} implementation used with |
| * {@link com.fasterxml.jackson.databind.annotation.JsonAppend} |
| * to add "virtual" properties in addition to regular ones. |
| * |
| * @since 2.5 |
| * |
| * @see com.fasterxml.jackson.databind.ser.impl.AttributePropertyWriter |
| */ |
| public abstract class VirtualBeanPropertyWriter |
| extends BeanPropertyWriter |
| implements java.io.Serializable |
| { |
| private static final long serialVersionUID = 1L; |
| |
| /** |
| * Constructor used by most sub-types. |
| */ |
| protected VirtualBeanPropertyWriter(BeanPropertyDefinition propDef, |
| Annotations contextAnnotations, JavaType declaredType) |
| { |
| this(propDef, contextAnnotations, declaredType, null, null, null, |
| propDef.findInclusion()); |
| } |
| |
| /** |
| * Constructor that may be used by sub-classes for constructing a "blue-print" instance; |
| * one that will only become (or create) actual usable instance when its |
| * {@link #withConfig} method is called. |
| */ |
| protected VirtualBeanPropertyWriter() { |
| super(); |
| } |
| |
| /** |
| * Pass-through constructor that may be used by sub-classes that |
| * want full control over implementation. |
| */ |
| protected VirtualBeanPropertyWriter(BeanPropertyDefinition propDef, |
| Annotations contextAnnotations, JavaType declaredType, |
| JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType, |
| JsonInclude.Value inclusion, Class<?>[] includeInViews) |
| { |
| super(propDef, propDef.getPrimaryMember(), contextAnnotations, declaredType, |
| ser, typeSer, serType, |
| _suppressNulls(inclusion), _suppressableValue(inclusion), |
| includeInViews); |
| } |
| |
| @Deprecated // since 2.8 |
| protected VirtualBeanPropertyWriter(BeanPropertyDefinition propDef, |
| Annotations contextAnnotations, JavaType declaredType, |
| JsonSerializer<?> ser, TypeSerializer typeSer, JavaType serType, |
| JsonInclude.Value inclusion) |
| { |
| this(propDef, contextAnnotations, declaredType, ser, typeSer, serType, inclusion, null); |
| } |
| |
| protected VirtualBeanPropertyWriter(VirtualBeanPropertyWriter base) { |
| super(base); |
| } |
| |
| protected VirtualBeanPropertyWriter(VirtualBeanPropertyWriter base, PropertyName name) { |
| super(base, name); |
| } |
| |
| protected static boolean _suppressNulls(JsonInclude.Value inclusion) { |
| if (inclusion == null) { |
| return false; |
| } |
| JsonInclude.Include incl = inclusion.getValueInclusion(); |
| return (incl != JsonInclude.Include.ALWAYS) && (incl != JsonInclude.Include.USE_DEFAULTS); |
| } |
| |
| protected static Object _suppressableValue(JsonInclude.Value inclusion) { |
| if (inclusion == null) { |
| return false; |
| } |
| JsonInclude.Include incl = inclusion.getValueInclusion(); |
| if ((incl == JsonInclude.Include.ALWAYS) |
| || (incl == JsonInclude.Include.NON_NULL) |
| || (incl == JsonInclude.Include.USE_DEFAULTS)) { |
| return null; |
| } |
| return MARKER_FOR_EMPTY; |
| } |
| |
| /* |
| /********************************************************** |
| /* Standard accessor overrides |
| /********************************************************** |
| */ |
| |
| @Override |
| public boolean isVirtual() { return true; } |
| |
| /* |
| /********************************************************** |
| /* Abstract methods for sub-classes to define |
| /********************************************************** |
| */ |
| |
| /** |
| * Method called to figure out the value to serialize. For simple sub-types |
| * (such as {@link com.fasterxml.jackson.databind.ser.impl.AttributePropertyWriter}) |
| * this may be one of few methods to define, although more advanced implementations |
| * may choose to not even use this method (by overriding {@link #serializeAsField}) |
| * and define a bogus implementation. |
| */ |
| protected abstract Object value(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception; |
| |
| /** |
| * Contextualization method called on a newly constructed virtual bean property. |
| * Usually a new intance needs to be created due to finality of some of configuration |
| * members; otherwise while recommended, creating a new instance is not strictly-speaking |
| * mandatory because calls are made in thread-safe manner, as part of initialization |
| * before use. |
| * |
| * @param config Currenct configuration; guaranteed to be {@link SerializationConfig} |
| * (just not typed since caller does not have dependency to serialization-specific types) |
| * @param declaringClass Class that contains this property writer |
| * @param propDef Nominal property definition to use |
| * @param type Declared type for the property |
| */ |
| public abstract VirtualBeanPropertyWriter withConfig(MapperConfig<?> config, |
| AnnotatedClass declaringClass, BeanPropertyDefinition propDef, JavaType type); |
| |
| /* |
| /********************************************************** |
| /* PropertyWriter serialization method overrides |
| /********************************************************** |
| */ |
| |
| @Override |
| public void serializeAsField(Object bean, JsonGenerator gen, SerializerProvider prov) throws Exception |
| { |
| // NOTE: mostly copied from base class, but off-lined get() access |
| final Object value = value(bean, gen, prov); |
| |
| if (value == null) { |
| if (_nullSerializer != null) { |
| gen.writeFieldName(_name); |
| _nullSerializer.serialize(null, gen, prov); |
| } |
| return; |
| } |
| JsonSerializer<Object> ser = _serializer; |
| if (ser == null) { |
| Class<?> cls = value.getClass(); |
| PropertySerializerMap m = _dynamicSerializers; |
| ser = m.serializerFor(cls); |
| if (ser == null) { |
| ser = _findAndAddDynamic(m, cls, prov); |
| } |
| } |
| if (_suppressableValue != null) { |
| if (MARKER_FOR_EMPTY == _suppressableValue) { |
| if (ser.isEmpty(prov, value)) { |
| return; |
| } |
| } else if (_suppressableValue.equals(value)) { |
| return; |
| } |
| } |
| if (value == bean) { // simple check for direct cycles |
| // three choices: exception; handled by call; or pass-through |
| if (_handleSelfReference(bean, gen, prov, ser)) { |
| return; |
| } |
| } |
| gen.writeFieldName(_name); |
| if (_typeSerializer == null) { |
| ser.serialize(value, gen, prov); |
| } else { |
| ser.serializeWithType(value, gen, prov, _typeSerializer); |
| } |
| } |
| |
| // This one's fine as-is from base class |
| //public void serializeAsOmittedField(Object bean, JsonGenerator jgen, SerializerProvider prov) throws Exception |
| |
| @Override |
| public void serializeAsElement(Object bean, JsonGenerator gen, SerializerProvider prov) |
| throws Exception |
| { |
| // NOTE: mostly copied from base class, but off-lined get() access |
| final Object value = value(bean, gen, prov); |
| |
| if (value == null) { |
| if (_nullSerializer != null) { |
| _nullSerializer.serialize(null, gen, prov); |
| } else { |
| gen.writeNull(); |
| } |
| return; |
| } |
| JsonSerializer<Object> ser = _serializer; |
| if (ser == null) { |
| Class<?> cls = value.getClass(); |
| PropertySerializerMap map = _dynamicSerializers; |
| ser = map.serializerFor(cls); |
| if (ser == null) { |
| ser = _findAndAddDynamic(map, cls, prov); |
| } |
| } |
| if (_suppressableValue != null) { |
| if (MARKER_FOR_EMPTY == _suppressableValue) { |
| if (ser.isEmpty(prov, value)) { |
| serializeAsPlaceholder(bean, gen, prov); |
| return; |
| } |
| } else if (_suppressableValue.equals(value)) { |
| serializeAsPlaceholder(bean, gen, prov); |
| return; |
| } |
| } |
| if (value == bean) { |
| if (_handleSelfReference(bean, gen, prov, ser)) { |
| return; |
| } |
| } |
| if (_typeSerializer == null) { |
| ser.serialize(value, gen, prov); |
| } else { |
| ser.serializeWithType(value, gen, prov, _typeSerializer); |
| } |
| } |
| |
| // This one's fine as-is from base class |
| //public void serializeAsPlaceholder(Object bean, JsonGenerator jgen, SerializerProvider prov) |
| } |