【问题标题】:Serialise selective class variables in Java在 Java 中序列化选择性类变量
【发布时间】:2020-04-13 12:46:14
【问题描述】:

我需要根据条件序列化一些字段。

例如,我有以下课程。

public class ClassExample
{
  private String id;
  private String type;
  private String string_1;
  private String string_2;
}

因此,假设 type 可以接收两个值,'type_1' 或 'type_2' 并且 string_1 和 string_2 将始终为 null(它们将被另一个应用程序更改)。

我想用 Jackson 序列化它,我想:

1) 如果是type_1,则string_1会出现在JSON中,而string_2不会出现。

2) 如果是type_2,则string_2 会出现在JSON 中,而string_1 不会出现。

有没有办法做到这一点?

提前致谢

【问题讨论】:

  • 您需要一个自定义序列化程序,但数据结构本身听起来有点混乱,尽管我没有太多关于您的应用程序的上下文
  • 我简化了很多,因为我无法提供有关该应用程序的太多信息,对此非常抱歉。那么,唯一的方法是使用自定义序列化程序?
  • 是的,这不是标准行为,因此您不会开箱即用。

标签: java serialization jackson


【解决方案1】:

一个字段依赖于另一个字段的可空性可能表明您应该将您的类分成 2 个。您可以将这个类替换为 2 个类,而不是一个具有 2 个可能值的类,而其中没有任何类型字段。 因此不需要自定义序列化程序。

【讨论】:

    【解决方案2】:

    据我了解,您希望序列化符合条件的类字段。 有多种方法可以解决这个问题,因为您想要不使用自定义序列化程序的解决方案,这里有一个解决方案:-

    该方案基于Jackson的FilterProvider。

    建议:-

    1. 使用自定义序列化器,如果您有非常严格的限制,请使用提到的解决方案
    2. 请将类型设为 Enum,并根据类型操作相应地进行不同的实现。

    如果您能详细说明您的用例,我可以推荐一个更好的解决方案。

    解决方案:-

    import com.fasterxml.jackson.annotation.JsonFilter;
    import com.fasterxml.jackson.core.JsonGenerator;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.SerializerProvider;
    import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
    import com.fasterxml.jackson.databind.ser.FilterProvider;
    import com.fasterxml.jackson.databind.ser.PropertyFilter;
    import com.fasterxml.jackson.databind.ser.PropertyWriter;
    import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
    import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
    import lombok.AllArgsConstructor;
    import lombok.Getter;
    import lombok.Setter;
    import lombok.extern.slf4j.Slf4j;
    
    @Getter
    @Setter
    @Slf4j
    @AllArgsConstructor
    @JsonFilter("myFilter")
    public class ClassExample {
        private String id;
        private String type;
        private String string_1;
        private String string_2;
        private static final ObjectMapper om = new ObjectMapper();
        private static final PropertyFilter theFilter = new SimpleBeanPropertyFilter() {
            @Override
            public void serializeAsField(Object pojo, JsonGenerator jgen,
                                         SerializerProvider provider, PropertyWriter writer)
                    throws Exception {
                if (include(writer)) {
                    if (!(writer.getName().equals("string_1") || writer.getName().equals("string_2"))) {
                        writer.serializeAsField(pojo, jgen, provider);
                        return;
                    }
    
                    String type = ((ClassExample) pojo).getType();
                    if ("type_1".equals(type) && (writer.getName().equals("string_1"))) {
                        writer.serializeAsField(pojo, jgen, provider);
                    } else if ("type_2".equals(type) && (writer.getName().equals("string_2"))) {
                        writer.serializeAsField(pojo, jgen, provider);
                    }
    
                } else if (!jgen.canOmitFields()) { // since 2.3
                    writer.serializeAsOmittedField(pojo, jgen, provider);
                }
            }
    
            @Override
            protected boolean include(BeanPropertyWriter writer) {
                return true;
            }
    
            @Override
            protected boolean include(PropertyWriter writer) {
                return true;
            }
        };
    
        public String toString() {
            try {
    
                FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", theFilter);
                return om.writer(filters).writeValueAsString(this);
            } catch (Exception e) {
                log.error("error while serialisation", e);
                return "";
            }
        }
    
        public static void main(String[] args) {
            System.out.println(new ClassExample("123", "type_1", "1", "2"));
        }
    }
    

    输出:

    If type is type_1 then {"id":"123","type":"type_1","string_1":"1"}
    If type if type_2 then {"id":"123","type":"type_2","string_2":"2"}
    
    

    【讨论】:

    • 我同意你@CodeScale 的观点,有很多更好的方法可以解决这个问题,但从问题和 cmets 来看,我认为由于某些限制,他想要这种解决方案。
    猜你喜欢
    • 2014-12-20
    • 2015-11-19
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2017-12-02
    • 1970-01-01
    • 2015-01-13
    • 1970-01-01
    相关资源
    最近更新 更多