Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
io.honeybadger.com.fasterxml.jackson.databind.ser.impl.PropertySerializerMap Maven / Gradle / Ivy
package com.fasterxml.jackson.databind.ser.impl;
import java.util.Arrays;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* Helper container used for resolving serializers for dynamic (possibly but not
* necessarily polymorphic) properties: properties whose type is not forced
* to use dynamic (declared) type and that are not final.
* If so, serializer to use can only be established once actual value type is known.
* Since this happens a lot unless static typing is forced (or types are final)
* this implementation is optimized for efficiency.
* Instances are immutable; new instances are created with factory methods: this
* is important to ensure correct multi-threaded access.
*/
public abstract class PropertySerializerMap
{
/**
* Configuration setting that determines what happens when maximum
* size (currently 8) is reached: if true, will "start from beginning";
* if false, will simply stop adding new entries.
*
* @since 2.5
*/
protected final boolean _resetWhenFull;
/**
* @since 2.5
*/
protected PropertySerializerMap(boolean resetWhenFull) {
_resetWhenFull = resetWhenFull;
}
protected PropertySerializerMap(PropertySerializerMap base) {
_resetWhenFull = base._resetWhenFull;
}
/**
* Main lookup method. Takes a "raw" type since usage is always from
* place where parameterization is fixed such that there cannot be
* type-parametric variations.
*/
public abstract JsonSerializer serializerFor(Class type);
/**
* Method called if initial lookup fails, when looking for a primary
* serializer (one that is directly attached to a property).
* Will both find serializer
* and construct new map instance if warranted, and return both.
*
* @since 2.3
*
* @throws JsonMappingException
*/
public final SerializerAndMapResult findAndAddPrimarySerializer(Class type,
SerializerProvider provider, BeanProperty property)
throws JsonMappingException
{
JsonSerializer serializer = provider.findPrimaryPropertySerializer(type, property);
return new SerializerAndMapResult(serializer, newWith(type, serializer));
}
public final SerializerAndMapResult findAndAddPrimarySerializer(JavaType type,
SerializerProvider provider, BeanProperty property)
throws JsonMappingException
{
JsonSerializer serializer = provider.findPrimaryPropertySerializer(type, property);
return new SerializerAndMapResult(serializer, newWith(type.getRawClass(), serializer));
}
/**
* Method called if initial lookup fails, when looking for a non-primary
* serializer (one that is not directly attached to a property).
* Will both find serializer
* and construct new map instance if warranted, and return both.
*
* @since 2.3
*
* @throws JsonMappingException
*/
public final SerializerAndMapResult findAndAddSecondarySerializer(Class type,
SerializerProvider provider, BeanProperty property)
throws JsonMappingException
{
JsonSerializer serializer = provider.findContentValueSerializer(type, property);
return new SerializerAndMapResult(serializer, newWith(type, serializer));
}
public final SerializerAndMapResult findAndAddSecondarySerializer(JavaType type,
SerializerProvider provider, BeanProperty property)
throws JsonMappingException
{
JsonSerializer serializer = provider.findContentValueSerializer(type, property);
return new SerializerAndMapResult(serializer, newWith(type.getRawClass(), serializer));
}
/**
* Method called if initial lookup fails, when looking for a root value
* serializer: one that is not directly attached to a property, but needs to
* have {@link com.fasterxml.jackson.databind.jsontype.TypeSerializer} wrapped
* around it. Will both find the serializer
* and construct new map instance if warranted, and return both.
*
* @since 2.5
*
* @throws JsonMappingException
*/
public final SerializerAndMapResult findAndAddRootValueSerializer(Class type,
SerializerProvider provider)
throws JsonMappingException
{
JsonSerializer serializer = provider.findTypedValueSerializer(type, false, null);
return new SerializerAndMapResult(serializer, newWith(type, serializer));
}
/**
* @since 2.5
*/
public final SerializerAndMapResult findAndAddRootValueSerializer(JavaType type,
SerializerProvider provider)
throws JsonMappingException
{
JsonSerializer serializer = provider.findTypedValueSerializer(type, false, null);
return new SerializerAndMapResult(serializer, newWith(type.getRawClass(), serializer));
}
/**
* Method called if initial lookup fails, when looking for a key
* serializer (possible attached indirectly to a property)
* Will both find serializer
* and construct new map instance if warranted, and return both.
*
* @since 2.7
*/
public final SerializerAndMapResult findAndAddKeySerializer(Class type,
SerializerProvider provider, BeanProperty property)
throws JsonMappingException
{
JsonSerializer serializer = provider.findKeySerializer(type, property);
return new SerializerAndMapResult(serializer, newWith(type, serializer));
}
/**
* Method that can be used to 'register' a serializer that caller has resolved
* without help of this map.
*
* @since 2.5
*/
public final SerializerAndMapResult addSerializer(Class type, JsonSerializer serializer) {
return new SerializerAndMapResult(serializer, newWith(type, serializer));
}
/**
* @since 2.5
*/
public final SerializerAndMapResult addSerializer(JavaType type, JsonSerializer serializer) {
return new SerializerAndMapResult(serializer, newWith(type.getRawClass(), serializer));
}
public abstract PropertySerializerMap newWith(Class type, JsonSerializer serializer);
/**
* @since 2.5
*/
public static PropertySerializerMap emptyForProperties() {
return Empty.FOR_PROPERTIES;
}
/**
* @since 2.5
*/
public static PropertySerializerMap emptyForRootValues() {
return Empty.FOR_ROOT_VALUES;
}
/*
/**********************************************************
/* Helper classes
/**********************************************************
*/
/**
* Value class used for returning tuple that has both serializer
* that was retrieved and new map instance
*/
public final static class SerializerAndMapResult
{
public final JsonSerializer serializer;
public final PropertySerializerMap map;
public SerializerAndMapResult(JsonSerializer serializer,
PropertySerializerMap map)
{
this.serializer = serializer;
this.map = map;
}
}
/**
* Trivial container for bundling type + serializer entries.
*/
private final static class TypeAndSerializer
{
public final Class type;
public final JsonSerializer serializer;
public TypeAndSerializer(Class type, JsonSerializer serializer) {
this.type = type;
this.serializer = serializer;
}
}
/*
/**********************************************************
/* Implementations
/**********************************************************
*/
/**
* Bogus instance that contains no serializers; used as the default
* map with new serializers.
*/
private final static class Empty extends PropertySerializerMap
{
// No root serializers; do not reset when full
public final static Empty FOR_PROPERTIES = new Empty(false);
// Yes, root serializers; do reset when full
public final static Empty FOR_ROOT_VALUES = new Empty(true);
protected Empty(boolean resetWhenFull) {
super(resetWhenFull);
}
@Override
public JsonSerializer serializerFor(Class type) {
return null; // empty, nothing to find
}
@Override
public PropertySerializerMap newWith(Class type, JsonSerializer serializer) {
return new Single(this, type, serializer);
}
}
/**
* Map that contains a single serializer; although seemingly silly
* this is probably the most commonly used variant because many
* theoretically dynamic or polymorphic types just have single
* actual type.
*/
private final static class Single extends PropertySerializerMap
{
private final Class _type;
private final JsonSerializer _serializer;
public Single(PropertySerializerMap base, Class type, JsonSerializer serializer) {
super(base);
_type = type;
_serializer = serializer;
}
@Override
public JsonSerializer serializerFor(Class type)
{
if (type == _type) {
return _serializer;
}
return null;
}
@Override
public PropertySerializerMap newWith(Class type, JsonSerializer serializer) {
return new Double(this, _type, _serializer, type, serializer);
}
}
private final static class Double extends PropertySerializerMap
{
private final Class _type1, _type2;
private final JsonSerializer _serializer1, _serializer2;
public Double(PropertySerializerMap base,
Class type1, JsonSerializer serializer1,
Class type2, JsonSerializer serializer2)
{
super(base);
_type1 = type1;
_serializer1 = serializer1;
_type2 = type2;
_serializer2 = serializer2;
}
@Override
public JsonSerializer serializerFor(Class type)
{
if (type == _type1) {
return _serializer1;
}
if (type == _type2) {
return _serializer2;
}
return null;
}
@Override
public PropertySerializerMap newWith(Class type, JsonSerializer serializer) {
// Ok: let's just create generic one
TypeAndSerializer[] ts = new TypeAndSerializer[3];
ts[0] = new TypeAndSerializer(_type1, _serializer1);
ts[1] = new TypeAndSerializer(_type2, _serializer2);
ts[2] = new TypeAndSerializer(type, serializer);
return new Multi(this, ts);
}
}
private final static class Multi extends PropertySerializerMap
{
/**
* Let's limit number of serializers we actually cache; linear
* lookup won't scale too well beyond smallish number, and if
* we really want to support larger collections should use
* a hash map. But it seems unlikely this is a common use
* case so for now let's just stop building after hard-coded
* limit. 8 sounds like a reasonable stab for now.
*/
private final static int MAX_ENTRIES = 8;
private final TypeAndSerializer[] _entries;
public Multi(PropertySerializerMap base, TypeAndSerializer[] entries) {
super(base);
_entries = entries;
}
@Override
public JsonSerializer serializerFor(Class type)
{
// Always have first 3 populated so
TypeAndSerializer entry;
entry = _entries[0];
if (entry.type == type) return entry.serializer;
entry = _entries[1];
if (entry.type == type) return entry.serializer;
entry = _entries[2];
if (entry.type == type) return entry.serializer;
switch (_entries.length) {
case 8:
entry = _entries[7];
if (entry.type == type) return entry.serializer;
case 7:
entry = _entries[6];
if (entry.type == type) return entry.serializer;
case 6:
entry = _entries[5];
if (entry.type == type) return entry.serializer;
case 5:
entry = _entries[4];
if (entry.type == type) return entry.serializer;
case 4:
entry = _entries[3];
if (entry.type == type) return entry.serializer;
default:
}
return null;
}
@Override
public PropertySerializerMap newWith(Class type, JsonSerializer serializer)
{
int len = _entries.length;
// Will only grow up to N entries. We could consider couple of alternatives after
// this if we wanted to... but for now, two main choices make most sense
if (len == MAX_ENTRIES) {
if (_resetWhenFull) {
return new Single(this, type, serializer);
}
return this;
}
TypeAndSerializer[] entries = Arrays.copyOf(_entries, len+1);
entries[len] = new TypeAndSerializer(type, serializer);
return new Multi(this, entries);
}
}
}