使用Jackson转换具有重复键的JSON

3

我正在将一个json转换为Java对象,但我没有得到我想要的结果。我的json中有重复的键“friend”。

我的json:

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

使用ObjectMapper的readValue只会获取最后一个"friend",但是我需要两个。 我知道JSONObject使用Map进行转换,所以它只获取了最后一个。
结果: Contacts(id=5ee2e2f780bc8e7511a65de9, friends=[{friend={id=2, name=William Lawrence}}])
ObjectMapper mapper = new ObjectMapper();
Contacts contacts = mapper.readValue(json, Contacts.class);

联系人数据类:

@Getter
@Setter
@ToString
public class Contacts {

    String id;
    List<Object> friends;
}

我希望能获得所有朋友的列表。由于提供JSON文件的服务不在我的手中,我需要找到解决方法。 我尝试使用apache.commons中的MultiMap,但没有成功。 我被卡住了。

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

2

当你有一个带有重复字段的JSON对象时,你可以使用com.fasterxml.jackson.annotation.JsonAnySetter注解。结果将是一个List<List<X>>,因此,你可以使用flatMap方法创建List<X>。请参见下面的示例:

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)]

1
我尝试了这种方法,但是当我使用Sys.out时,我发现我的@JsonAnySetter注释的方法没有获取到重复的条目。我的意思是,当我在@JsonAnySetter注释的方法中打印keyvalue时,即使是重复的key,我只看到一个条目,其值为最后一个。就好像在到达该方法之前,Jackson已经忽略了重复的条目一样。如果您有机会,请访问此处发布的问题,并告诉我该怎么做。 https://stackoverflow.com/questions/67413028/java-jackson-jsonanysetter-does-not-store-the-values-of-duplicate-key - BATMAN_2008

0
创建“Friend”的POJO类,然后编辑您的“Contacts”类。
public class Contacts {
   String id;
   List<Friend> friends;
}

然后,您应该获得Friend项的列表


1
你错过了一个重要的部分,即friends是一个只包含单个对象的数组:friends[ { {friend}, {friend} } ] - KunLun

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接