A Jackson Filter matching the path of the current value to serialize against the AntPathMatcher. The inclusion / exclusion works similar to the ant
file include / exclude
functionality. Ant / Maven users should mostly be aware of how this works.
- Java 5
- Jackson 2.5.0+ (2.5.0.RELEASE and its dependencies included)
Add a dependency to your project with the following co-ordinates:
- GroupId:
ch.mfrey.jackson
- ArtifactId:
jackson-antpathfilter
- Version:
${jackson-antpathfilter.version}
<dependency>
<groupId>ch.mfrey.jackson</groupId>
<artifactId>jackson-antpathfilter</artifactId>
<version>${jackson-antpathfilter.version}</version>
</dependency>
String[] filter = new String[] {"*", "*.*", "-not.that.path"};
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.addMixIn(Object.class, AntPathFilterMixin.class);
FilterProvider filterProvider = new SimpleFilterProvider().addFilter("antPathFilter", new AntPathPropertyFilter(filter));
objectMapper.setFilters(filterProvider);
objectMapper.writeValueAsString(someObject);
= Inclusion:
"*", "**", "*.*", "someproperty.someNesterProperty.*",
= Exclusion:
"-property", "-**.someExpensiveMethod";
= Before Spring 4.2.2
For those using this together with Spring it is easy to use the Jackson2Helper class as a Component to configure the objectMapper only once and avoid boilerplate code in each Controller
.
<!-- Needed so that Controllers can return a JSON ResponseBody directly as a String result (produced by Jackson2Helper) -->
<bean class = "org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<array>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="application/json; charset=UTF-8" />
</bean>
</array>
</property>
</bean>
@Configuration
public class Jackson2HelperConfig {
@Bean
public Jackson2Helper jackson2Helper() {
return new Jackson2Helper();
}
}
@Controller
@RequestMapping(value = "/someObject")
public class SomeController {
@Autowired
private Jackson2Helper jackson2Helper;
@RequestMapping
@ResponseBody
public String getSomeObject() {
return jackson2Helper.writeFiltered(someObject, "*", "*.*", "-not.that.path");
}
}
= With Spring 4.2.2+
With the latest addon in Spring 4.2.2, the class MappingJacksonValue
contains now a function setFilters
, it is now possible to integrate this filter in a cleaner way. No specific StringConverter is needed anymore, but we need some more classes for now:
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
@Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> messageConverters) {
// Add a MappingJackson2HttpMessageConverter so that
// objectMapper.writeFiltered
// is using the objectMapper configured with the needed Mixin
ObjectMapper objectMapper = Jackson2ObjectMapperBuilder
.json()
.mixIn(Object.class, AntPathFilterMixin.class)
.build();
messageConverters.add(new MappingJackson2HttpMessageConverter(objectMapper));
addDefaultHttpMessageConverters(messageConverters);
}
}
/**
* Just a helper class to simplify usage
*/
public class AntPathFilterMappingJacksonValue extends MappingJacksonValue {
public AntPathFilterMappingJacksonValue(final Object value) {
super(value);
setFilters(new SimpleFilterProvider().addFilter("antPathFilter", new AntPathPropertyFilter("**")));
}
public AntPathFilterMappingJacksonValue(final Object value, final String... filters) {
super(value);
setFilters(new SimpleFilterProvider().addFilter("antPathFilter", new AntPathPropertyFilter(filters)));
}
}
@Controller
@RequestMapping(value = "/someObject")
public class SomeController {
@RequestMapping
@ResponseBody
public MappingJacksonValue getSomeObject() {
return new AntPathFilterMappingJacksonValue(someObject, "*", "*.*", "-not.that.path");
}
}
Data
{
"address": {
"streetName":"At my place",
"streetNumber":"1"
},
"email":"[email protected]",
"firstName":"Martin",
"lastName":"Frey",
"manager":{
"address":null,
"email":"[email protected]",
"firstName":"John",
"lastName":"Doe",
"manager":null
}
}
Filter: **,
Result: {"address":{"streetName":"At my place","streetNumber":"1"},"email":"[email protected]","firstName":"Martin","lastName":"Frey","manager":{"address":null,"email":"[email protected]","firstName":"John","lastName":"Doe","manager":null}}
Filter: firstName,
Result: {"firstName":"Martin"}
Filter: **,-manager,
Result: {"address":{"streetName":"At my place","streetNumber":"1"},"email":"[email protected]","firstName":"Martin","lastName":"Frey"}
Filter: manager,manager.firstName,manager.lastName,
Result: {"manager":{"firstName":"John","lastName":"Doe"}}
Filter: *,address.*,manager.firstName,
Result: {"address":{"streetName":"At my place","streetNumber":"1"},"email":"[email protected]","firstName":"Martin","lastName":"Frey","manager":{"firstName":"John"}}
Filter: **,-manager,-**.streetNumber,
Result: {"address":{"streetName":"At my place"},"email":"[email protected]","firstName":"Martin","lastName":"Frey"}