JSON в Java POJO не работает для простой структуры?

#java #json #jackson

#java #json #джексон

Вопрос:

JSON:

 {
  "246": {
    "test1": "one" 
  },
  "355": {
    "test2": "two"
  }
}
  

Java POJO

 class POJO{
  private HashMap<String, SubPojo> subMap;

  @JsonAnySetter
  public void addToMap(String key, SubPojo val){ subMap.put(key, value); }
}

class SubPojo{
  private HashMap<String, String> map; 
  @JsonAnySetter
  public void addToMap(String key, String val) { map.put(key, value);}
}
  

В моем коде я делаю: (используя Jackson)

 POJO testing = (new ObjectMapper()).convertValue("path/to/json", POJO.class);
  

Я получаю исключение, говорящее:

 "Unrecognized field `246`..."
  

Где я ошибаюсь?

Комментарии:

1. POJO имеет поле, subMap но не 246 . Таким образом, вам нужно сообщить объектному картографу, что каждое неизвестное поле должно обрабатываться как ключ к subMap вместо фактического свойства. То, как это делается, зависит от используемой вами библиотеки json. Кстати, вам нужно сделать то же самое для SubPojo .

2. @Thomas, я использую JackSon, можете ли вы помочь мне здесь?

3. В принципе, вам нужно использовать аннотацию @JsonAnySetter @JsonAnyGetter , если вы также хотите сериализовать в json).

4. В качестве альтернативы, не определяйте никаких классов и не выполняйте синтаксический анализ в Map<String, Map<String, String>> , хотя вам придется использовать TypeReference для предотвращения потери аргументов универсального типа.

5. Обратите внимание, что если все ваши объекты в основном являются картами, вы также можете просто разобрать этот json в maps или в общий формат дерева через ObjectMapper.readTree(json) .

Ответ №1:

Что-то вроде этого:

 public class Pojo {
    private Map<String,Object> map = new HashMap<>();

    @JsonAnySetter
    public void addToMap(String key, Object value) {
        this.map.put(key, value);
    }

    @JsonAnyGetter
    public Map<String,Object> getMap() {
        return map;
    }
}
  

Существует статья о Baeldung, в которой рассматриваются различные аннотации Джексона, включая эту, и некоторые основы на Jackson wiki.

Комментарии:

1. Какой у меня объект с вложенным значением, хотя, как в моем примере?

Ответ №2:

Вам не нужно создавать какие-либо классы POJO для разбора этого текста в формате JSON, поскольку он может быть преобразован в Map<String, Map<String, String>> .

Вам придется использовать TypeReference , чтобы предотвратить потерю аргументов универсального типа.

 Map<String, Map<String, String>> data = new ObjectMapper()
        .readValue(new File("test.json"),
                   new TypeReference<Map<String, Map<String, String>>>() {});
  

Распечатка этой data карты с использованием текста JSON в вопросе покажет:

 {246={test1=one}, 355={test2=two}}
  

Комментарии:

1. Да, я знаю, но для меня требуется обернуть это.

Ответ №3:

converValue метод используется для преобразования объектов. Смотрите JavaDoc :

Удобный метод для выполнения двухэтапного преобразования из заданного значения в экземпляр заданного типа значения, если (но только если!) Преобразование необходимо. Если заданное значение уже имеет запрошенный тип, значение возвращается как есть. Этот метод функционально аналогичен первой сериализации заданного значения в JSON, а затем привязке данных JSON к значению заданного типа, но должен быть более эффективным, поскольку полная сериализация не выполняется (в этом нет необходимости). Однако будут использоваться те же преобразователи (сериализаторы, десериализаторы), что и для привязки данных, что означает, что работает та же конфигурация object mapper.

Например, вы можете «преобразовать» File в String вот так:

 mapper.convertValue(jsonFile, String.class)
  

Где jsonFile находится экземпляр File класса. Примером результата может быть: path/to/json .

Для десериализации JSON полезной нагрузки используйте один из readValue семейства методов.

Вы можете создать свой, POJO с аннотированным конструктором JsonCreator :

 class Pojo {

    private final Map<String, SubPojo> map;

    @JsonCreator
    public Pojo(Map<String, SubPojo> map) {
        this.map = map;
    }

    public Map<String, SubPojo> getMap() {
        return map;
    }

    @Override
    public String toString() {
        return "Pojo{"  
                "map="   map  
                '}';
    }
}

class SubPojo {

    private Map<String, String> map;

    @JsonCreator
    public SubPojo(Map<String, String> map) {
        this.map = map;
    }

    @Override
    public String toString() {
        return "SubPojo{"  
                "map="   map  
                '}';
    }
}
  

И простое использование. Для чтения JSON из файла используйте readValue метод:

 import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.util.Map;

public class JsonApp {

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

        ObjectMapper mapper = new ObjectMapper();
        Pojo map = mapper.readValue(jsonFile, Pojo.class);
        System.out.println(map);
    }
}
  

Приведенный выше код выводит:

 Pojo{map={246=SubPojo{map={test1=one}}, 355=SubPojo{map={test2=two}}}}
  

Если вы хотите сохранить свою модель данных, используйте JsonAnySetter аннотацию. Ваша модель данных может выглядеть следующим образом:

 class Pojo {
    private Map<String, SubPojo> subMap = new HashMap<>();

    @JsonAnySetter
    public void addToMap(String key, SubPojo value) {
        subMap.put(key, value);
    }

    @Override
    public String toString() {
        return "POJO{"  
                "subMap="   subMap  
                '}';
    }
}

class SubPojo {
    private Map<String, String> map = new HashMap<>();

    @JsonAnySetter
    public void addToMap(String key, String value) {
        map.put(key, value);
    }

    @Override
    public String toString() {
        return "SubPojo{"  
                "map="   map  
                '}';
    }
}
  

Приведенный выше пример использования выводит:

 POJO{subMap={355=SubPojo{map={test2=two}}, 246=SubPojo{map={test1=one}}}}
  

Комментарии:

1. Как это работает с вложенными еще дальше, хотя, как в моем примере?