【问题标题】:Jackson unwrapping of null value objects杰克逊解开空值对象
【发布时间】:2018-06-21 02:40:36
【问题描述】:

假设我有 Description 值对象:

@JsonInclude(value = JsonInclude.Include.ALWAYS)
public class Description {
    @Column(name = "DESCRIPTION")
    private final String description;
}

和Product实体:

@Entity
public class Product extends AbstractEntity<Long> {

    @JsonUnwrapped
    private final Description description;   
}

我为Description 创建了自定义序列化程序:

static class DescriptionSerializer extends StdSerializer<Description> {
    DescriptionSerializer() {
        super(Description.class);
    }

    @Override
    public void serialize(Description value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
        if (value != null) {
            jgen.writeString(value.getDescription());
        } else {
            jgen.writeNull();
        }
    }
}

当我创建时:

Product product = new Product(new Description("description"));

并将其序列化:

String result = mapper.writeValueAsString(spec);

它返回 JSON:{"description":"description"}

当我创建时:

Product product = new Product(null);

它返回{},

但我希望{"description":null}

如果我删除@JsonUnwrapped,它会按我的预期工作,但对于非空Description,它会创建嵌套对象

有没有办法以与内置 Java 类型类似的方式对具有空值对象的字段进行解包?

【问题讨论】:

    标签: java json jackson spring-data-rest


    【解决方案1】:

    想要得到你应该尝试的东西:

    Product p = new Product(new Description(null));
    

    在json中

    {"description":"description"}
    

    Description,作为其他字段的容器存在,空值是Description对象内部description字段的值。

    这两种序列化的含义不同。

    要在您的代码中轻松管理它,您可以使用如下类:

    public class Product {
        private Description description;
    
        public Product(Description d) {
            this.description = d;
        }
    
        public Product() {
            this(new Description()); //all fields are null
        }
    
        public Product(String description) {
             return new Product(new Description(description));
        }
    }
    

    我更喜欢最后两个构造函数作为工厂方法,但这只是代码风格的问题。

    【讨论】:

    • 我的问题是 JPA/Hibernate/Spring Data 将描述值对象填充为空,而不是描述(空)。即使我尝试使用 JPA 属性转换器
    • 我明白了,这里的问题是,当您尝试将同一个对象用于多个表示时,事情会变得一团糟。我认为您正在使用 Product 类作为数据模型来存储在您的数据库中,并作为休息 api 的响应。在这种情况下,我将返回存储时的数据结构,或者具有不同的对象用于存储和 api 响应,具体取决于服务的使用方式。不同的对象可能会闻到代码重复的味道,但有了重复,就可以更容易地以不同的方式进化它们。
    • 是的..就是这样..但是使用相同的域模型进行持久性和杰克逊(反)序列化是我使用的 Spring Data REST 项目中的关键设计考虑因素之一。看来这是我必须务实并相应地调整前端客户端的事情。同时,我发布了问题jira.spring.io/browse/DATAREST-1175和github.com/FasterXML/jackson-databind/issues/1887
    • 是的,如果您使用相同的表示来存储和从其余 api 读取数据,那么 Spring Data REST 可以帮助您,那么为什么您希望它们不同(从 json 中隐藏 Description 对象)?根据您的模型有多少不同,管理与 jackson/jpa/hibernate/spring 注释的不同可视化可能会很痛苦。我发现拥有更多代码更好,但更容易更改。据我了解,如果您管理调用其余 api 的代码,那么在 json 中也有 Description 对象会更简单。
    • 问题是我不想隐藏Description 对象。我想要实现的是当 Description 对象被填充时,然后打开它。如果它为空,则将 "description": null 放在 JSON 结果中,而不是什么都不放。最初我没有使用值对象,我只是在Product 实体中使用了字符串描述,而字符串类型的描述被呈现为"description": null。目标是保持与 react 前端客户端的向后兼容性
    猜你喜欢
    • 1970-01-01
    • 2013-10-05
    • 2022-06-22
    • 1970-01-01
    • 2017-08-04
    • 1970-01-01
    • 2017-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多