将一个JSON对象数组映射到java.util.Map,反之亦然

10

问题是如何将一个 JSON 对象数组映射到 java.util.Map 中,其中每个键都是对象的某个指定属性,值是该对象本身。

JSON:

{"items": [{"field1": 1, "field2": "Hello"}, {"field1": 2, "field2":"World"}]}

Java POJO:

public class Storage {
    private Map<Integer, Item> items;
}

public class Item {
    private Integer field1;
    private String field2;
}

有没有一种方法可以告诉 ObjectMapper 在将项数组反序列化为 Map 时使用每个 JSON 对象的 field1 属性作为键?

3个回答

7

如何反序列化JSON字符串

您可以使用Jackson来反序列化JSON字符串:

例如,如果您有一个名为Foo的类:

public class Foo {

   private Bar[] items;

   // Constructor / Getters & Setters

} 

这个类有一个Bar类的数组。

 public class Bar {

     private int field1;
     private String field2;


     // Constructor / Getters & Setters

 }

如果字段名称与您的JSON字符串匹配,那么可以执行以下操作进行转换:

String jsonString = "{\"items\": [{\"field1\": 1, \"field2\": \"Hello\"}, {\"field1\": 2, \"field2\":\"World\"}]}";

ObjectMapper mapper = new ObjectMapper();

Foo foo = mapper.readValue(jsonString, Foo.class);

如果您正在使用Maven,需要在您的pom.xml文件中添加以下依赖项:
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>${jackson.version}</version>
    </dependency>

解决问题的方法:

选项1 - 自定义反序列化器

编写自定义JsonDeserializer将您的JSON字符串反序列化为一个带有类型为Map<String,Item>Storage对象的字段items

 public class CustomDeserializer extends JsonDeserializer<Storage> {

    @Override
    public Storage deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException {

        Map<Integer, Item> map = new HashMap<>();

        ObjectCodec oc = jsonParser.getCodec();
        JsonNode rootNode = oc.readTree(jsonParser);
        JsonNode items = rootNode.get("items");

        for (int i = 0; i < items.size(); i++) {

            JsonNode childNode = items.get(i);

            Item item = new Item(childNode.get("field1").asInt(), childNode.get("field2").asText());

            map.put(item.getField1(), item);
        }

        return new Storage(map);
    }
}

接着,您需要在您的Storage类中添加以下内容:

@JsonDeserialize(using = CustomDeserializer.class)

您的Storage类大致如下:

@JsonDeserialize(using = CustomDeserializer.class)
public class Storage {

   private Map<Integer, Item> items;

   public Storage(Map<Integer, Item> map) {
    this.items = map;
   }

   ...

}

选项2 - 在反序列化后创建Map

将JSON字符串反序列化为一个Storage对象,其中包含一个如开头所述的Item数组,然后构建你的Map<Integer, Item>

希望这有所帮助。


它不能解决我的问题。我知道,如果“items”只是一个数组或某个“Collection”,如何反序列化JSON对象。再次强调:我想将“items”反序列化为映射,其中键是存储在值中的对象属性。 - Pavel Mitrofanov

1
你可以创建自己的自定义序列化器/反序列化器来实现这一点。Jackson提供了一种简洁的方法。只需在Storage类上注释@JsonDeserialize(using=YourDeserializer.class),并在YourDeserializer中编写将JSON转换的逻辑即可。

0

JSON对象数组是一个Items数组,对吧?那么为什么不将该数组反序列化为Java的Items数组,然后从中构建Map呢?


因为在我的情况下,有一个底层的通用源(DAO),它具有所有的序列化/反序列化逻辑,并在后台使用ObjectMapper。我不想在那里改变任何东西。目前,使用自定义序列化程序/反序列化程序的解决方案似乎是实现我想要的唯一方法... - Pavel Mitrofanov

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