Feature: JSON Filter

(see Jira entry JACKSON-312 for details)

In addition to existing serialization-side filtering functionality (like JacksonFeatureJsonViews), Jackson 1.7 adds a new flexible, powerful and efficient mechanism for doing dynamic filtering on per-call basis.

The basic idea is that it is possible to annotate classes with type filter ids using @JsonFilter annotation, and then define mapping from ids to filter instances; mappings can be defined on per-call basis using ObjectWriter.withFilters() method.

Usage

Let's consider a simple bean to filter:

@JsonFilter("myFilter")
static class Bean {
    public String name;
    public int age;
}

if we wanted to, say, filter out all properties except for 'name', we could just use org.codehaus.jackson.map.ser.impl.SimpleFilterProvider and org.codehaus.jackson.map.ser.impl.SimpleBeanPropertyFilter like so:

Bean value = ...
ObjectMapper mapper = new ObjectMapper();
// first, construct filter provider to exclude all properties but 'name', bind it as 'myFilter'
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter",
    SimpleBeanPropertyFilter.filterOutAllExcept("name"));
// and then serialize using that filter provider:
String json = mapper.filteredWriter(filters).writeValueAsString(value);

Note that filters can be shared between multiple classes; all classes that declare same filter id will use the same filter. This can be useful when removing specific properties from large set of types -- if so, @JsonFilter annotation can be defined once in a super-class and will apply to all sub-types.

It is also possible to implement complicated filtering logic, because BeanPropertyFilter interface is defined as:

public interface BeanPropertyFilter
{
    public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov, BeanPropertyWriter writer)
        throws Exception;
}

and allows replacing default serialization behavior with pretty much any code (not just block or pass), and gives enough contextual information for supporting about any kind of custom filtering or value transformations.

Advanced Customization

Since resolution of filter to use is a two-step process, we can not only customize what filter is used for given id, but we can also override mechanism used to locate actual filter id.

The default mechanism uses AnnotationIntrospector's findFilterId() method; which JacksonAnnotationIntrospector (default one used by Jackson if not overriden) implements as simple lookup for @JsonFilter annotation.

But we can very easily redefine this method, either by sub-classing JacksonAnnotationIntrospector, or combining it using AnnotationIntrospector.Pair. For example, we could have:

    public class CustomIntrospector extends JacksonAnnotationIntrospector
    {
      @Override
      public Object findFilterId(AnnotatedClass ac) {
        // Let's default to current behavior if annotation is found:
        Object id = super.findFilterId(ac);
        // but use simple class name if not
        if (id == null) {
           id = ac.getName();
        }
        return id;
    }

What is the benefit here? The usual reason is that this way one can associate filter ids with classes without modifying them (another option for this being using JacksonMixInAnnotations); but it could also just be used to reduce number of annotations one uses, or to add filtering for dynamic set of classes which are not even known at compile-time.

Second part that is needed, then, is mapping of id to actual filter. This can be done by sub-classing SimpleBeanPropertyFilter, for example.

External

Following links might help:


CategoryJackson

JacksonFeatureJsonFilter (last edited 2011-09-29 02:49:53 by TatuSaloranta)

Copyright ©2009 FasterXML, LLC