#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. Как это работает с вложенными еще дальше, хотя, как в моем примере?