aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatu Saloranta <tatu.saloranta@iki.fi>2017-07-19 13:06:29 -0700
committerTatu Saloranta <tatu.saloranta@iki.fi>2017-07-19 13:06:29 -0700
commit574d2bcaf6a8a3749217dcba27698ebcdc648572 (patch)
tree758ee1baa2fd2ff421fcb94bfe60e719ba93f2f3
parent445bd4482ff7e7fb2b222f410a5c9208f2a31c57 (diff)
downloadjackson-databind-574d2bcaf6a8a3749217dcba27698ebcdc648572.tar.gz
Add failing test for #1649
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java91
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java100
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java8
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java9
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java2
-rw-r--r--src/test/java/com/fasterxml/jackson/databind/ser/filter/MapInclusionTest.java7
-rw-r--r--src/test/java/com/fasterxml/jackson/failing/MapInclusion1649Test.java41
7 files changed, 149 insertions, 109 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java
index 0d5beb009..0c09ae156 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/BasicSerializerFactory.java
@@ -6,6 +6,7 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -1016,6 +1017,96 @@ public abstract class BasicSerializerFactory
/*
/**********************************************************
+ /* Factory methods for Reference types
+ /* (demoted from BeanSF down here in 2.9)
+ /**********************************************************
+ */
+
+ /**
+ * @since 2.7
+ */
+ public JsonSerializer<?> findReferenceSerializer(SerializerProvider prov, ReferenceType refType,
+ BeanDescription beanDesc, boolean staticTyping)
+ throws JsonMappingException
+ {
+ JavaType contentType = refType.getContentType();
+ TypeSerializer contentTypeSerializer = contentType.getTypeHandler();
+ final SerializationConfig config = prov.getConfig();
+ if (contentTypeSerializer == null) {
+ contentTypeSerializer = createTypeSerializer(config, contentType);
+ }
+ JsonSerializer<Object> contentSerializer = contentType.getValueHandler();
+ for (Serializers serializers : customSerializers()) {
+ JsonSerializer<?> ser = serializers.findReferenceSerializer(config, refType, beanDesc,
+ contentTypeSerializer, contentSerializer);
+ if (ser != null) {
+ return ser;
+ }
+ }
+ if (refType.isTypeOrSubTypeOf(AtomicReference.class)) {
+ return buildAtomicReferenceSerializer(prov, refType, beanDesc, staticTyping,
+ contentTypeSerializer, contentSerializer);
+ }
+ return null;
+ }
+
+ protected JsonSerializer<?> buildAtomicReferenceSerializer(SerializerProvider prov,
+ ReferenceType refType, BeanDescription beanDesc, boolean staticTyping,
+ TypeSerializer contentTypeSerializer, JsonSerializer<Object> contentSerializer)
+ throws JsonMappingException
+ {
+ final JavaType contentType = refType.getReferencedType();
+ JsonInclude.Value inclV = _findInclusionWithContent(prov, beanDesc,
+ contentType, AtomicReference.class);
+
+ // Need to support global legacy setting, for now:
+ JsonInclude.Include incl = (inclV == null) ? JsonInclude.Include.USE_DEFAULTS : inclV.getContentInclusion();
+ Object valueToSuppress;
+ boolean suppressNulls;
+
+ if (incl == JsonInclude.Include.USE_DEFAULTS
+ || incl == JsonInclude.Include.ALWAYS) {
+ valueToSuppress = null;
+ suppressNulls = false;
+ } else {
+ suppressNulls = true;
+ switch (incl) {
+ case NON_DEFAULT:
+ valueToSuppress = BeanUtil.getDefaultValue(contentType);
+ if (valueToSuppress != null) {
+ if (valueToSuppress.getClass().isArray()) {
+ valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
+ }
+ }
+ break;
+ case NON_ABSENT:
+ valueToSuppress = contentType.isReferenceType()
+ ? MapSerializer.MARKER_FOR_EMPTY : null;
+ break;
+ case NON_EMPTY:
+ valueToSuppress = MapSerializer.MARKER_FOR_EMPTY;
+ break;
+ case CUSTOM:
+ valueToSuppress = prov.includeFilterInstance(null, inclV.getContentFilter());
+ if (valueToSuppress == null) { // is this legal?
+ suppressNulls = true;
+ } else {
+ suppressNulls = prov.includeFilterSuppressNulls(valueToSuppress);
+ }
+ break;
+ case NON_NULL:
+ default: // should not matter but...
+ valueToSuppress = null;
+ break;
+ }
+ }
+ AtomicReferenceSerializer ser = new AtomicReferenceSerializer(refType, staticTyping,
+ contentTypeSerializer, contentSerializer);
+ return ser.withContentInclusion(valueToSuppress, suppressNulls);
+ }
+
+ /*
+ /**********************************************************
/* Factory methods, for non-container types
/**********************************************************
*/
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java
index af05bb4af..004025630 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/BeanSerializerFactory.java
@@ -1,10 +1,8 @@
package com.fasterxml.jackson.databind.ser;
import java.util.*;
-import java.util.concurrent.atomic.AtomicReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.ObjectIdGenerator;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
@@ -18,12 +16,9 @@ import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
import com.fasterxml.jackson.databind.ser.impl.FilteredBeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.ObjectIdWriter;
import com.fasterxml.jackson.databind.ser.impl.PropertyBasedObjectIdGenerator;
-import com.fasterxml.jackson.databind.ser.std.AtomicReferenceSerializer;
import com.fasterxml.jackson.databind.ser.std.MapSerializer;
import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer;
import com.fasterxml.jackson.databind.type.ReferenceType;
-import com.fasterxml.jackson.databind.util.ArrayBuilders;
-import com.fasterxml.jackson.databind.util.BeanUtil;
import com.fasterxml.jackson.databind.util.ClassUtil;
import com.fasterxml.jackson.databind.util.Converter;
@@ -285,89 +280,6 @@ public class BeanSerializerFactory
}
/**
- * @since 2.7
- */
- public JsonSerializer<?> findReferenceSerializer(SerializerProvider prov, ReferenceType refType,
- BeanDescription beanDesc, boolean staticTyping)
- throws JsonMappingException
- {
- JavaType contentType = refType.getContentType();
- TypeSerializer contentTypeSerializer = contentType.getTypeHandler();
- final SerializationConfig config = prov.getConfig();
- if (contentTypeSerializer == null) {
- contentTypeSerializer = createTypeSerializer(config, contentType);
- }
- JsonSerializer<Object> contentSerializer = contentType.getValueHandler();
- for (Serializers serializers : customSerializers()) {
- JsonSerializer<?> ser = serializers.findReferenceSerializer(config, refType, beanDesc,
- contentTypeSerializer, contentSerializer);
- if (ser != null) {
- return ser;
- }
- }
- if (refType.isTypeOrSubTypeOf(AtomicReference.class)) {
- return buildAtomicReferenceSerializer(prov, refType, beanDesc, staticTyping,
- contentTypeSerializer, contentSerializer);
- }
- return null;
- }
-
- protected JsonSerializer<?> buildAtomicReferenceSerializer(SerializerProvider prov,
- ReferenceType refType, BeanDescription beanDesc, boolean staticTyping,
- TypeSerializer contentTypeSerializer, JsonSerializer<Object> contentSerializer)
- throws JsonMappingException
- {
- final JavaType contentType = refType.getReferencedType();
- JsonInclude.Value inclV = _findInclusionWithContent(prov, beanDesc,
- contentType, AtomicReference.class);
-
- // Need to support global legacy setting, for now:
- JsonInclude.Include incl = (inclV == null) ? JsonInclude.Include.USE_DEFAULTS : inclV.getContentInclusion();
- Object valueToSuppress;
- boolean suppressNulls;
-
- if (incl == JsonInclude.Include.USE_DEFAULTS
- || incl == JsonInclude.Include.ALWAYS) {
- valueToSuppress = null;
- suppressNulls = false;
- } else {
- suppressNulls = true;
- switch (incl) {
- case NON_DEFAULT:
- valueToSuppress = BeanUtil.getDefaultValue(contentType);
- if (valueToSuppress != null) {
- if (valueToSuppress.getClass().isArray()) {
- valueToSuppress = ArrayBuilders.getArrayComparator(valueToSuppress);
- }
- }
- break;
- case NON_ABSENT:
- valueToSuppress = contentType.isReferenceType()
- ? MapSerializer.MARKER_FOR_EMPTY : null;
- break;
- case NON_EMPTY:
- valueToSuppress = MapSerializer.MARKER_FOR_EMPTY;
- break;
- case CUSTOM:
- valueToSuppress = prov.includeFilterInstance(null, inclV.getContentFilter());
- if (valueToSuppress == null) { // is this legal?
- suppressNulls = true;
- } else {
- suppressNulls = prov.includeFilterSuppressNulls(valueToSuppress);
- }
- break;
- case NON_NULL:
- default: // should not matter but...
- valueToSuppress = null;
- break;
- }
- }
- AtomicReferenceSerializer ser = new AtomicReferenceSerializer(refType, staticTyping,
- contentTypeSerializer, contentSerializer);
- return ser.withContentInclusion(valueToSuppress, suppressNulls);
- }
-
- /**
* Method called to create a type information serializer for values of given
* non-container property
* if one is needed. If not needed (no polymorphic handling configured), should
@@ -480,10 +392,9 @@ public class BeanSerializerFactory
}
}
- /* And if Object Id is needed, some preparation for that as well: better
- * do before view handling, mostly for the custom id case which needs
- * access to a property
- */
+ // And if Object Id is needed, some preparation for that as well: better
+ // do before view handling, mostly for the custom id case which needs
+ // access to a property
builder.setObjectIdWriter(constructObjectIdHandler(prov, beanDesc, props));
builder.setProperties(props);
@@ -562,9 +473,8 @@ public class BeanSerializerFactory
BeanPropertyWriter prop = props.get(i);
if (propName.equals(prop.getName())) {
idProp = prop;
- /* Let's force it to be the first property to output
- * (although it may still get rearranged etc)
- */
+ // Let's force it to be the first property to output
+ // (although it may still get rearranged etc)
if (i > 0) {
props.remove(i);
props.add(0, idProp);
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java
index 080a13c9b..43602e351 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyBuilder.java
@@ -107,10 +107,9 @@ public class PropertyBuilder
// Container types can have separate type serializers for content (value / element) type
if (contentTypeSer != null) {
- /* 04-Feb-2010, tatu: Let's force static typing for collection, if there is
- * type information for contents. Should work well (for JAXB case); can be
- * revisited if this causes problems.
- */
+ // 04-Feb-2010, tatu: Let's force static typing for collection, if there is
+ // type information for contents. Should work well (for JAXB case); can be
+ // revisited if this causes problems.
if (serializationType == null) {
// serializationType = TypeFactory.type(am.getGenericType(), _beanDesc.getType());
serializationType = declaredType;
@@ -149,6 +148,7 @@ public class PropertyBuilder
// property annotation override
inclV = inclV.withOverrides(propDef.findInclusion());
+
JsonInclude.Include inclusion = inclV.getValueInclusion();
if (inclusion == JsonInclude.Include.USE_DEFAULTS) { // should not occur but...
inclusion = JsonInclude.Include.ALWAYS;
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
index db75c5e1a..a95d81203 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/BeanSerializerBase.java
@@ -438,7 +438,7 @@ public abstract class BeanSerializerBase
// 16-Oct-2016, tatu: Ditto for `Map`, `Map.Entry` subtypes
} else if (shape == JsonFormat.Shape.NATURAL) {
if (_beanType.isMapLikeType() && Map.class.isAssignableFrom(_handledType)) {
-;
+ ;
} else if (Map.Entry.class.isAssignableFrom(_handledType)) {
JavaType mapEntryType = _beanType.findSuperType(Map.Entry.class);
@@ -726,10 +726,9 @@ public abstract class BeanSerializerBase
String name = (i == props.length) ? "[anySetter]" : props[i].getName();
wrapAndThrow(provider, e, bean, name);
} catch (StackOverflowError e) {
- /* 04-Sep-2009, tatu: Dealing with this is tricky, since we do not
- * have many stack frames to spare... just one or two; can't
- * make many calls.
- */
+ // 04-Sep-2009, tatu: Dealing with this is tricky, since we don't have many
+ // stack frames to spare... just one or two; can't make many calls.
+
// 10-Dec-2015, tatu: and due to above, avoid "from" method, call ctor directly:
//JsonMappingException mapE = JsonMappingException.from(gen, "Infinite recursion (StackOverflowError)", e);
JsonMappingException mapE = new JsonMappingException(gen, "Infinite recursion (StackOverflowError)", e);
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java
index 424cb3a3a..b4d6bb9e6 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapSerializer.java
@@ -108,7 +108,7 @@ public class MapSerializer
* Set of entries to omit during serialization, if any
*/
protected final Set<String> _ignoredEntries;
-
+
/**
* Id of the property filter to use, if any; null if none.
*
diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/filter/MapInclusionTest.java b/src/test/java/com/fasterxml/jackson/databind/ser/filter/MapInclusionTest.java
index cb8eb094c..cdd0a944f 100644
--- a/src/test/java/com/fasterxml/jackson/databind/ser/filter/MapInclusionTest.java
+++ b/src/test/java/com/fasterxml/jackson/databind/ser/filter/MapInclusionTest.java
@@ -1,8 +1,7 @@
package com.fasterxml.jackson.databind.ser.filter;
import java.io.IOException;
-import java.util.LinkedHashMap;
-import java.util.Map;
+import java.util.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.*;
@@ -41,7 +40,7 @@ public class MapInclusionTest extends BaseMapTest
return this;
}
}
-
+
/*
/**********************************************************
/* Test methods
@@ -67,7 +66,7 @@ public class MapInclusionTest extends BaseMapTest
String json = MAPPER.writeValueAsString(input);
assertEquals(aposToQuotes("{'stuff':{'b':''}}"), json);
}
-
+
public void testNonEmptyNoNullsMap() throws IOException
{
NoNullsNotEmptyMapContainer input = new NoNullsNotEmptyMapContainer()
diff --git a/src/test/java/com/fasterxml/jackson/failing/MapInclusion1649Test.java b/src/test/java/com/fasterxml/jackson/failing/MapInclusion1649Test.java
new file mode 100644
index 000000000..d2d0906d4
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/failing/MapInclusion1649Test.java
@@ -0,0 +1,41 @@
+package com.fasterxml.jackson.failing;
+
+import java.io.IOException;
+import java.util.*;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.*;
+
+public class MapInclusion1649Test extends BaseMapTest
+{
+ @JsonInclude(value=JsonInclude.Include.NON_EMPTY, content=JsonInclude.Include.NON_EMPTY)
+ static class Bean1649 {
+ public Map<String, String> map;
+
+ public Bean1649(String key, String value) {
+ map = new LinkedHashMap<>();
+ map.put(key, value);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Test methods
+ /**********************************************************
+ */
+
+ final private ObjectMapper MAPPER = objectMapper();
+
+ // [databind#1649]
+ public void testNonEmptyViaClass() throws IOException
+ {
+ // non-empty/null, include
+ assertEquals(aposToQuotes("{'map':{'a':'b'}}"),
+ MAPPER.writeValueAsString(new Bean1649("a", "b")));
+ // null, empty, nope
+ assertEquals(aposToQuotes("{}"),
+ MAPPER.writeValueAsString(new Bean1649("a", null)));
+ assertEquals(aposToQuotes("{}"),
+ MAPPER.writeValueAsString(new Bean1649("a", "")));
+ }
+}