杰克逊 - 有没有办法避免在运行时序列化父实体



假设我有两个简单的类

@JsonFilter("filter properties by name")
public class Foo
{
    private Integer id;
    private String name;
}
@JsonFilter("filter properties by name")
public class Bar
{
    private Integer id;
    private String name;
    private Foo foo;
}

我想序列化一个Bar实例,其中foo字段只有其 id。这一切都应该在运行时完成。我尝试使用过滤器执行此操作

FilterProvider filter = new SimpleFilterProvider().addFilter(
            "filter properties by name", SimpleBeanPropertyFilter
                .serializeAllExcept(/*name of the field to exclude*/));
objectMapper.writer(filter).writeValuAsString(bar);

但是,在这样做时,我必须手动排除父类的所有字段;此外,如果此字段之一与子类的字段同名,则它们都将被排除。在我的示例中,我不能以这种方式排除字段name,因为它也会影响Bar类的字段name

那么,我怎样才能以最简洁/优雅的方式解决呢?是否有类似于上述代码的东西,也许使用点符号或类似的东西?

例如,直到现在在我的示例过滤器中,我能够编写类似 [...].serializeAllExcept("name", "foo")); 的东西,但拥有 [...].serializeAllExcept("foo.name")); 或类似

的东西很棒。

你不需要任何过滤器。Foo和Bar类没有变化。

新的 MixInFoo 类:

public class MixInFoo {
    @JsonProperty("mixinFooId")
    private Integer id;
    @JsonIgnore
    private String name;
}

我更改了"id"属性名称只是为了说明您可以在不修改原始 Foo 类的情况下完全更改响应。

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getSerializationConfig().addMixInAnnotations(Foo.class, MixInFoo.class);
objectMapper.getDeserializationConfig().addMixInAnnotations(Foo.class, MixInFoo.class);
String result = objectMapper.writeValueAsString(json);

您需要注册 MixIn 类,如图所示。

******* 基于过滤器的实现 ***********

是的,您可以使用过滤器来获得相同的结果。您需要将@JsonFilter添加到Foo类中,并将其命名为"FooFilter"。然后,您可以添加仅适用于 Foo 类的过滤器:

@JsonFilter("FooFilter")
public class Foo {
    private Integer id;
    private String name;
}
public class Bar {
    private Integer id;
    private String name;
    private Foo foo;
}
public static void main(String []args) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    String []fooIgnore = {"name"};
    SimpleBeanPropertyFilter propertyFilter = SimpleBeanPropertyFilter.serializeAllExcept(fooIgnore);
    FilterProvider filterProvider = new SimpleFilterProvider().addFilter("FooFilter", propertyFilter);
    ObjectWriter objectWriter = objectMapper.writer(filterProvider);
    String result = objectWriter.writeValueAsString(json);
    System.out.println(result);
}

在该实现中,您无需扩展和实现自定义 SimpleBeanProvider 即可仅将筛选器应用于 Foo 类。

可以使用过滤器。您可以编写一个自定义属性筛选器,该筛选器将考虑序列化属性的声明类。

您应该扩展 SimpleBeanPropertyFilter 并重写 include(PropertyWriter writer) 方法。如果给定的编写器参数是 BeanPropertyWriter 类的实例,则可以提取有关属性源的信息并应用自定义的筛选逻辑。

下面是一个示例:

public class JacksonParentFilter {
    @JsonFilter("filter")
    public static class A {
        public final String field1;
        public A(final String field1) {this.field1 = field1;}
    }
    @JsonFilter("filter")
    public static class B {
        public final String field1;
        public final String field2;
        public B(final String field1, final String field2) {
            this.field1 = field1;
            this.field2 = field2;
        }
    }
    public static class MyFilter extends SimpleBeanPropertyFilter {
        private final Class<?> excludeClass;
        private final Set<String> excludeProperties;
        public MyFilter(final Class<?> excludeClass, final Set<String> excludeProperties) {
            this.excludeClass = excludeClass;
            this.excludeProperties = excludeProperties;
        }
        @Override
        protected boolean include(final BeanPropertyWriter writer) {
            return false;
        }
        @Override
        protected boolean include(final PropertyWriter writer) {
            if (writer instanceof BeanPropertyWriter) {
                final Class<?> cls = ((BeanPropertyWriter) writer).getMember().getDeclaringClass();
                if (cls == excludeClass) {
                    return !excludeProperties.contains(writer.getName());
                }
            }
            return true;
        }
    }
    public static void main(String[] args) throws JsonProcessingException {
        final A a = new A("A");
        final B b = new B("B1", "B2");
        final ObjectMapper mapper = new ObjectMapper();
        final SimpleFilterProvider filters = new SimpleFilterProvider();
        filters.addFilter("filter", new MyFilter(B.class, Collections.singleton("field1")));
        mapper.setFilters(filters);
        final ObjectWriter objectWriter = mapper.writerWithDefaultPrettyPrinter();
        System.out.println(objectWriter.writeValueAsString(Arrays.asList(a, b)));
    }
}

输出:

[ {
  "field1" : "A"
}, {
  "field2" : "B2"
} ]

最新更新