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)
}