SimpleSerializers.java
package tools.jackson.databind.module;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import tools.jackson.databind.*;
import tools.jackson.databind.jsontype.TypeSerializer;
import tools.jackson.databind.ser.Serializers;
import tools.jackson.databind.type.ArrayType;
import tools.jackson.databind.type.ClassKey;
import tools.jackson.databind.type.CollectionLikeType;
import tools.jackson.databind.type.CollectionType;
import tools.jackson.databind.type.MapLikeType;
import tools.jackson.databind.type.MapType;
import tools.jackson.databind.type.ReferenceType;
/**
* Simple implementation {@link Serializers} which allows registration of
* serializers based on raw (type erased class).
* It can work well for basic bean and scalar type serializers, but is not
* a good fit for handling generic types (like {@link Map}s and {@link Collection}s).
*<p>
* Type registrations are assumed to be general; meaning that registration of serializer
* for a super type will also be used for handling subtypes, unless an exact match
* is found first. As an example, handler for {@link CharSequence} would also be used
* serializing {@link StringBuilder} instances, unless a direct mapping was found.
*/
public class SimpleSerializers
extends Serializers.Base
implements java.io.Serializable // since included by SimpleModule
{
private static final long serialVersionUID = 3L;
/**
* Class-based mappings that are used both for exact and
* sub-class matches.
*/
protected HashMap<ClassKey,ValueSerializer<?>> _classMappings = null;
/**
* Interface-based matches.
*/
protected HashMap<ClassKey,ValueSerializer<?>> _interfaceMappings = null;
/**
* Flag to help find "generic" enum serializer, if one has been registered.
*/
protected boolean _hasEnumSerializer = false;
/*
/**********************************************************
/* Life-cycle, construction and configuring
/**********************************************************
*/
public SimpleSerializers() { }
public SimpleSerializers(List<ValueSerializer<?>> sers) {
addSerializers(sers);
}
/**
* Method for adding given serializer for type that {@link ValueSerializer#handledType}
* specifies (which MUST return a non-null class; and CANNOT be {@link Object}, as a
* sanity check).
* For serializers that do not declare handled type, use the variant that takes
* two arguments.
*
* @param ser
*/
public SimpleSerializers addSerializer(ValueSerializer<?> ser)
{
// Interface to match?
Class<?> cls = ser.handledType();
if (cls == null || cls == Object.class) {
throw new IllegalArgumentException("`ValueSerializer` of type `"+ser.getClass().getName()
+"` does not define valid handledType() -- must either register with method that takes type argument "
+" or make serializer extend 'tools.jackson.databind.ser.std.StdSerializer'");
}
_addSerializer(cls, ser);
return this;
}
public <T> SimpleSerializers addSerializer(Class<? extends T> type, ValueSerializer<T> ser)
{
_addSerializer(type, ser);
return this;
}
public SimpleSerializers addSerializers(List<ValueSerializer<?>> sers) {
for (ValueSerializer<?> ser : sers) {
addSerializer(ser);
}
return this;
}
/*
/**********************************************************************
/* Serializers implementation
/**********************************************************************
*/
@Override
public ValueSerializer<?> findSerializer(SerializationConfig config,
JavaType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides)
{
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findEnumSerializer(SerializationConfig config,
JavaType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides)
{
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findTreeNodeSerializer(SerializationConfig config,
JavaType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides)
{
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findArraySerializer(SerializationConfig config,
ArrayType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides,
TypeSerializer elementTypeSerializer, ValueSerializer<Object> elementValueSerializer) {
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findCollectionSerializer(SerializationConfig config,
CollectionType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides,
TypeSerializer elementTypeSerializer, ValueSerializer<Object> elementValueSerializer) {
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findCollectionLikeSerializer(SerializationConfig config,
CollectionLikeType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides,
TypeSerializer elementTypeSerializer, ValueSerializer<Object> elementValueSerializer) {
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findMapSerializer(SerializationConfig config,
MapType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides,
ValueSerializer<Object> keySerializer,
TypeSerializer elementTypeSerializer, ValueSerializer<Object> elementValueSerializer) {
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findMapLikeSerializer(SerializationConfig config,
MapLikeType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides,
ValueSerializer<Object> keySerializer,
TypeSerializer elementTypeSerializer, ValueSerializer<Object> elementValueSerializer) {
return _findSerializer(config, type);
}
@Override
public ValueSerializer<?> findReferenceSerializer(SerializationConfig config,
ReferenceType type, BeanDescription.Supplier beanDescRef, JsonFormat.Value formatOverrides,
TypeSerializer contentTypeSerializer, ValueSerializer<Object> contentValueSerializer) {
return _findSerializer(config, type);
}
/*
/**********************************************************************
/* Internal methods
/**********************************************************************
*/
protected ValueSerializer<?> _findSerializer(SerializationConfig config, JavaType type)
{
Class<?> cls = type.getRawClass();
ClassKey key = new ClassKey(cls);
ValueSerializer<?> ser = null;
// First: direct match?
if (cls.isInterface()) {
if (_interfaceMappings != null) {
ser = _interfaceMappings.get(key);
if (ser != null) {
return ser;
}
}
} else {
if (_classMappings != null) {
ser = _classMappings.get(key);
if (ser != null) {
return ser;
}
// Handle registration of plain `Enum` serializer
if (_hasEnumSerializer && type.isEnumType()) {
key.reset(Enum.class);
ser = _classMappings.get(key);
if (ser != null) {
return ser;
}
}
// If not direct match, maybe super-class match?
for (Class<?> curr = cls; (curr != null); curr = curr.getSuperclass()) {
key.reset(curr);
ser = _classMappings.get(key);
if (ser != null) {
return ser;
}
}
}
}
// No direct match? How about super-interfaces?
if (_interfaceMappings != null) {
ser = _findInterfaceMapping(cls, key);
if (ser != null) {
return ser;
}
// still no matches? Maybe interfaces of super classes
if (!cls.isInterface()) {
while ((cls = cls.getSuperclass()) != null) {
ser = _findInterfaceMapping(cls, key);
if (ser != null) {
return ser;
}
}
}
}
return null;
}
protected ValueSerializer<?> _findInterfaceMapping(Class<?> cls, ClassKey key)
{
for (Class<?> iface : cls.getInterfaces()) {
key.reset(iface);
ValueSerializer<?> ser = _interfaceMappings.get(key);
if (ser != null) {
return ser;
}
ser = _findInterfaceMapping(iface, key);
if (ser != null) {
return ser;
}
}
return null;
}
protected void _addSerializer(Class<?> cls, ValueSerializer<?> ser)
{
ClassKey key = new ClassKey(cls);
// Interface or class type?
if (cls.isInterface()) {
if (_interfaceMappings == null) {
_interfaceMappings = new HashMap<>();
}
_interfaceMappings.put(key, ser);
} else { // nope, class:
if (_classMappings == null) {
_classMappings = new HashMap<>();
}
_classMappings.put(key, ser);
if (cls == Enum.class) {
_hasEnumSerializer = true;
}
}
}
}