package com.fasterxml.jackson.databind.ser.std;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonMapFormatVisitor;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.ContainerSerializer;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.databind.util.ArrayBuilders;
/**
* Standard serializer implementation for serializing {link java.util.Map} types.
*
* Note: about the only configurable setting currently is ability to filter out
* entries with specified names.
*/
@JacksonStdImpl
public class MapSerializer
extends ContainerSerializer>
implements ContextualSerializer
{
private static final long serialVersionUID = 1L;
protected final static JavaType UNSPECIFIED_TYPE = TypeFactory.unknownType();
/**
* Map-valued property being serialized with this instance
*/
protected final BeanProperty _property;
/**
* Set of entries to omit during serialization, if any
*/
protected final HashSet _ignoredEntries;
/**
* Whether static types should be used for serialization of values
* or not (if not, dynamic runtime type is used)
*/
protected final boolean _valueTypeIsStatic;
/**
* Declared type of keys
*/
protected final JavaType _keyType;
/**
* Declared type of contained values
*/
protected final JavaType _valueType;
/**
* Key serializer to use, if it can be statically determined
*/
protected JsonSerializer _keySerializer;
/**
* Value serializer to use, if it can be statically determined
*/
protected JsonSerializer _valueSerializer;
/**
* Type identifier serializer used for values, if any.
*/
protected final TypeSerializer _valueTypeSerializer;
/**
* If value type can not be statically determined, mapping from
* runtime value types to serializers are stored in this object.
*/
protected PropertySerializerMap _dynamicValueSerializers;
/**
* Id of the property filter to use, if any; null if none.
*
* @since 2.3
*/
protected final Object _filterId;
/**
* Flag set if output is forced to be sorted by keys (usually due
* to annotation).
*
* @since 2.4
*/
protected final boolean _sortKeys;
/**
* Value that indicates suppression mechanism to use; either one of
* values of {@link com.fasterxml.jackson.annotation.JsonInclude.Include}, or actual object to compare
* against ("default value")
*
* @since 2.5
*/
protected final Object _suppressableValue;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
/**
* @since 2.5
*/
@SuppressWarnings("unchecked")
protected MapSerializer(HashSet ignoredEntries,
JavaType keyType, JavaType valueType, boolean valueTypeIsStatic,
TypeSerializer vts,
JsonSerializer> keySerializer, JsonSerializer> valueSerializer)
{
super(Map.class, false);
_ignoredEntries = ignoredEntries;
_keyType = keyType;
_valueType = valueType;
_valueTypeIsStatic = valueTypeIsStatic;
_valueTypeSerializer = vts;
_keySerializer = (JsonSerializer) keySerializer;
_valueSerializer = (JsonSerializer) valueSerializer;
_dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
_property = null;
_filterId = null;
_sortKeys = false;
_suppressableValue = null;
}
/**
* @since 2.5
*/
protected void _ensureOverride() {
if (getClass() != MapSerializer.class) {
throw new IllegalStateException("Missing override in class "+getClass().getName());
}
}
@SuppressWarnings("unchecked")
protected MapSerializer(MapSerializer src, BeanProperty property,
JsonSerializer> keySerializer, JsonSerializer> valueSerializer,
HashSet ignored)
{
super(Map.class, false);
_ignoredEntries = ignored;
_keyType = src._keyType;
_valueType = src._valueType;
_valueTypeIsStatic = src._valueTypeIsStatic;
_valueTypeSerializer = src._valueTypeSerializer;
_keySerializer = (JsonSerializer) keySerializer;
_valueSerializer = (JsonSerializer) valueSerializer;
_dynamicValueSerializers = src._dynamicValueSerializers;
_property = property;
_filterId = src._filterId;
_sortKeys = src._sortKeys;
_suppressableValue = src._suppressableValue;
}
@Deprecated // since 2.5
protected MapSerializer(MapSerializer src, TypeSerializer vts) {
this(src, vts, src._suppressableValue);
}
/**
* @since 2.5
*/
protected MapSerializer(MapSerializer src, TypeSerializer vts,
Object suppressableValue)
{
super(Map.class, false);
_ignoredEntries = src._ignoredEntries;
_keyType = src._keyType;
_valueType = src._valueType;
_valueTypeIsStatic = src._valueTypeIsStatic;
_valueTypeSerializer = vts;
_keySerializer = src._keySerializer;
_valueSerializer = src._valueSerializer;
_dynamicValueSerializers = src._dynamicValueSerializers;
_property = src._property;
_filterId = src._filterId;
_sortKeys = src._sortKeys;
// 05-Jun-2015, tatu: For referential, this is same as NON_EMPTY; for others, NON_NULL, so:
if (suppressableValue == JsonInclude.Include.NON_ABSENT) {
suppressableValue = _valueType.isReferenceType() ?
JsonInclude.Include.NON_EMPTY : JsonInclude.Include.NON_NULL;
}
_suppressableValue = suppressableValue;
}
protected MapSerializer(MapSerializer src, Object filterId, boolean sortKeys)
{
super(Map.class, false);
_ignoredEntries = src._ignoredEntries;
_keyType = src._keyType;
_valueType = src._valueType;
_valueTypeIsStatic = src._valueTypeIsStatic;
_valueTypeSerializer = src._valueTypeSerializer;
_keySerializer = src._keySerializer;
_valueSerializer = src._valueSerializer;
_dynamicValueSerializers = src._dynamicValueSerializers;
_property = src._property;
_filterId = filterId;
_sortKeys = sortKeys;
_suppressableValue = src._suppressableValue;
}
@Override
public MapSerializer _withValueTypeSerializer(TypeSerializer vts) {
if (_valueTypeSerializer == vts) {
return this;
}
_ensureOverride();
return new MapSerializer(this, vts, null);
}
/**
* @since 2.4
*/
public MapSerializer withResolved(BeanProperty property,
JsonSerializer> keySerializer, JsonSerializer> valueSerializer,
HashSet ignored, boolean sortKeys)
{
_ensureOverride();
MapSerializer ser = new MapSerializer(this, property, keySerializer, valueSerializer, ignored);
if (sortKeys != ser._sortKeys) {
ser = new MapSerializer(ser, _filterId, sortKeys);
}
return ser;
}
@Override
public MapSerializer withFilterId(Object filterId) {
if (_filterId == filterId) {
return this;
}
_ensureOverride();
return new MapSerializer(this, filterId, _sortKeys);
}
/**
* Mutant factory for constructing an instance with different inclusion strategy
* for content (Map values).
*
* @since 2.5
*/
public MapSerializer withContentInclusion(Object suppressableValue) {
if (suppressableValue == _suppressableValue) {
return this;
}
_ensureOverride();
return new MapSerializer(this, _valueTypeSerializer, suppressableValue);
}
/**
* @since 2.3
*/
public static MapSerializer construct(String[] ignoredList, JavaType mapType,
boolean staticValueType, TypeSerializer vts,
JsonSerializer keySerializer, JsonSerializer valueSerializer,
Object filterId)
{
HashSet ignoredEntries = (ignoredList == null || ignoredList.length == 0)
? null : ArrayBuilders.arrayToSet(ignoredList);
JavaType keyType, valueType;
if (mapType == null) {
keyType = valueType = UNSPECIFIED_TYPE;
} else {
keyType = mapType.getKeyType();
valueType = mapType.getContentType();
}
// If value type is final, it's same as forcing static value typing:
if (!staticValueType) {
staticValueType = (valueType != null && valueType.isFinal());
} else {
// also: Object.class can not be handled as static, ever
if (valueType.getRawClass() == Object.class) {
staticValueType = false;
}
}
MapSerializer ser = new MapSerializer(ignoredEntries, keyType, valueType, staticValueType, vts,
keySerializer, valueSerializer);
if (filterId != null) {
ser = ser.withFilterId(filterId);
}
return ser;
}
/*
/**********************************************************
/* Post-processing (contextualization)
/**********************************************************
*/
@Override
public JsonSerializer> createContextual(SerializerProvider provider,
BeanProperty property)
throws JsonMappingException
{
/* 29-Sep-2012, tatu: Actually, we need to do much more contextual
* checking here since we finally know for sure the property,
* and it may have overrides
*/
JsonSerializer> ser = null;
JsonSerializer> keySer = null;
final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
final AnnotatedMember propertyAcc = (property == null) ? null : property.getMember();
Object suppressableValue = _suppressableValue;
// First: if we have a property, may have property-annotation overrides
if (propertyAcc != null && intr != null) {
Object serDef = intr.findKeySerializer(propertyAcc);
if (serDef != null) {
keySer = provider.serializerInstance(propertyAcc, serDef);
}
serDef = intr.findContentSerializer(propertyAcc);
if (serDef != null) {
ser = provider.serializerInstance(propertyAcc, serDef);
}
JsonInclude.Include incl = intr.findSerializationInclusionForContent(propertyAcc, null);
if (incl != null) {
suppressableValue = incl;
}
}
if (ser == null) {
ser = _valueSerializer;
}
// [databind#124]: May have a content converter
ser = findConvertingContentSerializer(provider, property, ser);
if (ser == null) {
// 30-Sep-2012, tatu: One more thing -- if explicit content type is annotated,
// we can consider it a static case as well.
// 20-Aug-2013, tatu: Need to avoid trying to access serializer for java.lang.Object tho
if ((_valueTypeIsStatic && _valueType.getRawClass() != Object.class)
|| hasContentTypeAnnotation(provider, property)) {
ser = provider.findValueSerializer(_valueType, property);
}
} else {
ser = provider.handleSecondaryContextualization(ser, property);
}
if (keySer == null) {
keySer = _keySerializer;
}
if (keySer == null) {
keySer = provider.findKeySerializer(_keyType, property);
} else {
keySer = provider.handleSecondaryContextualization(keySer, property);
}
HashSet ignored = _ignoredEntries;
boolean sortKeys = false;
if (intr != null && propertyAcc != null) {
String[] moreToIgnore = intr.findPropertiesToIgnore(propertyAcc, true);
if (moreToIgnore != null) {
ignored = (ignored == null) ? new HashSet() : new HashSet(ignored);
for (String str : moreToIgnore) {
ignored.add(str);
}
}
Boolean b = intr.findSerializationSortAlphabetically(propertyAcc);
sortKeys = (b != null) && b.booleanValue();
}
MapSerializer mser = withResolved(property, keySer, ser, ignored, sortKeys);
if (suppressableValue != _suppressableValue) {
mser = mser.withContentInclusion(suppressableValue);
}
// [databind#307]: allow filtering
if (property != null) {
AnnotatedMember m = property.getMember();
if (m != null) {
Object filterId = intr.findFilterId(m);
if (filterId != null) {
mser = mser.withFilterId(filterId);
}
}
}
return mser;
}
/*
/**********************************************************
/* Accessors
/**********************************************************
*/
@Override
public JavaType getContentType() {
return _valueType;
}
@Override
public JsonSerializer> getContentSerializer() {
return _valueSerializer;
}
@Override
public boolean isEmpty(SerializerProvider prov, Map,?> value) {
return (value == null) || value.isEmpty();
}
@Override
public boolean hasSingleElement(Map,?> value) {
return (value.size() == 1);
}
/*
/**********************************************************
/* Extended API
/**********************************************************
*/
/**
* Accessor for currently assigned key serializer. Note that
* this may return null during construction of MapSerializer
:
* depedencies are resolved during {@link #createContextual} method
* (which can be overridden by custom implementations), but for some
* dynamic types, it is possible that serializer is only resolved
* during actual serialization.
*
* @since 2.0
*/
public JsonSerializer> getKeySerializer() {
return _keySerializer;
}
/*
/**********************************************************
/* JsonSerializer implementation
/**********************************************************
*/
@Override
public void serialize(Map,?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException
{
gen.writeStartObject();
// [databind#631]: Assign current value, to be accessible by custom serializers
gen.setCurrentValue(value);
if (!value.isEmpty()) {
Object suppressableValue = _suppressableValue;
if (suppressableValue == JsonInclude.Include.ALWAYS) {
suppressableValue = null;
} else if (suppressableValue == null) {
if (!provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES)) {
suppressableValue = JsonInclude.Include.NON_NULL;
}
}
if (_sortKeys || provider.isEnabled(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)) {
value = _orderEntries(value);
}
if (_filterId != null) {
serializeFilteredFields(value, gen, provider,
findPropertyFilter(provider, _filterId, value), suppressableValue);
} else if (suppressableValue != null) {
serializeOptionalFields(value, gen, provider, suppressableValue);
} else if (_valueSerializer != null) {
serializeFieldsUsing(value, gen, provider, _valueSerializer);
} else {
serializeFields(value, gen, provider);
}
}
gen.writeEndObject();
}
@Override
public void serializeWithType(Map,?> value, JsonGenerator gen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException
{
typeSer.writeTypePrefixForObject(value, gen);
// [databind#631]: Assign current value, to be accessible by custom serializers
gen.setCurrentValue(value);
if (!value.isEmpty()) {
Object suppressableValue = _suppressableValue;
if (suppressableValue == JsonInclude.Include.ALWAYS) {
suppressableValue = null;
} else if (suppressableValue == null) {
if (!provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES)) {
suppressableValue = JsonInclude.Include.NON_NULL;
}
}
if (_sortKeys || provider.isEnabled(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS)) {
value = _orderEntries(value);
}
if (_filterId != null) {
serializeFilteredFields(value, gen, provider,
findPropertyFilter(provider, _filterId, value), suppressableValue);
} else if (suppressableValue != null) {
serializeOptionalFields(value, gen, provider, suppressableValue);
} else if (_valueSerializer != null) {
serializeFieldsUsing(value, gen, provider, _valueSerializer);
} else {
serializeFields(value, gen, provider);
}
}
typeSer.writeTypeSuffixForObject(value, gen);
}
/*
/**********************************************************
/* JsonSerializer implementation
/**********************************************************
*/
/**
* Method called to serialize fields, when the value type is not statically known;
* but we know that no value suppression is needed (which simplifies processing a bit)
*/
public void serializeFields(Map,?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException
{
// If value type needs polymorphic type handling, some more work needed:
if (_valueTypeSerializer != null) {
serializeTypedFields(value, gen, provider, null);
return;
}
final JsonSerializer keySerializer = _keySerializer;
final HashSet ignored = _ignoredEntries;
PropertySerializerMap serializers = _dynamicValueSerializers;
for (Map.Entry,?> entry : value.entrySet()) {
Object valueElem = entry.getValue();
// First, serialize key
Object keyElem = entry.getKey();
if (keyElem == null) {
provider.findNullKeySerializer(_keyType, _property).serialize(null, gen, provider);
} else {
// One twist: is entry ignorable? If so, skip
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer.serialize(keyElem, gen, provider);
}
// And then value
if (valueElem == null) {
provider.defaultSerializeNull(gen);
} else {
Class> cc = valueElem.getClass();
JsonSerializer serializer = serializers.serializerFor(cc);
if (serializer == null) {
if (_valueType.hasGenericTypes()) {
serializer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
serializer = _findAndAddDynamic(serializers, cc, provider);
}
serializers = _dynamicValueSerializers;
}
try {
serializer.serialize(valueElem, gen, provider);
} catch (Exception e) {
// Add reference information
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}
}
/**
* Serialization method called when exclusion filtering needs to be applied.
*/
public void serializeOptionalFields(Map,?> value, JsonGenerator gen, SerializerProvider provider,
Object suppressableValue)
throws IOException
{
// If value type needs polymorphic type handling, some more work needed:
if (_valueTypeSerializer != null) {
serializeTypedFields(value, gen, provider, suppressableValue);
return;
}
final HashSet ignored = _ignoredEntries;
PropertySerializerMap serializers = _dynamicValueSerializers;
for (Map.Entry,?> entry : value.entrySet()) {
// First find key serializer
final Object keyElem = entry.getKey();
JsonSerializer keySerializer;
if (keyElem == null) {
keySerializer = provider.findNullKeySerializer(_keyType, _property);
} else {
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer = _keySerializer;
}
// Then value serializer
final Object valueElem = entry.getValue();
JsonSerializer valueSer;
if (valueElem == null) {
if (suppressableValue != null) { // all suppressions include null-suppression
continue;
}
valueSer = provider.getDefaultNullValueSerializer();
} else {
valueSer = _valueSerializer;
if (valueSer == null) {
Class> cc = valueElem.getClass();
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
if (_valueType.hasGenericTypes()) {
valueSer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
valueSer = _findAndAddDynamic(serializers, cc, provider);
}
serializers = _dynamicValueSerializers;
}
}
// also may need to skip non-empty values:
if ((suppressableValue == JsonInclude.Include.NON_EMPTY)
&& valueSer.isEmpty(provider, valueElem)) {
continue;
}
}
// and then serialize, if all went well
try {
keySerializer.serialize(keyElem, gen, provider);
valueSer.serialize(valueElem, gen, provider);
} catch (Exception e) {
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}
/**
* Method called to serialize fields, when the value type is statically known,
* so that value serializer is passed and does not need to be fetched from
* provider.
*/
protected void serializeFieldsUsing(Map,?> value, JsonGenerator gen, SerializerProvider provider,
JsonSerializer ser)
throws IOException
{
final JsonSerializer keySerializer = _keySerializer;
final HashSet ignored = _ignoredEntries;
final TypeSerializer typeSer = _valueTypeSerializer;
for (Map.Entry,?> entry : value.entrySet()) {
Object keyElem = entry.getKey();
if (ignored != null && ignored.contains(keyElem)) continue;
if (keyElem == null) {
provider.findNullKeySerializer(_keyType, _property).serialize(null, gen, provider);
} else {
keySerializer.serialize(keyElem, gen, provider);
}
final Object valueElem = entry.getValue();
if (valueElem == null) {
provider.defaultSerializeNull(gen);
} else {
try {
if (typeSer == null) {
ser.serialize(valueElem, gen, provider);
} else {
ser.serializeWithType(valueElem, gen, provider, typeSer);
}
} catch (Exception e) {
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}
}
/**
* Helper method used when we have a JSON Filter to use for potentially
* filtering out Map entries.
*
* @since 2.5
*/
public void serializeFilteredFields(Map,?> value, JsonGenerator gen, SerializerProvider provider,
PropertyFilter filter,
Object suppressableValue) // since 2.5
throws IOException
{
final HashSet ignored = _ignoredEntries;
PropertySerializerMap serializers = _dynamicValueSerializers;
final MapProperty prop = new MapProperty(_valueTypeSerializer, _property);
for (Map.Entry,?> entry : value.entrySet()) {
// First, serialize key; unless ignorable by key
final Object keyElem = entry.getKey();
if (ignored != null && ignored.contains(keyElem)) continue;
JsonSerializer keySerializer;
if (keyElem == null) {
keySerializer = provider.findNullKeySerializer(_keyType, _property);
} else {
keySerializer = _keySerializer;
}
// or by value; nulls often suppressed
final Object valueElem = entry.getValue();
JsonSerializer valueSer;
// And then value
if (valueElem == null) {
if (suppressableValue != null) { // all suppressions include null-suppression
continue;
}
valueSer = provider.getDefaultNullValueSerializer();
} else {
valueSer = _valueSerializer;
if (valueSer == null) {
Class> cc = valueElem.getClass();
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
if (_valueType.hasGenericTypes()) {
valueSer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
valueSer = _findAndAddDynamic(serializers, cc, provider);
}
serializers = _dynamicValueSerializers;
}
}
// also may need to skip non-empty values:
if ((suppressableValue == JsonInclude.Include.NON_EMPTY)
&& valueSer.isEmpty(provider, valueElem)) {
continue;
}
}
// and with that, ask filter to handle it
prop.reset(keyElem, keySerializer, valueSer);
try {
filter.serializeAsField(valueElem, gen, provider, prop);
} catch (Exception e) {
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}
@Deprecated // since 2.5
public void serializeFilteredFields(Map,?> value, JsonGenerator gen, SerializerProvider provider,
PropertyFilter filter) throws IOException {
serializeFilteredFields(value, gen, provider, filter,
provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES) ? null : JsonInclude.Include.NON_NULL);
}
/**
* @since 2.5
*/
protected void serializeTypedFields(Map,?> value, JsonGenerator gen, SerializerProvider provider,
Object suppressableValue) // since 2.5
throws IOException
{
final HashSet ignored = _ignoredEntries;
PropertySerializerMap serializers = _dynamicValueSerializers;
for (Map.Entry,?> entry : value.entrySet()) {
Object keyElem = entry.getKey();
JsonSerializer keySerializer;
if (keyElem == null) {
keySerializer = provider.findNullKeySerializer(_keyType, _property);
} else {
// One twist: is entry ignorable? If so, skip
if (ignored != null && ignored.contains(keyElem)) continue;
keySerializer = _keySerializer;
}
final Object valueElem = entry.getValue();
// And then value
JsonSerializer valueSer;
if (valueElem == null) {
if (suppressableValue != null) { // all suppression include null suppression
continue;
}
valueSer = provider.getDefaultNullValueSerializer();
} else {
valueSer = _valueSerializer;
Class> cc = valueElem.getClass();
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
if (_valueType.hasGenericTypes()) {
valueSer = _findAndAddDynamic(serializers,
provider.constructSpecializedType(_valueType, cc), provider);
} else {
valueSer = _findAndAddDynamic(serializers, cc, provider);
}
serializers = _dynamicValueSerializers;
}
// also may need to skip non-empty values:
if ((suppressableValue == JsonInclude.Include.NON_EMPTY)
&& valueSer.isEmpty(provider, valueElem)) {
continue;
}
}
keySerializer.serialize(keyElem, gen, provider);
try {
valueSer.serializeWithType(valueElem, gen, provider, _valueTypeSerializer);
} catch (Exception e) {
String keyDesc = ""+keyElem;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}
@Deprecated // since 2.5
protected void serializeTypedFields(Map,?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException {
serializeTypedFields(value, gen, provider,
provider.isEnabled(SerializationFeature.WRITE_NULL_MAP_VALUES) ? null : JsonInclude.Include.NON_NULL);
}
/*
/**********************************************************
/* Schema related functionality
/**********************************************************
*/
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("object", true);
//(ryan) even though it's possible to statically determine the "value" type of the map,
// there's no way to statically determine the keys, so the "Entries" can't be determined.
return o;
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
throws JsonMappingException
{
JsonMapFormatVisitor v2 = (visitor == null) ? null : visitor.expectMapFormat(typeHint);
if (v2 != null) {
v2.keyFormat(_keySerializer, _keyType);
JsonSerializer> valueSer = _valueSerializer;
if (valueSer == null) {
valueSer = _findAndAddDynamic(_dynamicValueSerializers,
_valueType, visitor.getProvider());
}
v2.valueFormat(valueSer, _valueType);
}
}
/*
/**********************************************************
/* Internal helper methods
/**********************************************************
*/
protected final JsonSerializer _findAndAddDynamic(PropertySerializerMap map,
Class> type, SerializerProvider provider) throws JsonMappingException
{
PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, _property);
// did we get a new map of serializers? If so, start using it
if (map != result.map) {
_dynamicValueSerializers = result.map;
}
return result.serializer;
}
protected final JsonSerializer _findAndAddDynamic(PropertySerializerMap map,
JavaType type, SerializerProvider provider) throws JsonMappingException
{
PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, _property);
if (map != result.map) {
_dynamicValueSerializers = result.map;
}
return result.serializer;
}
protected Map,?> _orderEntries(Map,?> input)
{
// minor optimization: may already be sorted?
if (input instanceof SortedMap,?>) {
return input;
}
return new TreeMap(input);
}
}