JsonFilterTest.java
package com.fasterxml.jackson.databind.ser.filter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.*;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.*;
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests for verifying that bean property filtering using JsonFilter
* works as expected.
*/
public class JsonFilterTest extends DatabindTestUtil
{
@JsonFilter("RootFilter")
@JsonPropertyOrder({ "a", "b" })
static class Bean {
public String a = "a";
public String b = "b";
}
@JsonFilter("checkSiblingContextFilter")
static class CheckSiblingContextBean {
public A a = new A();
public B b = new B();
@JsonFilter("checkSiblingContextFilter")
static class A {
}
@JsonFilter("checkSiblingContextFilter")
static class B {
public C c = new C();
@JsonFilter("checkSiblingContextFilter")
static class C {
}
}
}
@JsonFilter("filterB")
@JsonPropertyOrder({ "a", "b", "c"})
static class BeanB {
public String a;
public String b;
public String c;
public BeanB(String a, String b, String c) {
this.a = a;
this.b = b;
this.c = c;
}
}
static class CheckSiblingContextFilter extends SimpleBeanPropertyFilter {
@Override
public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer) throws Exception {
JsonStreamContext sc = jgen.getOutputContext();
if (writer.getName() != null && writer.getName().equals("c")) {
//This assertion is failing as sc.getParent() incorrectly returns 'a'. If you comment out the member 'a'
// in the CheckSiblingContextBean, you'll see that the sc.getParent() correctly returns 'b'
assertEquals("b", sc.getParent().getCurrentName());
}
writer.serializeAsField(bean, jgen, prov);
}
}
@Test
public void testCheckSiblingContextFilter() {
FilterProvider prov = new SimpleFilterProvider().addFilter("checkSiblingContextFilter",
new CheckSiblingContextFilter());
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(prov);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
mapper.valueToTree(new CheckSiblingContextBean());
}
// [Issue#89]
static class Pod
{
protected String username;
// @JsonProperty(value = "user_password")
protected String userPassword;
public String getUsername() {
return username;
}
public void setUsername(String value) {
this.username = value;
}
@JsonIgnore
@JsonProperty(value = "user_password")
public java.lang.String getUserPassword() {
return userPassword;
}
@JsonProperty(value = "user_password")
public void setUserPassword(String value) {
this.userPassword = value;
}
}
// [Issue#306]: JsonFilter for properties, too!
@JsonPropertyOrder(alphabetic=true)
static class FilteredProps
{
// will default to using "RootFilter", only including 'a'
public Bean first = new Bean();
// but minimal includes 'b'
@JsonFilter("b")
public Bean second = new Bean();
}
/*
/**********************************************************
/* Unit tests
/**********************************************************
*/
private final ObjectMapper MAPPER = newJsonMapper();
@Test
public void testSimpleInclusionFilter() throws Exception
{
FilterProvider prov = new SimpleFilterProvider().addFilter("RootFilter",
SimpleBeanPropertyFilter.filterOutAllExcept("a"));
assertEquals("{\"a\":\"a\"}", MAPPER.writer(prov).writeValueAsString(new Bean()));
// [JACKSON-504]: also verify it works via mapper
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(prov);
assertEquals("{\"a\":\"a\"}", mapper.writeValueAsString(new Bean()));
}
@Test
public void testIncludeAllFilter() throws Exception
{
FilterProvider prov = new SimpleFilterProvider().addFilter("RootFilter",
SimpleBeanPropertyFilter.serializeAll());
assertEquals("{\"a\":\"a\",\"b\":\"b\"}", MAPPER.writer(prov).writeValueAsString(new Bean()));
}
@Test
public void testExcludeAllFilter() throws Exception
{
FilterProvider prov = new SimpleFilterProvider().addFilter("RootFilter",
SimpleBeanPropertyFilter.filterOutAll());
assertEquals("{}", MAPPER.writer(prov).writeValueAsString(new Bean()));
}
@Test
public void testSimpleExclusionFilter() throws Exception
{
FilterProvider prov = new SimpleFilterProvider().addFilter("RootFilter",
SimpleBeanPropertyFilter.serializeAllExcept("a"));
assertEquals("{\"b\":\"b\"}", MAPPER.writer(prov).writeValueAsString(new Bean()));
}
// should handle missing case gracefully
@Test
public void testMissingFilter() throws Exception
{
// First: default behavior should be to throw an exception
try {
MAPPER.writeValueAsString(new Bean());
fail("Should have failed without configured filter");
} catch (InvalidDefinitionException e) { // should be resolved to this (internally may be something else)
verifyException(e, "Cannot resolve PropertyFilter with id 'RootFilter'");
}
// but when changing behavior, should work difference
SimpleFilterProvider fp = new SimpleFilterProvider().setFailOnUnknownId(false);
ObjectMapper mapper = new ObjectMapper();
mapper.setFilterProvider(fp);
String json = mapper.writeValueAsString(new Bean());
assertEquals("{\"a\":\"a\",\"b\":\"b\"}", json);
}
// defaulting, as per [JACKSON-449]
@Test
public void testDefaultFilter() throws Exception
{
FilterProvider prov = new SimpleFilterProvider().setDefaultFilter(SimpleBeanPropertyFilter.filterOutAllExcept("b"));
assertEquals("{\"b\":\"b\"}", MAPPER.writer(prov).writeValueAsString(new Bean()));
}
// [databind#89] combining @JsonIgnore, @JsonProperty
@Test
public void testIssue89() throws Exception
{
Pod pod = new Pod();
pod.username = "Bob";
pod.userPassword = "s3cr3t!";
String json = MAPPER.writeValueAsString(pod);
assertEquals("{\"username\":\"Bob\"}", json);
Pod pod2 = MAPPER.readValue("{\"username\":\"Bill\",\"user_password\":\"foo!\"}", Pod.class);
assertEquals("Bill", pod2.username);
assertEquals("foo!", pod2.userPassword);
}
// Wrt [databind#306]
@Test
public void testFilterOnProperty() throws Exception
{
FilterProvider prov = new SimpleFilterProvider()
.addFilter("RootFilter", SimpleBeanPropertyFilter.filterOutAllExcept("a"))
.addFilter("b", SimpleBeanPropertyFilter.filterOutAllExcept("b"));
assertEquals("{\"first\":{\"a\":\"a\"},\"second\":{\"b\":\"b\"}}",
MAPPER.writer(prov).writeValueAsString(new FilteredProps()));
}
@Test
public void testAllFiltersWithSameOutput() throws Exception
{
// Setup
SimpleBeanPropertyFilter[] allPossibleFilters = new SimpleBeanPropertyFilter[]{
// Parent class : SimpleBeanPropertyFilter
SimpleBeanPropertyFilter.filterOutAllExcept("a", "b"),
SimpleBeanPropertyFilter.filterOutAllExcept(setOf("a", "b")),
SimpleBeanPropertyFilter.serializeAllExcept("c"),
SimpleBeanPropertyFilter.serializeAllExcept(setOf("c")),
// Subclass : SerializeExceptFilter
new SimpleBeanPropertyFilter.SerializeExceptFilter(setOf("c")),
SimpleBeanPropertyFilter.SerializeExceptFilter.serializeAllExcept("c"),
SimpleBeanPropertyFilter.SerializeExceptFilter.serializeAllExcept(setOf("c")),
SimpleBeanPropertyFilter.SerializeExceptFilter.filterOutAllExcept("a", "b"),
SimpleBeanPropertyFilter.SerializeExceptFilter.filterOutAllExcept(setOf("a", "b")),
// Subclass : FilterExceptFilter
new SimpleBeanPropertyFilter.FilterExceptFilter(setOf("a", "b")),
SimpleBeanPropertyFilter.FilterExceptFilter.serializeAllExcept("c"),
SimpleBeanPropertyFilter.FilterExceptFilter.serializeAllExcept(setOf("c")),
SimpleBeanPropertyFilter.FilterExceptFilter.filterOutAllExcept(setOf("a", "b")),
SimpleBeanPropertyFilter.FilterExceptFilter.filterOutAllExcept("a", "b")
};
// Tests
for (SimpleBeanPropertyFilter filter : allPossibleFilters) {
BeanB beanB = new BeanB("aa", "bb", "cc");
SimpleFilterProvider prov = new SimpleFilterProvider().addFilter("filterB", filter);
String jsonStr = MAPPER.writer(prov).writeValueAsString(beanB);
assertEquals(a2q("{'a':'aa','b':'bb'}"), jsonStr);
}
}
private Set<String> setOf(String... properties) {
Set<String> set = new HashSet<>(properties.length);
set.addAll(Arrays.asList(properties));
return set;
}
}