StdContainerSerializer.java
package tools.jackson.databind.ser.std;
import tools.jackson.databind.*;
import tools.jackson.databind.jsontype.TypeSerializer;
import tools.jackson.databind.ser.impl.PropertySerializerMap;
/**
* Intermediate base class for serializers used for serializing
* types that contain element(s) of other types, such as arrays,
* {@link java.util.Collection}s (<code>Lists</code>, <code>Sets</code>
* etc) and {@link java.util.Map}s and iterable things
* ({@link java.util.Iterator}s).
*<p>
* NOTE: in Jackson 2.x, this class was named {@code ContainerSerializer}
* (in package {@code com.fasterxml.jackson.databind.ser}).
*/
public abstract class StdContainerSerializer<T>
extends StdSerializer<T>
{
/**
* Property that contains values handled by this serializer, if known; `null`
* for root value serializers (ones directly called by {@link ObjectMapper} and
* {@link ObjectWriter}).
*
* @since 3.0
*/
protected final BeanProperty _property;
/**
* If value type cannot be statically determined, mapping from
* runtime value types to serializers are stored in this object.
*
* @since 3.0 (in 2.x subtypes contained it)
*/
protected PropertySerializerMap _dynamicValueSerializers;
/*
/**********************************************************************
/* Construction, initialization
/**********************************************************************
*/
protected StdContainerSerializer(Class<?> t) {
this(t, null);
}
protected StdContainerSerializer(Class<?> t, BeanProperty prop) {
super(t);
_property = prop;
_dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
}
protected StdContainerSerializer(JavaType fullType, BeanProperty prop) {
super(fullType);
_property = prop;
_dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
}
protected StdContainerSerializer(StdContainerSerializer<?> src) {
this(src, src._property);
}
protected StdContainerSerializer(StdContainerSerializer<?> src, BeanProperty prop) {
super(src._handledType);
_property = prop;
// 16-Apr-2018, tatu: Could retain, possibly, in some cases... but may be
// dangerous as general practice so reset
_dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
}
/**
* Factory(-like) method that can be used to construct a new container
* serializer that uses specified {@link TypeSerializer} for decorating
* contained values with additional type information.
*
* @param vts Type serializer to use for contained values; can be null,
* in which case 'this' serializer is returned as is
* @return Serializer instance that uses given type serializer for values if
* that is possible (or if not, just 'this' serializer)
*/
public StdContainerSerializer<?> withValueTypeSerializer(TypeSerializer vts) {
if (vts == null) return this;
return _withValueTypeSerializer(vts);
}
/*
/**********************************************************************
/* Extended API
/**********************************************************************
*/
/**
* Accessor for finding declared (static) element type for
* type this serializer is used for.
*/
public abstract JavaType getContentType();
/**
* Accessor for serializer used for serializing contents
* (List and array elements, Map values etc) of the
* container for which this serializer is used, if it is
* known statically.
* Note that for dynamic types this may return null; if so,
* caller has to instead use {@link #getContentType()} and
* {@link tools.jackson.databind.SerializationContext#findContentValueSerializer}.
*/
public abstract ValueSerializer<?> getContentSerializer();
/*
/**********************************************************************
/* Abstract methods for sub-classes to implement
/**********************************************************************
*/
@Override
public abstract boolean isEmpty(SerializationContext prov, T value);
/**
* Method called to determine if the given value (of type handled by
* this serializer) contains exactly one element.
*<p>
* Note: although it might seem sensible to instead define something
* like "getElementCount()" method, this would not work well for
* containers that do not keep track of size (like linked lists may
* not).
*<p>
* Note, too, that this method is only called by serializer
* itself; and specifically is not used for non-array/collection types
* like <code>Map</code> or <code>Map.Entry</code> instances.
*/
public abstract boolean hasSingleElement(T value);
/*
/**********************************************************************
/* Helper methods for locating, caching element/value serializers
/**********************************************************************
*/
/**
* Method that needs to be implemented to allow construction of a new
* serializer object with given {@link TypeSerializer}, used when
* addition type information is to be embedded.
*/
protected abstract StdContainerSerializer<?> _withValueTypeSerializer(TypeSerializer vts);
/**
* @since 3.0
*/
protected ValueSerializer<Object> _findAndAddDynamic(SerializationContext ctxt, Class<?> type)
{
PropertySerializerMap map = _dynamicValueSerializers;
PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, ctxt, _property);
// did we get a new map of serializers? If so, start using it
if (map != result.map) {
_dynamicValueSerializers = result.map;
}
return result.serializer;
}
/**
* @since 3.0
*/
protected ValueSerializer<Object> _findAndAddDynamic(SerializationContext ctxt, JavaType type)
{
PropertySerializerMap map = _dynamicValueSerializers;
PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, ctxt, _property);
// did we get a new map of serializers? If so, start using it
if (map != result.map) {
_dynamicValueSerializers = result.map;
}
return result.serializer;
}
}