如何在使用Jackson序列化时仅包含特定属性

时间:2014-10-22 13:49:34

标签: json serialization filter jackson

我正在尝试实现一个通用方法,该方法将给定对象序列化为JSON,但仅限于在集合中传递的那些属性。如果可能的话,我希望在没有在类上指定@JsonFilter的情况下获得此功能。为此,我试图使用Jackson 2.4.1中的FilterExceptFilter。依赖关系:

这就是我现在所拥有的:

public static String serializeOnlyGivenFields(Object o,
                    Collection<String> fields) throws JsonProcessingException {
    if ((fields == null) || fields.isEmpty()) return null;

    Set<String> properties = new HashSet<String>(fields);

    SimpleBeanPropertyFilter filter =
        new SimpleBeanPropertyFilter.FilterExceptFilter(properties);
    SimpleFilterProvider fProvider = new SimpleFilterProvider();
    fProvider.addFilter("fieldFilter", filter);
    fProvider.setDefaultFilter(filter);

    ObjectMapper mapper = new ObjectMapper();
    mapper.setFilters(fProvider);

    String json = mapper.writeValueAsString(o);
    return json;
}

但是,永远不会应用过滤器。它总是序列化所有属性。

Set<String> fields = new HashSet<String>(); fields.add("name");
String json = Serializer.serializeOnlyGivenFields(e, fields);
System.out.println(json);
  

{&#34; name&#34;:&#34;测试实体&#34;,&#34;说明&#34;:&#34;测试说明&#34;}

我也尝试注册FilterProvider on the ObjectWriter,但结果相同:

String json = mapper.writer(fProvider).writeValueAsString(o);

我错过了什么?杰克逊有没有很好的方法来实现这一目标?

3 个答案:

答案 0 :(得分:4)

基于http://www.cowtowncoder.com/blog/archives/2011/09/entry_461.html设置过滤器的另一种方法是设置一个扩展JacksonAnnotationIntrospector并覆盖findFilterId的类。然后,您可以指定在findFilterId中查找过滤器。如果你想要基于其他一些地图或算法,这可以做得很健壮。以下是示例代码。不确定性能是否优于上述解决方案,但它似乎更简单,可能更容易扩展。我这样做是为了使用Jackson序列化CSV。欢迎任何反馈!

public class JSON {

private static String FILTER_NAME = "fieldFilter";

public static String serializeOnlyGivenFields(Object o,
                                              Collection<String> fields) throws JsonProcessingException {
    if ((fields == null) || fields.isEmpty()) fields = new HashSet<String>();

    Set<String> properties = new HashSet<String>(fields);

    SimpleBeanPropertyFilter filter =
            new SimpleBeanPropertyFilter.FilterExceptFilter(properties);
    SimpleFilterProvider fProvider = new SimpleFilterProvider();
    fProvider.addFilter(FILTER_NAME, filter);

    ObjectMapper mapper = new ObjectMapper();
    mapper.setAnnotationIntrospector( new AnnotationIntrospector() );

    String json = mapper.writer(fProvider).writeValueAsString(o);
    return json;
}

private static class AnnotationIntrospector extends JacksonAnnotationIntrospector {
    @Override
    public Object findFilterId(Annotated a) {
        return FILTER_NAME;
    }
}

}

答案 1 :(得分:0)

另外一件事是你必须指出@JsonFilter注释要使用哪个过滤器的Java类:

@JsonFilter("fieldFilter") public class MyType { }

然后它应该适用。

答案 2 :(得分:0)

我找到了一个基于Jackson: How to add custom property to the JSON without modifying the POJO的解决方案。我重写BeanSerializer#serializeFields以改为始终使用BeanSerializer#serializeFieldsFiltered。这样就可以始终应用过滤器。

性能方面不是一个很好的解决方案,因为必须在每次方法调用时构造ObjectMapper。随意发布改进或建议!

模块实施:

public class FilteredModule extends SimpleModule {
    private static final long serialVersionUID = 1L;

    @Override
    public void setupModule(SetupContext context) {
        super.setupModule(context);

        context.addBeanSerializerModifier(new BeanSerializerModifier() {

            @Override
            public JsonSerializer<?> modifySerializer(
                    SerializationConfig config,
                    BeanDescription beanDesc,
                    JsonSerializer<?> serializer) {
                if (serializer instanceof BeanSerializerBase) { 
                    return new FilteredBeanSerializer(
                            (BeanSerializerBase) serializer);
                } 
                return serializer; 

            }                   
        });
    }

    private class FilteredBeanSerializer extends BeanSerializer {

        public FilteredBeanSerializer(BeanSerializerBase source) {
            super(source);
        }

        @Override
        protected void serializeFields(Object arg0, JsonGenerator arg1,
                SerializerProvider arg2) throws IOException,
                JsonGenerationException {
            super.serializeFieldsFiltered(arg0, arg1, arg2);
        }

    }
}

API方法:

public static String serializeOnlyGivenFields(Object o,
            Collection<String> fields) throws JsonProcessingException {
    if ((fields == null) || fields.isEmpty()) fields = new HashSet<String>();

    Set<String> properties = new HashSet<String>(fields);

    SimpleBeanPropertyFilter filter =
            new SimpleBeanPropertyFilter.FilterExceptFilter(properties);
    SimpleFilterProvider fProvider = new SimpleFilterProvider();
    fProvider.addFilter("fieldFilter", filter);
    fProvider.setDefaultFilter(filter);

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new FilteredModule());

    String json = mapper.writer(fProvider).writeValueAsString(o);
    return json;
}

示例

Entity e = new Entity("Test entity", "Test description");   
Set<String> fields = new HashSet<String>(); fields.add("name");
String json = JSON.serializeOnlyGivenFields(e, fields);
System.out.println(json);
  

{“name”:“测试实体”}

基准: 同一对象的1000次迭代

serializeOnlyGivenFields:           536 ms
serialize (reuses ObjectMapper):    23 ms