【问题标题】:Convert JSON with duplicated keys with jackson使用杰克逊转换带有重复键的 JSON
【发布时间】:2020-06-12 22:11:26
【问题描述】:

我正在将 json 转换为 java 对象,但我没有得到我想要的。 我在我的 json 中复制了“朋友”键。

我的 json:

{
    "id" : "5ee2e2f780bc8e7511a65de9",
    "friends": [{
        "friend": {
            "id": 1,
            "name": "Priscilla Lynch"
        },
        "friend": {
            "id": 2,
            "name": "William Lawrence"
        }
    }]
}

使用 ObjectMapper 中的 readValue 只需要最后一个“朋友”,但我需要两者。 我知道 JSONObject 使用 Map 进行转换,所以这就是它采用最后一个的原因。

结果: 联系人(id=5ee2e2f780bc8e7511a65de9,朋友=[{朋友={id=2,姓名=威廉劳伦斯}}])

ObjectMapper mapper = new ObjectMapper();
Contacts contacts = mapper.readValue(json, Contacts.class);

联系Pojo:

@Getter
@Setter
@ToString
public class Contacts {

    String id;
    List<Object> friends;
}

我想要一份所有朋友的名单。作为提供 json 的服务不在我手中,我需要找到解决它的方法。 我尝试使用 apache.commons 中的 MultiMap 但没有成功。 我坚持这一点。

【问题讨论】:

  • 您需要Friend 作为对象吗?因为您可以从JsonNode 中提取它们而无需反序列化它们。
  • 是的,我需要朋友列表
  • 你的 json 有点奇怪。您在同一节点中有 2 个名称相同的字段 friend。这使得杰克逊只选择其中一个(最后一个)。因此,即使您使用 JsonNode 处理它,第一个 friend 也会丢失。你可以执行这个JsonNode jsonNode = mapper.readTree(json); System.out.println(jsonNode.get("friends").get(0).toString()); 它打印数组friends 的第一个元素。它只打印一个,而不是两个。在我看来,json 是“错误的”。你的friends 是这样的[ { {}, {} } ]
  • @KunLun, JSON 有效载荷有效。对象结构表示为一对围绕零个或多个名称/值对的花括号标记。名称是一个字符串。每个名称后面都有一个冒号标记,将名称与值分开。单个逗号标记将值与后面的名称分开。 JSON 语法对用作名称的字符串不施加任何限制,不要求名称字符串是唯一的,并且不对名称/值对的顺序赋予任何意义。 Source

标签: java json jackson jackson-databind


【解决方案1】:

当您有一个带有重复字段的JSON Object 时,您可以使用com.fasterxml.jackson.annotation.JsonAnySetter 注释。结果将是List&lt;List&lt;X&gt;&gt;,因此,您可以使用flatMap 方法创建List&lt;X&gt;。见下例:

import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class DuplicatedFieldsInJsonObjectApp {

    public static void main(String[] args) throws Exception {
        File jsonFile = new File("./resource/test.json").getAbsoluteFile();

        ObjectMapper mapper = JsonMapper.builder().build();
        Contacts contacts = mapper.readValue(jsonFile, Contacts.class);
        System.out.println(contacts.getUnwrappedFriends());
    }
}

@Getter
@Setter
@ToString
class Contacts {

    String id;
    List<Friends> friends;

    public List<Friend> getUnwrappedFriends() {
        return friends.stream().flatMap(f -> f.getFriends().stream()).collect(Collectors.toList());
    }
}

class Friends {

    private List<Friend> friends = new ArrayList<>();

    @JsonAnySetter
    public void setAny(String property, Friend friend) {
        friends.add(friend);
    }

    public List<Friend> getFriends() {
        return friends;
    }
}

@Getter
@Setter
@ToString
class Friend {
    int id;
    String name;
}

上面的代码打印:

[Friend(id=1, name=Priscilla Lynch), Friend(id=2, name=William Lawrence)]

【讨论】:

  • 我尝试了这种方法,但我发现我的@JsonAnySetter 注释方法在我Sys.out 时没有得到重复的条目。我的意思是当我在@JsonAnySetter 注释方法中打印keyvalue 时,我只看到一个条目,即使是重复的key 也只有最后一个值。就好像Jackson 在使用此方法之前已经忽略了重复的条目。如果你得到,我已经在这里发布了我的问题。有机会请让我知道我该怎么做。 stackoverflow.com/questions/67413028/…
【解决方案2】:

还创建“朋友”的 POJO 类,然后编辑您的“联系人”类,如

public class Contacts {
   String id;
   List<Friend> friends;
}

然后你应该得到朋友项目的列表

【讨论】:

  • 您错过了friends 是一个包含单个对象的数组:friends[ { {friend}, {friend} } ]
猜你喜欢
  • 2012-09-07
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-25
  • 2019-05-18
  • 2013-08-16
  • 1970-01-01
相关资源
最近更新 更多