Deserialize JSON to ArrayList<POJO> using Jackson

JavaJsonMappingJackson

Java 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.class (which does not compile).

> So if you want to bind data into a Map you will need to use:

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);

TypeReference Javadoc

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>() {} but is not working.

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 as follows:

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.
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiontacos_tacos_tacosView Question on Stackoverflow
Solution 1 - JavaPerceptionView Answer on Stackoverflow
Solution 2 - JavaDevNGView Answer on Stackoverflow
Solution 3 - JavaДмитрий КулешовView Answer on Stackoverflow
Solution 4 - Javarushidesai1View Answer on Stackoverflow
Solution 5 - JavaJugal PanchalView Answer on Stackoverflow