【问题标题】:Jackson XML deserialization, InvalidDefinitionException: Conflicting getter definitions for property "time"Jackson XML 反序列化,InvalidDefinitionException:属性“时间”的 getter 定义冲突
【发布时间】:2021-10-04 08:22:54
【问题描述】:

我有一个这样的 DTO:

package ...;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.*;
import lombok.experimental.FieldDefaults;

import java.time.LocalDateTime;
import java.util.List;

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
@JacksonXmlRootElement(localName = "root")
public class RootDto {
    @JsonInclude(value = JsonInclude.Include.NON_NULL)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
    LocalDateTime time;

    @JsonInclude(value = JsonInclude.Include.NON_NULL)
    @JacksonXmlElementWrapper(localName = "times")
    @JacksonXmlProperty(localName = "time")
    List<InternalTimeDto> times;

    ...
}
package ...;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import lombok.*;
import lombok.experimental.FieldDefaults;

import java.time.LocalDateTime;

@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
public class InternalTimeDto {
    @JacksonXmlProperty(isAttribute = true)
    Long id;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
    LocalDateTime time;
}

据我了解,问题在于time 字段和times 字段的元素具有相同的名称。有没有办法在不将time 重命名为其他名称的情况下解决冲突?理论上应该完全没有冲突,因为time字段和列表项处于不同的级别。
XML 示例:

<root>
    <time>2020-11-18 12:34</time>
    <times>
        <time id="5">2020-11-18 10:00</time>
        <time id="6">2020-11-17 15:30</time>
    </times>

    ...
</root>

我找到了几个答案,但是当两个具有相同名称的不同对象处于同一级别时,它们解决了问题。

也使用JSON:

{
  "time": "2020-11-18 12:34",
  "times": [
    {
      "id": 5,
      "time": "2020-11-18 10:00"
    },
    {
      "id": 6,
      "time": "2020-11-17 15:30"
    }
  ],
  ...
}

【问题讨论】:

    标签: spring-boot spring-mvc jackson json-deserialization xml-deserialization


    【解决方案1】:

    解决由于多个定义的属性 time 保留您的 xml 格式而引起的冲突的一种方法是创建一个包装您的 List&lt;InternalTimeDto&gt; 次的 Times 类:

    public class Times {
        @JacksonXmlProperty(localName = "time")
        @JacksonXmlElementWrapper(useWrapping = false)
        List<InternalTimeDto> times;   
    }
    

    所以你的RootDto 类可以这样重写:

    @Getter
    @Setter
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    @FieldDefaults(level = AccessLevel.PRIVATE)
    @JacksonXmlRootElement(localName = "root")
    public class RootDto {
        @JsonInclude(value = JsonInclude.Include.NON_NULL)
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
        LocalDateTime time;
    
        @JsonInclude(value = JsonInclude.Include.NON_NULL)
        private Times times; //<-- times field instead of List<InternalTimeDto> times 
    }
    

    您的InternalTimeDto 类需要JacksonXmlText 注释用于time 字段:

    @Getter
    @Setter
    @Builder
    @ToString
    @NoArgsConstructor
    @AllArgsConstructor
    @FieldDefaults(level = AccessLevel.PRIVATE)
    public class InternalTimeDto {
        @JacksonXmlProperty(isAttribute = true)
        Long id;
    
        @JacksonXmlText
        @JsonFormat(pattern = "yyyy-MM-dd HH:mm")
        LocalDateTime time;
    }
    

    【讨论】:

    • 谢谢,现在这对 XML 很好。不幸的是,为了简单起见,我没有提到也使用 JSON。我已经更新了问题。
    • @YaroslavTarasenko 欢迎您。使用我的类在RootDto 的json 案例中,将Times 类替换为List&lt;InternalTimeDto&gt; times,否则如果你想对xml 和json 使用相同的代码,唯一的选择是为Times 类编写一个自定义反序列化器。
    • 是的,在我看来,自定义反序列化器是唯一的解决方案。谢谢。
    猜你喜欢
    • 2014-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-19
    • 2019-06-23
    • 2016-02-12
    • 1970-01-01
    • 2016-08-15
    相关资源
    最近更新 更多