Сопоставьте массив объектов JSON с java.util.Map и наоборот

Вопрос заключается в том, как сопоставить массив объектов 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, что он должен использовать свойство field1 каждого объекта JSON в качестве ключа при десериализации массива элементов в Map?

Ответ 1

Как десериализовать строку 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 в объект Storage с полем items типа Map<String,Item>

 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 - Создать десериализацию почтовой рассылки

Уничтожьте строку JSON в объект Storage с массивом Item, как описано в начале, а затем создайте Map<Integer, Item> после.

Надеюсь, что это поможет.

Ответ 2

Для этого вы можете создать свои собственные Сериализаторы /Deserializers. Джексон обеспечивает аккуратный способ сделать это. Просто комментируйте класс Storage с помощью @JsonDeserialize (используя = YourDeserializer.class) и получите логику для преобразования json в YourDeserializer.

Ответ 3

Массив объектов JSON представляет собой массив элементов, правильно? Итак, почему бы просто не десериализовать массив в массив Java элементов, а затем построить там карту?