Fix #1655
diff --git a/release-notes/VERSION b/release-notes/VERSION
index 66271eb..82db869 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -90,6 +90,8 @@
#1637: `ObjectReader.at()` with `JsonPointer` stops after first collection
(reported by Chris P)
#1653: Convenience overload(s) for ObjectMapper#registerSubtypes
+#1655: `@JsonAnyGetter` uses different `bean` parameter in `SimpleBeanPropertyFilter`
+ (reported by georgeflugq@github)
2.8.9 (12-Jun-2017)
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java
index db14484..045adea 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/AnyGetterWriter.java
@@ -83,13 +83,14 @@
}
// 19-Oct-2014, tatu: Should we try to support @JsonInclude options here?
if (_mapSerializer != null) {
- _mapSerializer.serializeFilteredFields((Map<?,?>) value, gen, provider, filter, null);
+ _mapSerializer.serializeFilteredAnyProperties(provider, gen, bean,(Map<?,?>) value,
+ filter, null);
return;
}
// ... not sure how custom handler would do it
_serializer.serialize(value, gen, provider);
}
-
+
// Note: NOT part of ResolvableSerializer...
@SuppressWarnings("unchecked")
public void resolve(SerializerProvider provider) throws JsonMappingException
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyFilter.java b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyFilter.java
index a77c540..89f32ef 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/PropertyFilter.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/PropertyFilter.java
@@ -34,17 +34,17 @@
* Typical implementation is something like:
*<pre>
* if (include(writer)) {
- * writer.serializeAsField(pojo, jgen, prov);
+ * writer.serializeAsField(pojo, gen, prov);
* }
*</pre>
*
* @param pojo Object that contains property value to serialize
- * @param jgen Generator use for serializing value
+ * @param gen Generator use for serializing value
* @param prov Provider that can be used for accessing dynamic aspects of serialization
* processing
* @param writer Object called to do actual serialization of the field, if not filtered out
*/
- public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov,
+ public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider prov,
PropertyWriter writer)
throws Exception;
@@ -58,17 +58,17 @@
* Typical implementation is something like:
*<pre>
* if (include(writer)) {
- * writer.serializeAsElement(pojo, jgen, prov);
+ * writer.serializeAsElement(pojo, gen, prov);
* }
*</pre>
*
* @param elementValue Element value being serializerd
- * @param jgen Generator use for serializing value
+ * @param gen Generator use for serializing value
* @param prov Provider that can be used for accessing dynamic aspects of serialization
* processing
* @param writer Object called to do actual serialization of the field, if not filtered out
*/
- public void serializeAsElement(Object elementValue, JsonGenerator jgen, SerializerProvider prov,
+ public void serializeAsElement(Object elementValue, JsonGenerator gen, SerializerProvider prov,
PropertyWriter writer)
throws Exception;
diff --git a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapProperty.java b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapProperty.java
index 41fdb1e..fa0b6e0 100644
--- a/src/main/java/com/fasterxml/jackson/databind/ser/std/MapProperty.java
+++ b/src/main/java/com/fasterxml/jackson/databind/ser/std/MapProperty.java
@@ -28,7 +28,7 @@
protected final BeanProperty _property;
- protected Object _key;
+ protected Object _key, _value;
protected JsonSerializer<Object> _keySerializer, _valueSerializer;
@@ -43,10 +43,11 @@
* Initialization method that needs to be called before passing
* property to filter.
*/
- public void reset(Object key,
+ public void reset(Object key, Object value,
JsonSerializer<Object> keySer, JsonSerializer<Object> valueSer)
{
_key = key;
+ _value = value;
_keySerializer = keySer;
_valueSerializer = valueSer;
}
@@ -59,6 +60,20 @@
return String.valueOf(_key);
}
+ /**
+ * @since 2.9
+ */
+ public Object getValue() {
+ return _value;
+ }
+
+ /**
+ * @since 2.9
+ */
+ public void setValue(Object v) {
+ _value = v;
+ }
+
@Override
public PropertyName getFullName() {
return new PropertyName(getName());
@@ -75,19 +90,19 @@
}
@Override
- public void serializeAsField(Object value, JsonGenerator gen,
+ public void serializeAsField(Object map, JsonGenerator gen,
SerializerProvider provider) throws IOException
{
_keySerializer.serialize(_key, gen, provider);
if (_typeSerializer == null) {
- _valueSerializer.serialize(value, gen, provider);
+ _valueSerializer.serialize(_value, gen, provider);
} else {
- _valueSerializer.serializeWithType(value, gen, provider, _typeSerializer);
+ _valueSerializer.serializeWithType(_value, gen, provider, _typeSerializer);
}
}
@Override
- public void serializeAsOmittedField(Object value, JsonGenerator gen,
+ public void serializeAsOmittedField(Object map, JsonGenerator gen,
SerializerProvider provider) throws Exception
{
if (!gen.canOmitFields()) {
@@ -96,13 +111,13 @@
}
@Override
- public void serializeAsElement(Object value, JsonGenerator gen,
+ public void serializeAsElement(Object map, JsonGenerator gen,
SerializerProvider provider) throws Exception
{
if (_typeSerializer == null) {
- _valueSerializer.serialize(value, gen, provider);
+ _valueSerializer.serialize(_value, gen, provider);
} else {
- _valueSerializer.serializeWithType(value, gen, provider, _typeSerializer);
+ _valueSerializer.serializeWithType(_value, gen, provider, _typeSerializer);
}
}
@@ -132,7 +147,7 @@
public void depositSchemaProperty(ObjectNode propertiesNode,
SerializerProvider provider) throws JsonMappingException {
// nothing to do here
- }
+ }
@Override
public JavaType getType() {
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 2bfb904..e30987c 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
@@ -872,9 +872,9 @@
}
}
// and with that, ask filter to handle it
- prop.reset(keyElem, keySerializer, valueSer);
+ prop.reset(keyElem, valueElem, keySerializer, valueSer);
try {
- filter.serializeAsField(valueElem, gen, provider, prop);
+ filter.serializeAsField(value, gen, provider, prop);
} catch (Exception e) {
wrapAndThrow(provider, e, value, String.valueOf(keyElem));
}
@@ -935,16 +935,80 @@
}
}
+ /**
+ * Helper method used when we have a JSON Filter to use AND contents are
+ * "any properties" of a POJO.
+ *
+ * @param bean Enclosing POJO that has any-getter used to obtain "any properties"
+ *
+ * @since 2.9
+ */
+ public void serializeFilteredAnyProperties(SerializerProvider provider, JsonGenerator gen,
+ Object bean, Map<?,?> value, PropertyFilter filter,
+ Object suppressableValue)
+ throws IOException
+ {
+ final Set<String> ignored = _ignoredEntries;
+ final MapProperty prop = new MapProperty(_valueTypeSerializer, _property);
+ final boolean checkEmpty = (MARKER_FOR_EMPTY == suppressableValue);
+
+ for (Map.Entry<?,?> entry : value.entrySet()) {
+ // First, serialize key; unless ignorable by key
+ final Object keyElem = entry.getKey();
+ if (ignored != null && ignored.contains(keyElem)) continue;
+
+ JsonSerializer<Object> keySerializer;
+ if (keyElem == null) {
+ keySerializer = provider.findNullKeySerializer(_keyType, _property);
+ } else {
+ keySerializer = _keySerializer;
+ }
+ // or by value; nulls often suppressed
+ final Object valueElem = entry.getValue();
+
+ JsonSerializer<Object> valueSer;
+ // And then value
+ if (valueElem == null) {
+ if (_suppressNulls) {
+ continue;
+ }
+ valueSer = provider.getDefaultNullValueSerializer();
+ } else {
+ valueSer = _valueSerializer;
+ if (valueSer == null) {
+ valueSer = _findSerializer(provider, valueElem);
+ }
+ // also may need to skip non-empty values:
+ if (checkEmpty) {
+ if (valueSer.isEmpty(provider, valueElem)) {
+ continue;
+ }
+ } else if (suppressableValue != null) {
+ if (suppressableValue.equals(valueElem)) {
+ continue;
+ }
+ }
+ }
+ // and with that, ask filter to handle it
+ prop.reset(keyElem, valueElem, keySerializer, valueSer);
+ try {
+ filter.serializeAsField(bean, gen, provider, prop);
+ } catch (Exception e) {
+ wrapAndThrow(provider, e, value, String.valueOf(keyElem));
+ }
+ }
+ }
+
/*
/**********************************************************
/* Schema related functionality
/**********************************************************
*/
-
+
@Override
public JsonNode getSchema(SerializerProvider provider, Type typeHint)
{
- //(ryan) even though it's possible to statically determine the "value" type of the map,
+ // even though it's possible to statically determine the "value" type of the map,
// there's no way to statically determine the keys, so the "Entries" can't be determined.
return createSchemaNode("object", true);
}
diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestAnyGetterFiltering.java b/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestAnyGetterFiltering.java
index 9983d47..dadc7e2 100644
--- a/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestAnyGetterFiltering.java
+++ b/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestAnyGetterFiltering.java
@@ -3,7 +3,9 @@
import java.util.*;
import com.fasterxml.jackson.annotation.*;
+
import com.fasterxml.jackson.core.JsonGenerator;
+
import com.fasterxml.jackson.databind.BaseMapTest;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
@@ -51,6 +53,32 @@
}
}
+ // [databind#1655]
+ @JsonFilter("CustomFilter")
+ static class OuterObject {
+ public int getExplicitProperty() {
+ return 42;
+ }
+
+ @JsonAnyGetter
+ public Map<String, Object> getAny() {
+ Map<String, Object> extra = new HashMap<>();
+ extra.put("dynamicProperty", "I will not serialize");
+ return extra;
+ }
+ }
+
+ static class CustomFilter extends SimpleBeanPropertyFilter {
+ @Override
+ public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider provider,
+ PropertyWriter writer) throws Exception
+ {
+ if (pojo instanceof OuterObject) {
+ writer.serializeAsField(pojo, gen, provider);
+ }
+ }
+ }
+
/*
/**********************************************************
/* Test methods
@@ -72,4 +100,15 @@
assertEquals(aposToQuotes("{'a':'1','b':'3'}"),
MAPPER.writeValueAsString(new AnyBeanWithIgnores()));
}
+
+ // [databind#1655]
+ public void testAnyGetterPojo1655() throws Exception
+ {
+ FilterProvider filters = new SimpleFilterProvider().addFilter("CustomFilter", new CustomFilter());
+ String json = MAPPER.writer(filters).writeValueAsString(new OuterObject());
+ Map<?,?> stuff = MAPPER.readValue(json, Map.class);
+ if (stuff.size() != 2) {
+ fail("Should have 2 properties, got: "+stuff);
+ }
+ }
}
diff --git a/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestMapFiltering.java b/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestMapFiltering.java
index d78ad4a..ab2a9a9 100644
--- a/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestMapFiltering.java
+++ b/src/test/java/com/fasterxml/jackson/databind/ser/filter/TestMapFiltering.java
@@ -14,6 +14,7 @@
import com.fasterxml.jackson.databind.ser.*;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
+import com.fasterxml.jackson.databind.ser.std.MapProperty;
@SuppressWarnings("serial")
public class TestMapFiltering extends BaseMapTest
@@ -56,7 +57,7 @@
static class TestMapFilter implements PropertyFilter
{
@Override
- public void serializeAsField(Object value, JsonGenerator g,
+ public void serializeAsField(Object bean, JsonGenerator g,
SerializerProvider provider, PropertyWriter writer)
throws Exception
{
@@ -71,9 +72,14 @@
}
CustomOffset n = writer.findAnnotation(CustomOffset.class);
int offset = (n == null) ? 0 : n.value();
- Integer I = offset + ((Integer) value).intValue();
- writer.serializeAsField(I, g, provider);
+ // 12-Jun-2017, tatu: With 2.9, `value` is the surrounding POJO, so
+ // need to do casting
+ MapProperty prop = (MapProperty) writer;
+ Integer old = (Integer) prop.getValue();
+ prop.setValue(Integer.valueOf(offset + old.intValue()));
+
+ writer.serializeAsField(bean, g, provider);
}
@Override
diff --git a/src/test/java/com/fasterxml/jackson/failing/TestAnyGetter1655Filtering.java b/src/test/java/com/fasterxml/jackson/failing/TestAnyGetter1655Filtering.java
deleted file mode 100644
index c295322..0000000
--- a/src/test/java/com/fasterxml/jackson/failing/TestAnyGetter1655Filtering.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.fasterxml.jackson.failing;
-
-import java.util.*;
-
-import com.fasterxml.jackson.annotation.*;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.BaseMapTest;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.FilterProvider;
-import com.fasterxml.jackson.databind.ser.PropertyWriter;
-import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
-import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
-
-/**
- * Unit tests for ensuring that entries accessible via "any filter"
- * can also be filtered with JSON Filter functionality.
- */
-public class TestAnyGetter1655Filtering extends BaseMapTest
-{
- // [databind#1655]
- @JsonFilter("CustomFilter")
- static class OuterObject {
- public int getExplicitProperty() {
- return 42;
- }
-
- @JsonAnyGetter
- public Map<String, Object> getAny() {
- Map<String, Object> extra = new HashMap<>();
- extra.put("dynamicProperty", "I will not serialize");
- return extra;
- }
- }
-
- static class CustomFilter extends SimpleBeanPropertyFilter {
- @Override
- public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer) throws Exception {
- if (pojo instanceof OuterObject) {
- writer.serializeAsField(pojo, jgen, provider);
- }
- }
- }
-
- /*
- /**********************************************************
- /* Test methods
- /**********************************************************
- */
-
- private final ObjectMapper MAPPER = new ObjectMapper();
-
- // [databind#1655]
- public void testAnyGetterPojo1655() throws Exception
- {
- FilterProvider filters = new SimpleFilterProvider().addFilter("CustomFilter", new CustomFilter());
- String json = MAPPER.writer(filters).writeValueAsString(new OuterObject());
- Map<?,?> stuff = MAPPER.readValue(json, Map.class);
- if (stuff.size() != 2) {
- fail("Should have 2 properties, got: "+stuff);
- }
- }
-}