aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatu Saloranta <tatu.saloranta@iki.fi>2015-06-19 09:33:30 -0700
committerTatu Saloranta <tatu.saloranta@iki.fi>2015-06-19 09:33:30 -0700
commitbd256eaa8934384409ac74ec58bf67925209af35 (patch)
tree3c86c0444badaf25290d164825211ac4d06ceab4
parent7defcfe28b4d9965a63215e8ec6f1b2b0f339cda (diff)
downloadjackson-databind-bd256eaa8934384409ac74ec58bf67925209af35.tar.gz
More work on contextual property features via @JsonFormat
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java7
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/ArraySerializerBase.java39
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/ByteArraySerializer.java80
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java9
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/StdArraySerializers.java119
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/struct/FormatFeaturesTest.java30
6 files changed, 211 insertions, 73 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java
index bb0c2045c..41916bdb9 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/impl/StringArraySerializer.java
@@ -56,7 +56,12 @@ public class StringArraySerializer
super(src, prop, unwrapSingle);
_elementSerializer = (JsonSerializer<Object>) ser;
}
-
+
+ @Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop, Boolean unwrapSingle) {
+ return new StringArraySerializer(this, prop, _elementSerializer, unwrapSingle);
+ }
+
/**
* Strings never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/ArraySerializerBase.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/ArraySerializerBase.java
index 3df6d3593..9ec87fd48 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/ArraySerializerBase.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/ArraySerializerBase.java
@@ -2,6 +2,7 @@ package com.fasterxml.jackson.databind.ser.std;
import java.io.IOException;
+import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
@@ -16,6 +17,7 @@ import com.fasterxml.jackson.databind.ser.*;
@SuppressWarnings("serial")
public abstract class ArraySerializerBase<T>
extends ContainerSerializer<T>
+ implements ContextualSerializer // for 'unwrapSingleElemArray'
{
protected final BeanProperty _property;
@@ -78,16 +80,45 @@ public abstract class ArraySerializerBase<T>
_unwrapSingle = src._unwrapSingle;
}
+ /**
+ * @since 2.6
+ */
+ public abstract JsonSerializer<?> _withResolved(BeanProperty prop,
+ Boolean unwrapSingle);
+
+ @Override
+ public JsonSerializer<?> createContextual(SerializerProvider provider,
+ BeanProperty property) throws JsonMappingException
+ {
+ Boolean unwrapSingle = null;
+
+ // First: if we have a property, may have property-annotation overrides
+ if (property != null) {
+ final AnnotationIntrospector intr = provider.getAnnotationIntrospector();
+ JsonFormat.Value format = property.findFormatOverrides(intr);
+ if (format != null) {
+ unwrapSingle = format.getFeature(JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);
+ if (unwrapSingle != _unwrapSingle) {
+ return _withResolved(property, unwrapSingle);
+ }
+ }
+ }
+ return this;
+ }
+
// NOTE: as of 2.5, sub-classes SHOULD override (in 2.4 and before, was final),
// at least if they can provide access to actual size of value and use `writeStartArray()`
// variant that passes size of array to output, which is helpful with some data formats
@Override
public void serialize(T value, JsonGenerator gen, SerializerProvider provider) throws IOException
{
- if (provider.isEnabled(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
- && hasSingleElement(value)) {
- serializeContents(value, gen, provider);
- return;
+ if (((_unwrapSingle == null) &&
+ provider.isEnabled(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED))
+ || (_unwrapSingle == Boolean.TRUE)) {
+ if (hasSingleElement(value)) {
+ serializeContents(value, gen, provider);
+ return;
+ }
}
gen.writeStartArray();
// [databind#631]: Assign current value, to be accessible by custom serializers
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/ByteArraySerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/ByteArraySerializer.java
new file mode 100644
index 000000000..536dc6b97
--- /dev/null
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/ByteArraySerializer.java
@@ -0,0 +1,80 @@
+package com.fasterxml.jackson.databind.ser.std;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
+import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonArrayFormatVisitor;
+import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
+import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatVisitorWrapper;
+import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * 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
+ *<p>
+ * NOTE: since 2.6, has been a main-level class; earlier was embedded in
+ * {@link StdArraySerializers}.
+ */
+@JacksonStdImpl
+public class ByteArraySerializer extends StdSerializer<byte[]>
+{
+ private static final long serialVersionUID = 1L;
+
+ public ByteArraySerializer() {
+ super(byte[].class);
+ }
+
+ @Override
+ public boolean isEmpty(SerializerProvider prov, byte[] value) {
+ return (value == null) || (value.length == 0);
+ }
+
+ @Override
+ public void serialize(byte[] value, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException
+ {
+ jgen.writeBinary(provider.getConfig().getBase64Variant(),
+ value, 0, value.length);
+ }
+
+ @Override
+ public void serializeWithType(byte[] value, JsonGenerator jgen, SerializerProvider provider,
+ TypeSerializer typeSer)
+ throws IOException
+ {
+ typeSer.writeTypePrefixForScalar(value, jgen);
+ jgen.writeBinary(provider.getConfig().getBase64Variant(),
+ value, 0, value.length);
+ 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?
+ return o.set("items", itemSchema);
+ }
+
+ @Override
+ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
+ throws JsonMappingException
+ {
+ if (visitor != null) {
+ JsonArrayFormatVisitor v2 = visitor.expectArrayFormat(typeHint);
+ if (v2 != null) {
+ v2.itemsFormat(JsonFormatTypes.STRING);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java
index 21f76476a..0fbe9148e 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/ObjectArraySerializer.java
@@ -95,10 +95,15 @@ public class ObjectArraySerializer
_dynamicSerializers = src._dynamicSerializers;
_elementSerializer = (JsonSerializer<Object>) elementSerializer;
}
+
+ @Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop, Boolean unwrapSingle) {
+ return new ObjectArraySerializer(this, prop,
+ _valueTypeSerializer, _elementSerializer, unwrapSingle);
+ }
@Override
- public ContainerSerializer<?> _withValueTypeSerializer(TypeSerializer vts)
- {
+ public ContainerSerializer<?> _withValueTypeSerializer(TypeSerializer vts) {
return new ObjectArraySerializer(_elementType, _staticTyping, vts, _elementSerializer);
}
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdArraySerializers.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdArraySerializers.java
index 733edc6e5..5f753505e 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/StdArraySerializers.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/StdArraySerializers.java
@@ -4,6 +4,7 @@ import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
+import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.annotation.JacksonStdImpl;
@@ -13,6 +14,7 @@ import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonFormatTypes;
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.ser.ContainerSerializer;
+import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.fasterxml.jackson.databind.type.TypeFactory;
/**
@@ -27,7 +29,7 @@ public class StdArraySerializers
static {
// Arrays of various types (including common object types)
_arraySerializers.put(boolean[].class.getName(), new StdArraySerializers.BooleanArraySerializer());
- _arraySerializers.put(byte[].class.getName(), new StdArraySerializers.ByteArraySerializer());
+ _arraySerializers.put(byte[].class.getName(), new ByteArraySerializer());
_arraySerializers.put(char[].class.getName(), new StdArraySerializers.CharArraySerializer());
_arraySerializers.put(short[].class.getName(), new StdArraySerializers.ShortArraySerializer());
_arraySerializers.put(int[].class.getName(), new StdArraySerializers.IntArraySerializer());
@@ -56,7 +58,8 @@ public class StdArraySerializers
* Intermediate base class used for cases where we may add
* type information (excludes boolean/int/double arrays).
*/
- protected abstract static class TypedPrimitiveArraySerializer<T> extends ArraySerializerBase<T>
+ protected abstract static class TypedPrimitiveArraySerializer<T>
+ extends ArraySerializerBase<T>
{
/**
* Type serializer to use for values, if any.
@@ -82,13 +85,24 @@ public class StdArraySerializers
*/
@JacksonStdImpl
- public static class BooleanArraySerializer extends ArraySerializerBase<boolean[]>
+ public static class BooleanArraySerializer
+ extends ArraySerializerBase<boolean[]>
{
// as above, assuming no one re-defines primitive/wrapper types
private final static JavaType VALUE_TYPE = TypeFactory.defaultInstance().uncheckedSimpleType(Boolean.class);
public BooleanArraySerializer() { super(boolean[].class); }
+ protected BooleanArraySerializer(BooleanArraySerializer src,
+ BeanProperty prop, Boolean unwrapSingle) {
+ super(src, prop, unwrapSingle);
+ }
+
+ @Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop, Boolean unwrapSingle) {
+ return new BooleanArraySerializer(this, prop, unwrapSingle);
+ }
+
/**
* Booleans never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
@@ -167,62 +181,14 @@ public class StdArraySerializers
}
/**
- * 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
+ * @deprecated Since 2.6 use the main-level implementation, base class of this class
*/
+ @Deprecated
@JacksonStdImpl
- public static class ByteArraySerializer extends StdSerializer<byte[]>
+ public static class ByteArraySerializer
+ extends com.fasterxml.jackson.databind.ser.std.ByteArraySerializer
{
- public ByteArraySerializer() {
- super(byte[].class);
- }
-
- @Override
- public boolean isEmpty(SerializerProvider prov, byte[] value) {
- return (value == null) || (value.length == 0);
- }
-
- @Override
- public void serialize(byte[] value, JsonGenerator jgen, SerializerProvider provider)
- throws IOException
- {
- jgen.writeBinary(provider.getConfig().getBase64Variant(),
- value, 0, value.length);
- }
-
- @Override
- public void serializeWithType(byte[] value, JsonGenerator jgen, SerializerProvider provider,
- TypeSerializer typeSer)
- throws IOException
- {
- typeSer.writeTypePrefixForScalar(value, jgen);
- jgen.writeBinary(provider.getConfig().getBase64Variant(),
- value, 0, value.length);
- 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?
- return o.set("items", itemSchema);
- }
-
- @Override
- public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType typeHint)
- throws JsonMappingException
- {
- if (visitor != null) {
- JsonArrayFormatVisitor v2 = visitor.expectArrayFormat(typeHint);
- if (v2 != null) {
- v2.itemsFormat(JsonFormatTypes.STRING);
- }
- }
- }
+ public ByteArraySerializer() { super(); }
}
@JacksonStdImpl
@@ -238,6 +204,11 @@ public class StdArraySerializers
}
@Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop,Boolean unwrapSingle) {
+ return new ShortArraySerializer(this, prop, _valueTypeSerializer, unwrapSingle);
+ }
+
+ @Override
public ContainerSerializer<?> _withValueTypeSerializer(TypeSerializer vts) {
return new ShortArraySerializer(this, _property, vts, _unwrapSingle);
}
@@ -406,6 +377,19 @@ public class StdArraySerializers
public IntArraySerializer() { super(int[].class); }
/**
+ * @since 2.6
+ */
+ protected IntArraySerializer(IntArraySerializer src,
+ BeanProperty prop, Boolean unwrapSingle) {
+ super(src, prop, unwrapSingle);
+ }
+
+ @Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop, Boolean unwrapSingle) {
+ return new IntArraySerializer(this, prop, unwrapSingle);
+ }
+
+ /**
* Ints never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
*/
@@ -491,6 +475,11 @@ public class StdArraySerializers
}
@Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop,Boolean unwrapSingle) {
+ return new LongArraySerializer(this, prop, _valueTypeSerializer, unwrapSingle);
+ }
+
+ @Override
public ContainerSerializer<?> _withValueTypeSerializer(TypeSerializer vts) {
return new LongArraySerializer(this, _property, vts, _unwrapSingle);
}
@@ -591,6 +580,11 @@ public class StdArraySerializers
}
@Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop,Boolean unwrapSingle) {
+ return new FloatArraySerializer(this, prop, _valueTypeSerializer, unwrapSingle);
+ }
+
+ @Override
public JavaType getContentType() {
return VALUE_TYPE;
}
@@ -671,6 +665,19 @@ public class StdArraySerializers
public DoubleArraySerializer() { super(double[].class); }
/**
+ * @since 2.6
+ */
+ protected DoubleArraySerializer(DoubleArraySerializer src,
+ BeanProperty prop, Boolean unwrapSingle) {
+ super(src, prop, unwrapSingle);
+ }
+
+ @Override
+ public JsonSerializer<?> _withResolved(BeanProperty prop, Boolean unwrapSingle) {
+ return new DoubleArraySerializer(this, prop, unwrapSingle);
+ }
+
+ /**
* Doubles never add type info; hence, even if type serializer is suggested,
* we'll ignore it...
*/
diff --git a/src/test/java/com/fasterxml/jackson/databind/struct/FormatFeaturesTest.java b/src/test/java/com/fasterxml/jackson/databind/struct/FormatFeaturesTest.java
index deb1276b6..602ddcd59 100644
--- a/src/test/java/com/fasterxml/jackson/databind/struct/FormatFeaturesTest.java
+++ b/src/test/java/com/fasterxml/jackson/databind/struct/FormatFeaturesTest.java
@@ -1,5 +1,7 @@
package com.fasterxml.jackson.databind.struct;
+import java.util.*;
+
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.databind.*;
@@ -9,7 +11,7 @@ import com.fasterxml.jackson.databind.*;
public class FormatFeaturesTest extends BaseMapTest
{
@JsonPropertyOrder( { "strings", "ints", "bools" })
- static class WrapWriteTest
+ static class WrapWriteWithArrays
{
@JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
public String[] strings = new String[] {
@@ -24,26 +26,34 @@ public class FormatFeaturesTest extends BaseMapTest
public boolean[] bools = new boolean[] { true };
}
+ @JsonPropertyOrder( { "strings", "ints", "bools" })
+ static class WrapWriteWithCollections
+ {
+ @JsonFormat(with={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
+ public List<String> strings = Arrays.asList("a");
+
+ @JsonFormat(without={ JsonFormat.Feature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED })
+ public Collection<Integer> ints = Arrays.asList(Integer.valueOf(1));
+
+ public Set<Boolean> bools = Collections.singleton(true);
+ }
+
private final ObjectMapper MAPPER = new ObjectMapper();
public void testWriteSingleElemArrayUnwrapped() throws Exception
{
- // Comment out temporarily, to prevent build fail!
-
- /*
-
// default: strings unwrapped, ints wrapped
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':[true]}"),
- MAPPER.writeValueAsString(new WrapWriteTest()));
+ MAPPER.writeValueAsString(new WrapWriteWithArrays()));
// change global default to "yes, unwrap"; changes 'bools' only
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':true}"),
- MAPPER.writeValueAsString(new WrapWriteTest()));
+ MAPPER.writer().with(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
+ .writeValueAsString(new WrapWriteWithArrays()));
// change global default to "no, don't, unwrap", same as first case
assertEquals(aposToQuotes("{'strings':'a','ints':[1],'bools':[true]}"),
- MAPPER.writeValueAsString(new WrapWriteTest()));
- */
+ MAPPER.writer().without(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED)
+ .writeValueAsString(new WrapWriteWithArrays()));
}
-
}