UnrolledBeanAsArraySerializer.java
package tools.jackson.databind.ser.bean;
import java.util.Set;
import tools.jackson.core.JacksonException;
import tools.jackson.core.JsonGenerator;
import tools.jackson.core.JsonToken;
import tools.jackson.core.type.WritableTypeId;
import tools.jackson.databind.*;
import tools.jackson.databind.jsontype.TypeSerializer;
import tools.jackson.databind.ser.BeanPropertyWriter;
import tools.jackson.databind.ser.impl.ObjectIdWriter;
import tools.jackson.databind.util.NameTransformer;
/**
* Specialization of {@link BeanAsArraySerializer}, optimized for handling
* small number of properties where calls to property handlers can be
* "unrolled" by eliminated looping. This can help optimize execution
* significantly for some backends.
*/
public class UnrolledBeanAsArraySerializer
extends BeanSerializerBase
{
/**
* Serializer that would produce JSON Object version; used in
* cases where array output cannot be used.
*/
protected final BeanSerializerBase _defaultSerializer;
public static final int MAX_PROPS = 6;
protected final int _propCount;
// // // We store separate references in form more easily accessed
// // // from switch statement
protected BeanPropertyWriter _prop1;
protected BeanPropertyWriter _prop2;
protected BeanPropertyWriter _prop3;
protected BeanPropertyWriter _prop4;
protected BeanPropertyWriter _prop5;
protected BeanPropertyWriter _prop6;
/*
/**********************************************************************
/* Life-cycle: constructors
/**********************************************************************
*/
public UnrolledBeanAsArraySerializer(BeanSerializerBase src) {
super(src, (ObjectIdWriter) null);
_defaultSerializer = src;
_propCount = _props.length;
_calcUnrolled();
}
protected UnrolledBeanAsArraySerializer(BeanSerializerBase src,
Set<String> toIgnore, Set<String> toInclude) {
super(src, toIgnore, toInclude);
_defaultSerializer = src;
_propCount = _props.length;
_calcUnrolled();
}
private void _calcUnrolled() {
BeanPropertyWriter[] oProps = new BeanPropertyWriter[6];
int offset = 6 - _propCount;
System.arraycopy(_props, 0, oProps, offset, _propCount);
_prop1 = oProps[0];
_prop2 = oProps[1];
_prop3 = oProps[2];
_prop4 = oProps[3];
_prop5 = oProps[4];
_prop6 = oProps[5];
}
/**
* Factory method that will construct optimized instance if all the constraints
* are obeyed; or, if not, return `null` to indicate that instance cannot be
* created.
*/
public static UnrolledBeanAsArraySerializer tryConstruct(BeanSerializerBase src)
{
if ((src.propertyCount() > MAX_PROPS)
|| (src.getFilterId() != null)
|| src.hasViewProperties()) {
return null;
}
return new UnrolledBeanAsArraySerializer(src);
}
/*
/**********************************************************************
/* Life-cycle: factory methods, fluent factories
/**********************************************************************
*/
@Override
public ValueSerializer<Object> unwrappingSerializer(NameTransformer transformer) {
// If this gets called, we will just need delegate to the default
// serializer, to "undo" as-array serialization
return _defaultSerializer.unwrappingSerializer(transformer);
}
@Override
public boolean isUnwrappingSerializer() {
return false;
}
@Override
public BeanSerializerBase withObjectIdWriter(ObjectIdWriter objectIdWriter) {
// can't handle Object Ids, for now, so:
return _defaultSerializer.withObjectIdWriter(objectIdWriter);
}
@Override
public BeanSerializerBase withFilterId(Object filterId) {
// Revert to Vanilla variant, if so:
return new BeanAsArraySerializer(_defaultSerializer,
_objectIdWriter, filterId);
}
@Override
protected UnrolledBeanAsArraySerializer withByNameInclusion(Set<String> toIgnore,
Set<String> toInclude) {
return new UnrolledBeanAsArraySerializer(this, toIgnore, toInclude);
}
@Override
protected BeanSerializerBase withProperties(BeanPropertyWriter[] properties,
BeanPropertyWriter[] filteredProperties) {
// Similar to regular as-array-serializer, let's NOT reorder properties
return this;
}
@Override
protected BeanSerializerBase asArraySerializer() {
return this; // already is one...
}
@Override
public void resolve(SerializationContext provider)
{
super.resolve(provider);
_calcUnrolled();
}
/*
/**********************************************************************
/* ValueSerializer implementation that differs between impls
/**********************************************************************
*/
// Re-defined from base class, due to differing prefixes
@Override
public void serializeWithType(Object bean, JsonGenerator gen,
SerializationContext ctxt, TypeSerializer typeSer)
throws JacksonException
{
WritableTypeId typeIdDef = _typeIdDef(typeSer, bean, JsonToken.START_ARRAY);
typeSer.writeTypePrefix(gen, ctxt, typeIdDef);
// NOTE: instances NOT constructed if view-processing available
serializeNonFiltered(bean, gen, ctxt);
typeSer.writeTypeSuffix(gen, ctxt, typeIdDef);
}
/**
* Main serialization method that will delegate actual output to
* configured
* {@link BeanPropertyWriter} instances.
*/
@Override
public final void serialize(Object bean, JsonGenerator gen, SerializationContext provider)
throws JacksonException
{
if (provider.isEnabled(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
&& hasSingleElement(provider)) {
serializeNonFiltered(bean, gen, provider);
return;
}
// note: it is assumed here that limitations (type id, object id,
// any getter, filtering) have already been checked; so code here
// is trivial.
gen.writeStartArray(bean, _props.length);
// NOTE: instances NOT constructed if view-processing available
serializeNonFiltered(bean, gen, provider);
gen.writeEndArray();
}
/*
/**********************************************************************
/* Property serialization methods
/**********************************************************************
*/
private boolean hasSingleElement(SerializationContext provider) {
return _props.length == 1;
}
protected final void serializeNonFiltered(Object bean, JsonGenerator gen,
SerializationContext provider)
throws JacksonException
{
BeanPropertyWriter prop = null;
try {
switch (_propCount) {
default:
//case 6:
prop = _prop1;
prop.serializeAsElement(bean, gen, provider);
// fall through
case 5:
prop = _prop2;
prop.serializeAsElement(bean, gen, provider);
case 4:
prop = _prop3;
prop.serializeAsElement(bean, gen, provider);
case 3:
prop = _prop4;
prop.serializeAsElement(bean, gen, provider);
case 2:
prop = _prop5;
prop.serializeAsElement(bean, gen, provider);
case 1:
prop = _prop6;
prop.serializeAsElement(bean, gen, provider);
case 0:
}
// NOTE: any getters cannot be supported either
} catch (Exception e) {
wrapAndThrow(provider, e, bean, prop.getName());
} catch (StackOverflowError e) {
throw DatabindException.from(gen, "Infinite recursion (StackOverflowError)", e)
.prependPath(bean, prop.getName());
}
}
}