package com.fasterxml.jackson.datatype.guava.ser;
import java.io.IOException;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.google.common.collect.BoundType;
import com.google.common.collect.Range;
/**
* Jackson serializer for a Guava {@link Range}.
*/
public class RangeSerializer extends StdSerializer<Range<?>>
implements ContextualSerializer
{
protected final JavaType _rangeType;
protected final JsonSerializer<Object> _endpointSerializer;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
public RangeSerializer(JavaType type) { this(type, null); }
@SuppressWarnings("unchecked")
public RangeSerializer(JavaType type, JsonSerializer<?> endpointSer)
{
super(type);
_rangeType = type;
_endpointSerializer = (JsonSerializer<Object>) endpointSer;
}
// TODO: can this be implemented with better semantics? Base class only
// checks for null
@Override
public boolean isEmpty(Range<?> value) {
return super.isEmpty(value);
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov,
BeanProperty property) throws JsonMappingException
{
if (_endpointSerializer == null) {
JavaType endpointType = _rangeType.containedType(0);
// let's not consider "untyped" (java.lang.Object) to be meaningful here...
if (endpointType != null && !endpointType.hasRawClass(Object.class)) {
JsonSerializer<?> ser = prov.findValueSerializer(endpointType, property);
return new RangeSerializer(_rangeType, ser);
}
/* 21-Sep-2014, tatu: Need to make sure all serializers get proper contextual
* access, in case they rely on annotations on properties... (or, more generally,
* in getting a chance to be contextualized)
*/
} else if (_endpointSerializer instanceof ContextualSerializer) {
JsonSerializer<?> cs = ((ContextualSerializer)_endpointSerializer).createContextual(prov, property);
if (cs != _endpointSerializer) {
return new RangeSerializer(_rangeType, cs);
}
}
return this;
}
/*
/**********************************************************
/* Serialization methods
/**********************************************************
*/
@Override
public void serialize(Range<?> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
jgen.writeStartObject();
_writeContents(value, jgen, provider);
jgen.writeEndObject();
}
@Override
public void serializeWithType(Range<?> value, JsonGenerator jgen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException, JsonProcessingException
{
// Will be serialized as a JSON Object, so:
typeSer.writeTypePrefixForObject(value, jgen);
_writeContents(value, jgen, provider);
typeSer.writeTypeSuffixForObject(value, jgen);
}
@Override
public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
throws JsonMappingException
{
if (visitor != null) {
JsonObjectFormatVisitor objectVisitor = visitor.expectObjectFormat(typeHint);
if (objectVisitor != null) {
if (_endpointSerializer != null) {
JavaType endpointType = _rangeType.containedType(0);
JavaType btType = visitor.getProvider().constructType(BoundType.class);
JsonSerializer<?> btSer = visitor.getProvider()
.findValueSerializer(btType, null);
objectVisitor.property("lowerEndpoint", _endpointSerializer, endpointType);
objectVisitor.property("lowerBoundType", btSer, btType);
objectVisitor.property("upperEndpoint", _endpointSerializer, endpointType);
objectVisitor.property("upperBoundType", btSer, btType);
}
}
}
}
private void _writeContents(Range<?> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException
{
if (value.hasLowerBound()) {
if (_endpointSerializer != null) {
jgen.writeFieldName("lowerEndpoint");
_endpointSerializer.serialize(value.lowerEndpoint(), jgen, provider);
} else {
provider.defaultSerializeField("lowerEndpoint", value.lowerEndpoint(), jgen);
}
provider.defaultSerializeField("lowerBoundType", value.lowerBoundType(), jgen);
}
if (value.hasUpperBound()) {
if (_endpointSerializer != null) {
jgen.writeFieldName("upperEndpoint");
_endpointSerializer.serialize(value.upperEndpoint(), jgen, provider);
} else {
provider.defaultSerializeField("upperEndpoint", value.upperEndpoint(), jgen);
}
provider.defaultSerializeField("upperBoundType", value.upperBoundType(), jgen);
}
}
}