【问题标题】:@JsonUnwrapped creates non-null object even when all fields are null即使所有字段为空,@JsonUnwrapped 也会创建非空对象
【发布时间】:2021-10-18 02:11:04
【问题描述】:

我在 SpringBoot 的上下文中遇到了这个问题,但它似乎只是一个 Jackson 问题。

我有一个包含多个字段的 DataObject。 DataObject 包含在模型中。 DataObject 的所有字段都是可选的。但是如果所有字段都为空,那么我希望 dataoObject 本身为空,但这似乎不是它的工作方式。

这是我的示例代码

@Getter
@ToString
@NoArgsConstructor
public class TestContract {

    private String field1;

    @JsonUnwrapped
    @Valid
    private DataObject dataObject;

    public static void main(String[] args) throws JsonProcessingException {
        //language=JSON
        String json = "{ \"field1\" :  \"value1\"}";
        ObjectMapper mapper = new ObjectMapper();
        TestContract contract = mapper.readValue(json, TestContract.class);
        System.out.println("contract: " + contract);
    }
}


@Getter
@NoArgsConstructor
@ToString
public class DataObject {
    private String nested1;
    private String nested2;
}

我最终得到的输出是

contract: TestContract(field1=value1, dataObject=DataObject(nested1=null, nested2=null))

有没有办法让对象最终为空?

【问题讨论】:

    标签: json spring-boot jackson


    【解决方案1】:

    问题是由于JsonUnwrapped 注释具有enabled 属性和默认true 值,因此即使属性dataObject 不存在于您的json 消息中,空的dataObject在任何情况下都会创建对象。要解决这个问题,可以使用JsonUnwrapped(enabled = false)注解,也可以直接删除JsonUnwrapped注解。

    更新:由于根据项目的具体情况,不可能删除JsonUnwrapped 注释,解决方法是创建一个自定义反序列化器,保持主代码不变,如下所示:

    @Getter
    @ToString
    @NoArgsConstructor
    public class TestContract {
    
        private String field1;
    
        @JsonUnwrapped
        private DataObject dataObject;
    
        public static void main(String[] args) throws JsonProcessingException, IOException {
            //language=JSON
            String json = "{ \"field1\" :  \"value1\"}";
            ObjectMapper mapper = new ObjectMapper();
            TestContract contract = mapper.readValue(json, TestContract.class);
            System.out.println("contract: " + contract);
        }
    }
    
    
    @Getter
    @Setter
    @NoArgsConstructor
    @ToString
    @JsonDeserialize(using = DataObjectDeserializer.class)
    public class DataObject {
        private String nested1;
        private String nested2;
    }
    
    public class DataObjectDeserializer extends JsonDeserializer<DataObject> {
        @Override
        public DataObject deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
            JsonNode node = jp.getCodec().readTree(jp);
            String nested1 = node.get("nested1").asText();
            String nested2 = node.get("nested2").asText();
            DataObject dataObject = new DataObject();
            dataObject.setNested1(nested1);
            dataObject.setNested2(nested2);
            return dataObject;
        }
    }
    

    【讨论】:

    • 谢谢。不知道直接删除 JsonUnwrapped 注释是什么意思。显然,不使用该注释可以解决问题。但我出于其他原因需要它。但我会尝试使用enabled=false
    • 您好,恐怕这不起作用。它总是将对象设置为空。我不完全理解enabled=false 的作用。文档很少,但说它仅适用于一些非常特定的情况。来自文档:Property that is usually only used when overriding (masking) annotations, using mix-in annotations.
    • @PeterKronenberg 您好,作为一种解决方法,我实现了一个自定义 DataObjectDeserializer,因此在 DataObject 类上使用 @JsonDeserializeSetter 注释可以解决问题。如果您认为它对您有用,我会将其添加到我的答案中。
    • @PeterKronenberg 可能我遗漏了一些东西,在我的版本代码中,我只删除了TestContract 类中的Valid 注释,并在Setter 类中添加了Setter 注释,所以JsonUnwrapped 注释在 TestContract 类中仍然保持不变。我正在使用杰克逊 2.12.2。
    • @PeterKronenberg,我添加了我的代码,所有类都在一个通用 maven 项目的同一个包中(没有 spring-boot)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-15
    • 1970-01-01
    • 2013-05-30
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    相关资源
    最近更新 更多