Describe the bug
When a POJO has both @JsonFilter and a @JsonAnyGetter, exclude-style filters (SimpleBeanPropertyFilter.serializeAllExcept()) are not applied to the entries the any-getter produces: every entry is written out, including ones whose key the filter explicitly excludes. Since exclude filters are typically used to suppress sensitive properties, entries slip out that the filter was configured to hide.
The cause is that SimpleBeanPropertyFilter.serializeAsProperty() calls include(writer) on the AnyGetterWriter itself, so the name being checked is the any-getter accessor's implied name, not the names of the entries it emits. That name is not in the exclude set, so the writer goes straight to getAndSerialize(), which writes all entries unfiltered. Only include-style filters (filterOutAllExcept()) ever reach the per-entry getAndFilter() path, since that call sits in the else branch behind canOmitProperties().
There is a second variant: a JsonNode/ObjectNode-valued any-getter (supported since [databind#3604]) leaks under both filter styles, because AnyGetterWriter.getAndFilter() short-circuits JsonNode values to plain unfiltered entry serialization, so no filter is consulted at all.
2.18 and earlier are not affected: there the any-getter writer was kept out of the property array and BeanSerializerBase.serializeFieldsFiltered() called getAndFilter() unconditionally. Folding the any-getter into the property array as a BeanPropertyWriter put it behind the writer-level include() check.
Version Information
Reproduced on 3.3.0-SNAPSHOT (3.x head); same code is on 3.1/3.2. 2.18 is not affected.
Reproduction
@JsonFilter("anyFilter")
static class AnyBeanWithSecret {
public String name = "bob";
private Map<String, String> properties = new LinkedHashMap<>();
{
properties.put("a", "1");
properties.put("secret", "s3cr3t");
}
@JsonAnyGetter
public Map<String, String> anyProperties() {
return properties;
}
}
FilterProvider prov = new SimpleFilterProvider().addFilter("anyFilter",
SimpleBeanPropertyFilter.serializeAllExcept("secret"));
String json = MAPPER.writer(prov).writeValueAsString(new AnyBeanWithSecret());
// expected: {"name":"bob","a":"1"}
// actual: {"name":"bob","a":"1","secret":"s3cr3t"}
The ObjectNode variant leaks the same way, and also with filterOutAllExcept("name", "a"):
@JsonFilter("anyFilter")
static class ObjectNodeAnyBeanWithSecret {
public String name = "bob";
@JsonAnyGetter
public ObjectNode anyProperties() {
return JsonNodeFactory.instance.objectNode()
.put("a", "1")
.put("secret", "s3cr3t");
}
}
Expected behavior
The filter should decide inclusion per emitted entry name, the way filterOutAllExcept() already does for Map-valued any-getters, so that serializeAllExcept("secret") suppresses the secret entry regardless of filter style or any-getter value type.
Describe the bug
When a POJO has both
@JsonFilterand a@JsonAnyGetter, exclude-style filters (SimpleBeanPropertyFilter.serializeAllExcept()) are not applied to the entries the any-getter produces: every entry is written out, including ones whose key the filter explicitly excludes. Since exclude filters are typically used to suppress sensitive properties, entries slip out that the filter was configured to hide.The cause is that
SimpleBeanPropertyFilter.serializeAsProperty()callsinclude(writer)on theAnyGetterWriteritself, so the name being checked is the any-getter accessor's implied name, not the names of the entries it emits. That name is not in the exclude set, so the writer goes straight togetAndSerialize(), which writes all entries unfiltered. Only include-style filters (filterOutAllExcept()) ever reach the per-entrygetAndFilter()path, since that call sits in theelsebranch behindcanOmitProperties().There is a second variant: a
JsonNode/ObjectNode-valued any-getter (supported since [databind#3604]) leaks under both filter styles, becauseAnyGetterWriter.getAndFilter()short-circuitsJsonNodevalues to plain unfiltered entry serialization, so no filter is consulted at all.2.18 and earlier are not affected: there the any-getter writer was kept out of the property array and
BeanSerializerBase.serializeFieldsFiltered()calledgetAndFilter()unconditionally. Folding the any-getter into the property array as aBeanPropertyWriterput it behind the writer-levelinclude()check.Version Information
Reproduced on 3.3.0-SNAPSHOT (
3.xhead); same code is on 3.1/3.2. 2.18 is not affected.Reproduction
The
ObjectNodevariant leaks the same way, and also withfilterOutAllExcept("name", "a"):Expected behavior
The filter should decide inclusion per emitted entry name, the way
filterOutAllExcept()already does forMap-valued any-getters, so thatserializeAllExcept("secret")suppresses thesecretentry regardless of filter style or any-getter value type.