blob: 52549e10874467121f73392c210a65d266bea5d4 [file] [log] [blame]
package org.codehaus.jackson.map.ser.std;
import java.io.IOException;
import java.lang.reflect.Type;
import org.codehaus.jackson.*;
import org.codehaus.jackson.node.ObjectNode;
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.annotate.JacksonStdImpl;
/**
* Dummy container class to group standard homogenous array serializer implementations
* (primitive arrays and String array).
*/
public class StdArraySerializers
{
protected StdArraySerializers() { }
/*
/**********************************************************
/* Base classes
/**********************************************************
*/
/**
* Base class for serializers that will output contents as JSON
* arrays.
*/
public abstract static class ArraySerializerBase<T>
extends ContainerSerializerBase<T>
{
/**
* Type serializer used for values, if any.
*/
protected final TypeSerializer _valueTypeSerializer;
/**
* Array-valued property being serialized with this instance
*
* @since 1.7
*/
protected final BeanProperty _property;
protected ArraySerializerBase(Class<T> cls, TypeSerializer vts, BeanProperty property)
{
super(cls);
_valueTypeSerializer = vts;
_property = property;
}
@Override
public final void serialize(T value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
jgen.writeStartArray();
serializeContents(value, jgen, provider);
jgen.writeEndArray();
}
@Override
public final void serializeWithType(T value, JsonGenerator jgen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException, JsonGenerationException
{
typeSer.writeTypePrefixForArray(value, jgen);
serializeContents(value, jgen, provider);
typeSer.writeTypeSuffixForArray(value, jgen);
}
protected abstract void serializeContents(T value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException;
}
/*
****************************************************************
/* Concrete serializers, arrays
****************************************************************
*/
/**
* Standard serializer used for <code>String[]</code> values.
*/
@JacksonStdImpl
public final static class StringArraySerializer
extends ArraySerializerBase<String[]>
implements ResolvableSerializer
{
/**
* Value serializer to use, if it's not the standard one
* (if it is we can optimize serialization a lot)
*
* @since 1.7
*/
protected JsonSerializer<Object> _elementSerializer;
public StringArraySerializer(BeanProperty prop) {
super(String[].class, null, prop);
}
/**
* Strings never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
*/
@Override
public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts) {
return this;
}
@Override
public void serializeContents(String[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
final int len = value.length;
if (len == 0) {
return;
}
if (_elementSerializer != null) {
serializeContentsSlow(value, jgen, provider, _elementSerializer);
return;
}
/* 08-Dec-2008, tatus: If we want this to be fully overridable
* (for example, to support String cleanup during writing
* or something), we should find serializer by provider.
* But for now, that seems like an overkill: and caller can
* add custom serializer if that is needed as well.
* (ditto for null values)
*/
//JsonSerializer<String> ser = (JsonSerializer<String>)provider.findValueSerializer(String.class);
for (int i = 0; i < len; ++i) {
String str = value[i];
if (str == null) {
jgen.writeNull();
} else {
//ser.serialize(value[i], jgen, provider);
jgen.writeString(value[i]);
}
}
}
private void serializeContentsSlow(String[] value, JsonGenerator jgen, SerializerProvider provider,
JsonSerializer<Object> ser)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
String str = value[i];
if (str == null) {
provider.defaultSerializeNull(jgen);
} else {
ser.serialize(value[i], jgen, provider);
}
}
}
/**
* Need to get callback to resolve value serializer, which may
* be overridden by custom serializer
*/
@Override
public void resolve(SerializerProvider provider)
throws JsonMappingException
{
JsonSerializer<Object> ser = provider.findValueSerializer(String.class, _property);
// Retain if not the standard implementation
if (ser != null && ser.getClass().getAnnotation(JacksonStdImpl.class) == null) {
_elementSerializer = ser;
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
o.put("items", createSchemaNode("string"));
return o;
}
}
@JacksonStdImpl
public final static class BooleanArraySerializer
extends ArraySerializerBase<boolean[]>
{
public BooleanArraySerializer() { super(boolean[].class, null, null); }
/**
* Booleans never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
*/
@Override
public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts)
{
return this;
}
@Override
public void serializeContents(boolean[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
jgen.writeBoolean(value[i]);
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
o.put("items", createSchemaNode("boolean"));
return o;
}
}
/**
* Unlike other integral number array serializers, we do not just print out byte values
* as numbers. Instead, we assume that it would make more sense to output content
* as base64 encoded bytes (using default base64 encoding).
*<p>
* NOTE: since it is NOT serialized as an array, can not use AsArraySerializer as base
*/
@JacksonStdImpl
public final static class ByteArraySerializer
extends SerializerBase<byte[]>
{
public ByteArraySerializer() {
super(byte[].class);
}
@Override
public void serialize(byte[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
jgen.writeBinary(value);
}
@Override
public void serializeWithType(byte[] value, JsonGenerator jgen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException, JsonGenerationException
{
typeSer.writeTypePrefixForScalar(value, jgen);
jgen.writeBinary(value);
typeSer.writeTypeSuffixForScalar(value, jgen);
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
ObjectNode itemSchema = createSchemaNode("string"); //binary values written as strings?
o.put("items", itemSchema);
return o;
}
}
@JacksonStdImpl
public final static class ShortArraySerializer
extends ArraySerializerBase<short[]>
{
public ShortArraySerializer() { this(null); }
public ShortArraySerializer(TypeSerializer vts) { super(short[].class, vts, null); }
@Override
public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts) {
return new ShortArraySerializer(vts);
}
@SuppressWarnings("cast")
@Override
public void serializeContents(short[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
jgen.writeNumber((int)value[i]);
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
//no "short" type defined by json
ObjectNode o = createSchemaNode("array", true);
o.put("items", createSchemaNode("integer"));
return o;
}
}
/**
* Character arrays are different from other integral number arrays in that
* they are most likely to be textual data, and should be written as
* Strings, not arrays of entries.
*<p>
* NOTE: since it is NOT serialized as an array, can not use AsArraySerializer as base
*/
@JacksonStdImpl
public final static class CharArraySerializer
extends SerializerBase<char[]>
{
public CharArraySerializer() { super(char[].class); }
@Override
public void serialize(char[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
// [JACKSON-289] allows serializing as 'sparse' char array too:
if (provider.isEnabled(SerializationConfig.Feature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS)) {
jgen.writeStartArray();
_writeArrayContents(jgen, value);
jgen.writeEndArray();
} else {
jgen.writeString(value, 0, value.length);
}
}
@Override
public void serializeWithType(char[] value, JsonGenerator jgen, SerializerProvider provider,
TypeSerializer typeSer)
throws IOException, JsonGenerationException
{
// [JACKSON-289] allows serializing as 'sparse' char array too:
if (provider.isEnabled(SerializationConfig.Feature.WRITE_CHAR_ARRAYS_AS_JSON_ARRAYS)) {
typeSer.writeTypePrefixForArray(value, jgen);
_writeArrayContents(jgen, value);
typeSer.writeTypeSuffixForArray(value, jgen);
} else { // default is to write as simple String
typeSer.writeTypePrefixForScalar(value, jgen);
jgen.writeString(value, 0, value.length);
typeSer.writeTypeSuffixForScalar(value, jgen);
}
}
private final void _writeArrayContents(JsonGenerator jgen, char[] value)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
jgen.writeString(value, i, 1);
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
ObjectNode itemSchema = createSchemaNode("string");
itemSchema.put("type", "string");
o.put("items", itemSchema);
return o;
}
}
@JacksonStdImpl
public final static class IntArraySerializer
extends ArraySerializerBase<int[]>
{
public IntArraySerializer() { super(int[].class, null, null); }
/**
* Ints never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
*/
@Override
public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts)
{
return this;
}
@Override
public void serializeContents(int[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
jgen.writeNumber(value[i]);
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
o.put("items", createSchemaNode("integer"));
return o;
}
}
@JacksonStdImpl
public final static class LongArraySerializer
extends ArraySerializerBase<long[]>
{
public LongArraySerializer() { this(null); }
public LongArraySerializer(TypeSerializer vts) { super(long[].class, vts, null); }
@Override
public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts) {
return new LongArraySerializer(vts);
}
@Override
public void serializeContents(long[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
jgen.writeNumber(value[i]);
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
o.put("items", createSchemaNode("number", true));
return o;
}
}
@JacksonStdImpl
public final static class FloatArraySerializer
extends ArraySerializerBase<float[]>
{
public FloatArraySerializer() { this(null); }
public FloatArraySerializer(TypeSerializer vts) { super(float[].class, vts, null); }
@Override
public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts) {
return new FloatArraySerializer(vts);
}
@Override
public void serializeContents(float[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
jgen.writeNumber(value[i]);
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
o.put("items", createSchemaNode("number"));
return o;
}
}
@JacksonStdImpl
public final static class DoubleArraySerializer
extends ArraySerializerBase<double[]>
{
public DoubleArraySerializer() { super(double[].class, null, null); }
/**
* Doubles never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
*/
@Override
public ContainerSerializerBase<?> _withValueTypeSerializer(TypeSerializer vts)
{
return this;
}
@Override
public void serializeContents(double[] value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonGenerationException
{
for (int i = 0, len = value.length; i < len; ++i) {
jgen.writeNumber(value[i]);
}
}
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
ObjectNode o = createSchemaNode("array", true);
o.put("items", createSchemaNode("number"));
return o;
}
}
}