Deserialize JSON в ArrayList <POJO> с использованием Jackson
У меня есть класс Java MyPojo
, который меня интересует десериализацией от JSON. Я настроил специальный класс MixIn, MyPojoDeMixIn
, чтобы помочь мне в десериализации. MyPojo
имеет только переменные экземпляра int
и String
в сочетании с правильными геттерами и сеттерами. MyPojoDeMixIn
выглядит примерно так:
public abstract class MyPojoDeMixIn {
MyPojoDeMixIn(
@JsonProperty("JsonName1") int prop1,
@JsonProperty("JsonName2") int prop2,
@JsonProperty("JsonName3") String prop3) {}
}
В моем тестовом клиенте я делаю следующее, но, конечно, он не работает во время компиляции, потому что существует JsonMappingException
, связанный с несоответствием типа.
ObjectMapper m = new ObjectMapper();
m.getDeserializationConfig().addMixInAnnotations(MyPojo.class,MyPojoDeMixIn.class);
try { ArrayList<MyPojo> arrayOfPojo = m.readValue(response, MyPojo.class); }
catch (Exception e) { System.out.println(e) }
Я знаю, что я мог бы облегчить эту проблему, создав объект "Response", в котором есть только ArrayList<MyPojo>
, но тогда мне пришлось бы создавать эти несколько бесполезных объектов для каждого отдельного типа, который я хочу вернуть.
Я также посмотрел онлайн на JacksonInFiveMinutes, но страшно понял информацию о Map<A,B>
и о том, как она относится к моей проблеме. Если вы не можете сказать, я совершенно новичок в Java и исхожу из фона Obj-C. Они специально упоминают:
Помимо привязки к POJO и "простым" типам, существует один дополнительный вариант: привязка к универсальным (типизированным) контейнерам. Этот случай требует специальной обработки из-за так называемого Type Erasure (используется Java для реализации генериков в несколько обратной совместимости путь), что мешает вам использовать что-то вроде Collection.class(который не компилируется).
Итак, если вы хотите привязать данные к карте, вам нужно будет использовать:
Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });
Как я могу десериализоваться непосредственно на ArrayList
?
Ответы
Ответ 1
Вы можете десериализовать непосредственно в список с помощью оболочки TypeReference
. Пример метода:
public static <T> T fromJSON(final TypeReference<T> type,
final String jsonPacket) {
T data = null;
try {
data = new ObjectMapper().readValue(jsonPacket, type);
} catch (Exception e) {
// Handle the problem
}
return data;
}
И используется таким образом:
final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);
Тип Ссылка Javadoc
Ответ 2
Другой способ - использовать массив как тип, например:
ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);
Таким образом, вы избегаете всех проблем с объектом Type, и если вам действительно нужен список, вы всегда можете преобразовать массив в список:
List<MyPojo> pojoList = Arrays.asList(pojos);
ИМХО это гораздо читаемо.
И чтобы сделать его реальным списком (который можно изменить, см. ограничения Arrays.asList()
), просто выполните следующее:
List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));
Ответ 3
Этот вариант выглядит более простым и элегантным.
CollectionType typeReference =
TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);
Ответ 4
У меня тоже такая же проблема. У меня есть json, который должен быть преобразован в ArrayList.
Учетная запись выглядит следующим образом.
Account{
Person p ;
Related r ;
}
Person{
String Name ;
Address a ;
}
Все вышеуказанные классы были аннотированы правильно.
Я попробовал TypeReference > () {}
но не работает.
Он дает мне Arraylist, но ArrayList имеет связанныйHashMap, который содержит еще несколько связанных hashmaps, содержащих окончательные значения.
Мой код выглядит следующим образом:
public T unmarshal(String responseXML,String c)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
try
{
this.targetclass = (T) mapper.readValue(responseXML, new TypeReference<ArrayList<T>>() {});
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return this.targetclass;
}
Я, наконец, решил проблему. Я могу преобразовать List в Json String прямо в ArrayList следующим образом:
JsonMarshallerUnmarshaller<T>{
T targetClass ;
public ArrayList<T> unmarshal(String jsonString)
{
ObjectMapper mapper = new ObjectMapper();
AnnotationIntrospector introspector = new JacksonAnnotationIntrospector();
mapper.getDeserializationConfig().withAnnotationIntrospector(introspector);
mapper.getSerializationConfig().withAnnotationIntrospector(introspector);
JavaType type = mapper.getTypeFactory().
constructCollectionType(ArrayList.class, targetclass.getClass()) ;
try
{
Class c1 = this.targetclass.getClass() ;
Class c2 = this.targetclass1.getClass() ;
ArrayList<T> temp = (ArrayList<T>) mapper.readValue(jsonString, type);
return temp ;
}
catch (JsonParseException e)
{
e.printStackTrace();
}
catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null ;
}
}
Ответ 5
Это работает для меня.
@Test
public void cloneTest() {
List<Part> parts = new ArrayList<Part>();
Part part1 = new Part(1);
parts.add(part1);
Part part2 = new Part(2);
parts.add(part2);
try {
ObjectMapper objectMapper = new ObjectMapper();
String jsonStr = objectMapper.writeValueAsString(parts);
List<Part> cloneParts = objectMapper.readValue(jsonStr, new TypeReference<ArrayList<Part>>() {});
} catch (Exception e) {
//fail("failed.");
e.printStackTrace();
}
//TODO: Assert: compare both list values.
}