使用 Jackson 序列化时有条件地跳过对象

fal*_*con 4 java serialization json jackson

我有一个像这样的课程

interface IHideable {
   boolean isHidden();
}

class Address implements IHideable {
    private String city;
    private String street;
    private boolean hidden;
}

class PersonalInfo implements IHideable {
    private String name;
    private int age;
    private boolean hidden;
}
Run Code Online (Sandbox Code Playgroud)

我想在我的网络服务中序列化 IHideable 列表;但过滤掉隐藏字段设置为 true 的任何对象。

基本上给出了一个对象列表,例如

[
{'city 1','street 1',false},
{'city 2','street 2',true},
{'city 3','street 3',false}
]
Run Code Online (Sandbox Code Playgroud)

我想要的输出为

[
  {
    city:'city 1',
    street:'street 1'
  },
  {
    city:'city 3',
    street:'street 3'
  }
]
Run Code Online (Sandbox Code Playgroud)

我尝试了以下实现

class ItemSerializer extends JsonSerializer<IHideable> {  
    @Override
    public void serialize(IHideable value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {

        if (!value.isHidden()) {
            jgen.writeStartObject();
            jgen.writeString("city", value.city);
            jgen.writeString("street", value.street);
            jgen.writeEndObject();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但编写的 writeString 方法是特定于 Address 类的。当我在那里使用 writeObject 时,它会抛出 stackoverflow 异常。我可以使用一些通用的 writeObject 方法来编写任何实现 IHideable() 的对象吗?这可以通过杰克逊默认/自定义序列化实现吗?

Ale*_*lov 5

您可以使用BeanSerializerModifier注册IHideable类型的序列化器并获取对默认 bean 序列化器的引用,正如问题中讨论的那样。

在序列化器中,检查该isHidden标志,如果未设置,则使用默认序列化器序列化实例。这个技巧应该适用于任何实现你的IHideable接口的类型。这是一个例子:

public class JacksonHide {
    @JsonIgnoreProperties("hidden")
    public static interface IHideable {
        boolean isHidden();
    }

    public static class Address implements IHideable {
        public final String city;
        public final String street;
        public final boolean hidden;

        public Address(String city, String street, boolean hidden) {
            this.city = city;
            this.street = street;
            this.hidden = hidden;
        }

        @Override
        public boolean isHidden() {
            return hidden;
        }
    }

    public static class PersonalInfo implements IHideable {
        public final String name;
        public final int age;
        public final boolean hidden;

        public PersonalInfo(String name, int age, boolean hidden) {
            this.name = name;
            this.age = age;
            this.hidden = hidden;
        }

        @Override
        public boolean isHidden() {
            return hidden;
        }
    }

    private static class MyBeanSerializerModifier extends BeanSerializerModifier {
        @Override
        public JsonSerializer<?> modifySerializer(SerializationConfig config,
                                                  BeanDescription beanDesc,
                                                  JsonSerializer<?> serializer) {
            if (IHideable.class.isAssignableFrom(beanDesc.getBeanClass())) {
                return new MyIHideableJsonSerializer((JsonSerializer<IHideable>) serializer);
            }
            return super.modifySerializer(config, beanDesc, serializer);
        }

        private static class MyIHideableJsonSerializer extends JsonSerializer<IHideable> {
            private final JsonSerializer<IHideable> serializer;

            public MyIHideableJsonSerializer(JsonSerializer<IHideable> serializer) {
                this.serializer = serializer;
            }

            @Override
            public void serialize(IHideable value,
                                  JsonGenerator jgen,
                                  SerializerProvider provider) throws IOException {
                if (!value.isHidden()) {
                     serializer.serialize(value, jgen, provider);
                }

            }
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.setSerializerModifier(new MyBeanSerializerModifier());
        mapper.registerModule(module);

        PersonalInfo p1 = new PersonalInfo("John", 30, false);
        PersonalInfo p2 = new PersonalInfo("Ivan", 20, true);
        Address a1 = new Address("A", "B", false);
        Address a2 = new Address("C", "D", true);

        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString
                (Arrays.asList(p1, p2, a1, a2)));
    }

}
Run Code Online (Sandbox Code Playgroud)

输出:

[ {
  "name" : "John",
  "age" : 30
}, {
  "city" : "A",
  "street" : "B"
} ]
Run Code Online (Sandbox Code Playgroud)