package com.fasterxml.jackson.databind.ser; import com.fasterxml.jackson.databind.AnnotationIntrospector; import com.fasterxml.jackson.databind.BeanProperty; import com.fasterxml.jackson.databind.JavaType; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; import com.fasterxml.jackson.databind.ser.std.StdSerializer; /** * 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). */ public abstract class ContainerSerializer<T> extends StdSerializer<T> { /* /********************************************************** /* Construction, initialization /********************************************************** */ protected ContainerSerializer(Class<T> t) { super(t); } /** * Alternate constructor that is (alas!) needed to work * around kinks of generic type handling * * @param t */ protected ContainerSerializer(Class<?> t, boolean dummy) { super(t, dummy); } protected ContainerSerializer(ContainerSerializer<?> src) { super(src._handledType, false); } /** * 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 ContainerSerializer<?> 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 com.fasterxml.jackson.databind.SerializerProvider#findValueSerializer}. */ public abstract JsonSerializer<?> getContentSerializer(); /* /********************************************************** /* Abstract methods for sub-classes to implement /********************************************************** */ /* Overridden as abstract, to force re-implementation; necessary for all * collection types. */ @Override public abstract boolean isEmpty(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). */ public abstract boolean hasSingleElement(T value); /** * 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 ContainerSerializer<?> _withValueTypeSerializer(TypeSerializer vts); /* /********************************************************** /* Helper methods for sub-types /********************************************************** */ /** * Helper method used to encapsulate logic for determining whether there is * a property annotation that overrides element type; if so, we can * and need to statically find the serializer. * * @since 2.1 */ protected boolean hasContentTypeAnnotation(SerializerProvider provider, BeanProperty property) { if (property != null) { AnnotationIntrospector intr = provider.getAnnotationIntrospector(); if (intr != null) { if (intr.findSerializationContentType(property.getMember(), property.getType()) != null) { return true; } } } return false; } }