121

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?

tacos_tacos_tacos
  • 10,277
  • 11
  • 73
  • 126
  • See also https://stackoverflow.com/questions/7246157/how-to-parse-a-json-string-to-an-array-using-jackson – Raedwald Mar 01 '19 at 16:11

5 Answers5

173

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

reevesy
  • 3,452
  • 1
  • 26
  • 23
Perception
  • 79,279
  • 19
  • 185
  • 195
  • Your answer seems related to their info on how to use the built-in support for `TypeReference` - I just don't get how to do it... Please see my edit above for their instructions on how to use generics. – tacos_tacos_tacos Mar 22 '12 at 20:04
  • 1
    Well, it is related. But this is a snippet from working code in production. Forget about your mixin, just use the code I've shown (but replace POJO of course with the name of your actual bean class). – Perception Mar 22 '12 at 20:07
  • Your code compiled, but I get a run time exception when attempting to print out the `arrayList.toString()` about a `NullPointerException`. I'm guessing that this could be because my `POJO` does not conform to the right naming conventions for its properties, that is, the whole issue is that the web service returns `Prop1Member` and my object has `Prop1`. This is the only real reason I'm using mixins to begin with, so I do not have to put the declarations for `@JsonProperty` in my pure objects. – tacos_tacos_tacos Mar 22 '12 at 20:19
  • 1
    Visually inspect your array to make sure you got back a list at least. And if need be add the mixin back, which *should* work along with the TypeReference to get everything neatly deserialized. – Perception Mar 22 '12 at 20:27
  • I know that the `response` string is definitely a valid JSON representation of an array. Right now I get the runtime exception: `org.codehaus.jackson.map.exc.UnrecognizedPropertyException: Unrecognized field "PropertyMember" (Class com.obfuscated.general.Object), not marked as ignorable at [Source: java.io.StringReader@406754d6; line: 1, column: 30] (through reference chain: com.obfuscated.general.Object["PropertyMember"])` so how do I incorporate my mixin? Forgive me if its a thick question, I am new to Java. – tacos_tacos_tacos Mar 22 '12 at 20:57
  • And to be clear, your code works beautifully when I add the `@JsonProperty` declarations in the object itself, but I've been told that this is an undesirable thing to do, and prescribed the mixin solution as the antidote. – tacos_tacos_tacos Mar 22 '12 at 21:00
  • 3
    @JsonProperty is not as evil as people make it out too be. It's hard to get away from vendor specific annotations what with the current state of standardization (minimal) in the field. – Perception Mar 22 '12 at 21:19
  • Any examples on how to deserialize json objects into Lists using jackson 2.x api? – Andy Dufresne Aug 27 '13 at 11:56
  • The answer from @DevNG using Arrays.asList to convert an array or mapped objects is better than this one – robjwilkins Feb 23 '18 at 11:01
  • Just for info, here's the necessary syntax in Kotlin: `objectMapper.readValue>(fileOrString, object : TypeReference>() {})` – Robert Jack Will Mar 17 '18 at 14:51
  • If, like me, you tried moving that type parameter into the fromJson method, you would quickly find that it doesn't work. Is this due to type erasure? – Adrian Redgers May 31 '19 at 09:56
124

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));
DevNG
  • 5,875
  • 3
  • 18
  • 14
  • 1
    Elegant sure, but I am unable to generify it because of MyPojo[].class , which I don't want to pass in as a parameter. – Adrian Redgers May 31 '19 at 09:59
  • I think using `TypeFactory` as described in the next answer: https://stackoverflow.com/a/42458104/91497 is the Jackson way to specify the type. – Jmini Aug 06 '19 at 10:30
53

This variant looks more simple and elegant.

//import com.fasterxml.jackson.core.JsonProcessingException;
//import com.fasterxml.jackson.databind.ObjectMapper;
//import com.fasterxml.jackson.databind.type.CollectionType;
//import com.fasterxml.jackson.databind.type.TypeFactory;

//import java.util.List;


CollectionType typeReference =
    TypeFactory.defaultInstance().constructCollectionType(List.class, Dto.class);
List<Dto> resultDto = objectMapper.readValue(content, typeReference);
granadaCoder
  • 26,328
  • 10
  • 113
  • 146
6

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.
}
Jugal Panchal
  • 1,448
  • 16
  • 20
4

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

}
Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
rushidesai1
  • 173
  • 1
  • 9