Deserialize JSON to ArrayList<POJO> using Jackson
JavaJsonMappingJacksonJava Problem Overview
I have a Java class MyPojo
that I am interested in deserializing from JSON. I have configured a special MixIn class, MyPojoDeMixIn
, to assist me with the deserialization. MyPojo
has only int
and String
instance variables combined with proper getters and setters. MyPojoDeMixIn
looks something like this:
public abstract class MyPojoDeMixIn {
MyPojoDeMixIn(
@JsonProperty("JsonName1") int prop1,
@JsonProperty("JsonName2") int prop2,
@JsonProperty("JsonName3") String prop3) {}
}
In my test client I do the following, but of course it does not work at compile time because there is a JsonMappingException
related to a type mismatch.
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) }
I am aware that I could alleviate this issue by creating a "Response" object that has only an ArrayList<MyPojo>
in it, but then I would have to create these somewhat useless objects for every single type I want to return.
I also looked online at JacksonInFiveMinutes but had a terrible time understanding the stuff about Map<A,B>
and how it relates to my issue. If you cannot tell, I'm entirely new to Java and come from an Obj-C background. They specifically mention:
> In addition to binding to POJOs and "simple" types, there is one
> additional variant: that of binding to generic (typed) containers.
> This case requires special handling due to so-called Type Erasure
> (used by Java to implement generics in somewhat backwards compatible
> way), which prevents you from using something like
> Collection
> So if you want to bind data into a Map
Map<String,User> result = mapper.readValue(src, new TypeReference<Map<String,User>>() { });
How can I deserialize directly to ArrayList
?
Java Solutions
Solution 1 - Java
You can deserialize directly to a list by using the TypeReference
wrapper. An example method:
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;
}
And is used thus:
final String json = "";
Set<POJO> properties = fromJSON(new TypeReference<Set<POJO>>() {}, json);
Solution 2 - Java
Another way is to use an array as a type, e.g.:
ObjectMapper objectMapper = new ObjectMapper();
MyPojo[] pojos = objectMapper.readValue(json, MyPojo[].class);
This way you avoid all the hassle with the Type object, and if you really need a list you can always convert the array to a list by:
List<MyPojo> pojoList = Arrays.asList(pojos);
IMHO this is much more readable.
And to make it be an actual list (that can be modified, see limitations of Arrays.asList()
) then just do the following:
List<MyPojo> mcList = new ArrayList<>(Arrays.asList(pojos));
Solution 3 - Java
This variant looks more simple and elegant.
CollectionType typeReference =
TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);
Solution 4 - Java
I am also having the same problem. I have a json which is to be converted to ArrayList
Account looks like this.
Account{
Person p ;
Related r ;
}
Person{
String Name ;
Address a ;
}
All of the above classes have been annotated properly.
I have tried TypeReference
It gives me Arraylist but ArrayList has a linkedHashMap which contains some more linked hashmaps containing final values.
My code is as Follows:
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;
}
I finally solved the problem. I am able to convert the List in Json String directly to 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 ;
}
}
Solution 5 - Java
This works for me.
@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.
}