package com.fasterxml.jackson.datatype.guava.ser;
import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonArrayFormatVisitor;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitable;
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.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.ser.std.MapProperty;
import com.fasterxml.jackson.databind.type.MapLikeType;
import com.google.common.collect.Multimap;
public class MultimapSerializer
extends ContainerSerializer<Multimap<?, ?>>
implements ContextualSerializer
{
private static final long serialVersionUID = 1L;
private final MapLikeType _type;
private final BeanProperty _property;
private final JsonSerializer<Object> _keySerializer;
private final TypeSerializer _valueTypeSerializer;
private final JsonSerializer<Object> _valueSerializer;
protected final Set<String> _ignoredEntries;
protected PropertySerializerMap _dynamicValueSerializers;
protected final Object _filterId;
protected final boolean _sortKeys;
public MultimapSerializer(MapLikeType type, BeanDescription beanDesc,
JsonSerializer<Object> keySerializer, TypeSerializer vts, JsonSerializer<Object> valueSerializer,
Set<String> ignoredEntries, Object filterId)
{
super(type.getRawClass(), false);
_type = type;
_property = null;
_keySerializer = keySerializer;
_valueTypeSerializer = vts;
_valueSerializer = valueSerializer;
_ignoredEntries = ignoredEntries;
_filterId = filterId;
_sortKeys = false;
_dynamicValueSerializers = PropertySerializerMap.emptyForProperties();
}
@SuppressWarnings("unchecked")
protected MultimapSerializer(MultimapSerializer src, BeanProperty property,
JsonSerializer<?> keySerializer, TypeSerializer vts, JsonSerializer<?> valueSerializer,
Set<String> ignoredEntries, Object filterId, boolean sortKeys)
{
super(src);
_type = src._type;
_property = property;
_keySerializer = (JsonSerializer<Object>) keySerializer;
_valueTypeSerializer = vts;
_valueSerializer = (JsonSerializer<Object>) valueSerializer;
_dynamicValueSerializers = src._dynamicValueSerializers;
_ignoredEntries = ignoredEntries;
_filterId = filterId;
_sortKeys = sortKeys;
}
protected MultimapSerializer withResolved(BeanProperty property,
JsonSerializer<?> keySer, TypeSerializer vts, JsonSerializer<?> valueSer,
Set<String> ignored, Object filterId, boolean sortKeys)
{
return new MultimapSerializer(this, property, keySer, vts, valueSer,
ignored, filterId, sortKeys);
}
@Override
protected ContainerSerializer<?> _withValueTypeSerializer(TypeSerializer typeSer) {
return new MultimapSerializer(this, _property, _keySerializer,
typeSer, _valueSerializer, _ignoredEntries, _filterId, _sortKeys);
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider provider,
BeanProperty property) throws JsonMappingException
{
JsonSerializer<?> valueSer = _valueSerializer;
if (valueSer == null) {
JavaType valueType = _type.getContentType();
if (valueType.isFinal()) {
valueSer = provider.findValueSerializer(valueType, property);
}
} else if (valueSer instanceof ContextualSerializer) {
valueSer = ((ContextualSerializer) valueSer).createContextual(provider, property);
}
final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
final AnnotatedMember propertyAcc = (property == null) ? null : property.getMember();
JsonSerializer<?> keySer = null;
Object filterId = _filterId;
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) {
valueSer = provider.serializerInstance(propertyAcc, serDef);
}
filterId = intr.findFilterId(propertyAcc);
}
if (valueSer == null) {
valueSer = _valueSerializer;
}
valueSer = findContextualConvertingSerializer(provider, property, valueSer);
if (valueSer == null) {
JavaType valueType = _type.getContentType();
if (valueType.useStaticType()) {
valueSer = provider.findValueSerializer(valueType, property);
}
} else {
valueSer = provider.handleSecondaryContextualization(valueSer, property);
}
if (keySer == null) {
keySer = _keySerializer;
}
if (keySer == null) {
keySer = provider.findKeySerializer(_type.getKeyType(), property);
} else {
keySer = provider.handleSecondaryContextualization(keySer, property);
}
TypeSerializer typeSer = _valueTypeSerializer;
if (typeSer != null) {
typeSer = typeSer.forProperty(property);
}
Set<String> ignored = _ignoredEntries;
boolean sortKeys = false;
if (intr != null && propertyAcc != null) {
JsonIgnoreProperties.Value ignorals = intr.findPropertyIgnoralByName(provider.getConfig(), propertyAcc);
if (ignorals != null) {
Set<String> newIgnored = ignorals.findIgnoredForSerialization();
if ((newIgnored != null) && !newIgnored.isEmpty()) {
ignored = (ignored == null) ? new HashSet<String>() : new HashSet<>(ignored);
for (String str : newIgnored) {
ignored.add(str);
}
}
}
Boolean b = intr.findSerializationSortAlphabetically(propertyAcc);
sortKeys = (b != null) && b.booleanValue();
}
JsonFormat.Value format = findFormatOverrides(provider, property, handledType());
if (format != null) {
Boolean B = format.getFeature(JsonFormat.Feature.WRITE_SORTED_MAP_ENTRIES);
if (B != null) {
sortKeys = B.booleanValue();
}
}
return withResolved(property, keySer, typeSer, valueSer,
ignored, filterId, sortKeys);
}
@Override
public JsonSerializer<?> getContentSerializer() {
return _valueSerializer;
}
@Override
public JavaType getContentType() {
return _type.getContentType();
}
@Override
public boolean hasSingleElement(Multimap<?,?> map) {
return map.size() == 1;
}
@Override
public boolean isEmpty(SerializerProvider prov, Multimap<?,?> value) {
return value.isEmpty();
}
@Override
public void serialize(Multimap<?, ?> value, JsonGenerator gen, SerializerProvider provider)
throws IOException
{
gen.writeStartObject();
gen.setCurrentValue(value);
if (!value.isEmpty()) {
if (_filterId != null) {
serializeFilteredFields(value, gen, provider);
} else {
serializeFields(value, gen, provider);
}
}
gen.writeEndObject();
}
@Override
public void serializeWithType(Multimap<?,?> value, JsonGenerator gen,
SerializerProvider provider, TypeSerializer typeSer)
throws IOException
{
gen.setCurrentValue(value);
WritableTypeId typeIdDef = typeSer.writeTypePrefix(gen,
typeSer.typeId(value, JsonToken.START_OBJECT));
if (!value.isEmpty()) {
if (_filterId != null) {
serializeFilteredFields(value, gen, provider);
} else {
serializeFields(value, gen, provider);
}
}
typeSer.writeTypeSuffix(gen, typeIdDef);
}
private final void serializeFields(Multimap<?, ?> mmap, JsonGenerator
gen, SerializerProvider provider)
throws IOException
{
final Set<String> ignored = _ignoredEntries;
PropertySerializerMap serializers = _dynamicValueSerializers;
for (Entry<?, ? extends Collection<?>> entry : mmap.asMap().entrySet()) {
Object key = entry.getKey();
if ((ignored != null) && ignored.contains(key)) {
continue;
}
if (key == null) {
provider.findNullKeySerializer(_type.getKeyType(), _property)
.serialize(null, gen, provider);
} else {
_keySerializer.serialize(key, gen, provider);
}
gen.writeStartArray();
for (Object vv : entry.getValue()) {
if (vv == null) {
provider.defaultSerializeNull(gen);
continue;
}
JsonSerializer<Object> valueSer = _valueSerializer;
if (valueSer == null) {
Class<?> cc = vv.getClass();
valueSer = serializers.serializerFor(cc);
if (valueSer == null) {
valueSer = _findAndAddDynamic(serializers, cc, provider);
serializers = _dynamicValueSerializers;
}
}
if (_valueTypeSerializer == null) {
valueSer.serialize(vv, gen, provider);
} else {
valueSer.serializeWithType(vv, gen, provider, _valueTypeSerializer);
}
}
gen.writeEndArray();
}
}
private final void serializeFilteredFields(Multimap<?, ?> mmap, JsonGenerator gen, SerializerProvider provider)
throws IOException
{
final Set<String> ignored = _ignoredEntries;
PropertyFilter filter = findPropertyFilter(provider, _filterId, mmap);
final MapProperty prop = new MapProperty(_valueTypeSerializer, _property);
for (Entry<?, ? extends Collection<?>> entry : mmap.asMap().entrySet()) {
Object key = entry.getKey();
if ((ignored != null) && ignored.contains(key)) {
continue;
}
Collection<?> value = entry.getValue();
JsonSerializer<Object> valueSer;
if (value == null) {
valueSer = provider.getDefaultNullValueSerializer();
} else {
valueSer = _valueSerializer;
}
prop.reset(key, value, _keySerializer, valueSer);
try {
filter.serializeAsField(mmap, gen, provider, prop);
} catch (Exception e) {
String keyDesc = ""+key;
wrapAndThrow(provider, e, value, keyDesc);
}
}
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
throws JsonMappingException
{
JsonMapFormatVisitor v2 = (visitor == null) ? null : visitor.expectMapFormat(typeHint);
if (v2 != null) {
v2.keyFormat(_keySerializer, _type.getKeyType());
JsonSerializer<?> valueSer = _valueSerializer;
final JavaType vt = _type.getContentType();
final SerializerProvider prov = visitor.getProvider();
if (valueSer == null) {
valueSer = _findAndAddDynamic(_dynamicValueSerializers, vt, prov);
}
final JsonSerializer<?> valueSer2 = valueSer;
v2.valueFormat(new JsonFormatVisitable() {
final JavaType arrayType = prov.getTypeFactory().constructArrayType(vt);
@Override
public void acceptJsonFormatVisitor(
JsonFormatVisitorWrapper v3, JavaType hint3)
throws JsonMappingException
{
JsonArrayFormatVisitor v4 = v3.expectArrayFormat(arrayType);
if (v4 != null) {
v4.itemsFormat(valueSer2, vt);
}
}
}, vt);
}
}
protected final JsonSerializer<Object> _findAndAddDynamic(PropertySerializerMap map,
Class<?> type, SerializerProvider provider) throws JsonMappingException
{
PropertySerializerMap.SerializerAndMapResult result = map.findAndAddSecondarySerializer(type, provider, _property);
if (map != result.map) {
_dynamicValueSerializers = result.map;
}
return result.serializer;
}
protected final JsonSerializer<Object> _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;
}
}