【问题标题】:Map dynamic field names while deserializing a JSON to a Java object在将 JSON 反序列化为 Java 对象时映射动态字段名称
【发布时间】:2018-02-02 20:05:24
【问题描述】:

我有一个有趣的问题想要解决。这是在我解析来自我们与之交互的平台之一的响应时。响应会根据用户而变化。

对于用户 A,我有以下 JSON:

{
 "userId": "AA001",
 "AA001_Name": "Username",
 "AA001_Email": "user@gmail.com",
 "AA001_Phone": "000-000-0000"
}

对于用户 B,我有:

{ 
  "userId" : "AA002",
  "AA002_Name" : "Username",
  "AA002_Email" : "user@gmail.com",
  "AA002_Phone" : "000-000-0000"
}

现在,在反序列化时,我想将它们都映射到以下对象,忽略 json 附带的字段名称:

class User {
  private String userId,
  private String name,
  private String email,
  private String phone
}

很容易映射 userId,因为那也是 JSON 中的字段,但是自定义字段呢?

现在,我不能使用@JsonProperty,因为字段的名称会根据用户动态变化。

有什么办法可以做到吗? 请注意,我可能有几个这样的自定义对象,如部门、组织等,并且平台以这种方式返回数据,这意味着键附加了用户特定的信息。

感谢任何帮助。我对此非常困惑。

【问题讨论】:

标签: java json jackson deserialization objectmapper


【解决方案1】:

我认为你不能比使用@JsonCreator 做得更好:

class User {

    private String userId;
    private String name;
    private String email;
    private String phone;

    @JsonCreator
    public User(Map<String, Object> map) {
        this.userId = (String) map.get("userId");
        map.entrySet().stream()
            .filter(e -> e.getKey().endsWith("_Name"))
            .findFirst()
            .ifPresent(e -> this.name = (String) e.getValue());
        // repeat for other fields
    }

    // getters & setters (if needed)
}

您可以通过传统方式更改地图条目集上的每个流,以优化性能。

【讨论】:

  • Alternative 可以使用@JsonAnySetter 用于接受两个参数(键名、值)的方法,类似的想法。主要好处是只有在没有要绑定的固定属性时才会调用它,因此您可以将属性与静态名称和“动态”属性结合起来。
  • @StaxMan @JsonAnySetter 也可以接收地图,对吗?
  • 感谢@Federico,这个解决方案是一个好的开始。我唯一担心的是,如果我的自定义对象“用户”中有另一个自定义对象,例如“地址”,或者说一个 List phoneNumbers,并且每个自定义对象的字段名称与来自平台的字段名称不同,您认为我们应该如何处理?
  • @Partha 我需要测试一下,因为我现在不记得了。我会在周末做,然后通知你。
  • @FedericoPeraltaSchaffner 是的,但仅作为单个未映射属性的值。不是所有未知的来源。
【解决方案2】:

您不能按原样使用@JSONProperty,但是如果您在反序列化 JSON 之前重新格式化密钥会怎样?即

  String key = "AA001_Name"
  String[] key = key.split("_") 
  key[0] = "AA001"
  key[1] = "Name"
  //Use key[1] as the new field name

对每个键执行此操作,使用正确的字段名称创建一个新的 JSON 对象,然后对其进行反序列化。

【讨论】:

  • 当我说以下场景时,此策略将不起作用,平台响应具有“AA001_complete_name_with_spaces_and_salutation”并且我想将其简单映射到我的 Java 对象中的“fullName”。
  • 嗯。当您收到 JSON 对象的键时,它们的顺序是否始终相同?键是否总是包含目标映射的某些部分?您收到的 JSON 是否一致?
  • 这很好。无法保证键的顺序,它是从 Map 中检索的,我很确定它们没有实现 TreeMap,但可能是一个普通的 HashMap 实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-24
  • 2018-01-12
  • 2012-04-02
相关资源
最近更新 更多