33

I have a question which is similar to some questions at stackoverflow but none really answer my problem. I use the ObjectMapper of Jackson and want to parse this JSON string into an List of User objects:

[{ "user" : "Tom", "role" : "READER" }, 
 { "user" : "Agnes", "role" : "MEMBER" }]

I define an inner class like this:

public class UserRole {

    private String user
    private String role;

    public void setUser(String user) {
        this.user = user;
    }

    public void setRole(String role) {
        this.role = role;
    }

    public String getUser() {
        return user;
    }

    public String getRole() {
        return role;
    }
}

To parse the JSON String to an List of UserRoles I use generics:

protected <T> List<T> mapJsonToObjectList(String json) throws Exception {
    List<T> list;
    try {
        list = mapper.readValue(json, new TypeReference<List<T>>() {});
    } catch (Exception e) {
        throw new Exception("was not able to parse json");
    }
    return list;
}

But what I get back is a List of LinkedHashMaps.

What is wrong with my code?

pb2q
  • 58,613
  • 19
  • 146
  • 147
Markus Weigelt
  • 352
  • 1
  • 3
  • 6
  • 3
    It's Java language, and infamous type erasure: T in there is a type variable and not type definition; and basically means that you are asking for List. Jackson then binds JSON using 'natural' Object types, and JSON Object then becomes a Map (of type LinkedHashMap which preserves ordering). You correctly solved the problem by passing Class, which does then define actual type. – StaxMan Aug 13 '11 at 00:09

1 Answers1

40

The following works and as per StaxMan's advice no longer uses the deprecated static collectionType() method.

public class SoApp
{

   /**
    * @param args
    * @throws Exception
    */
   public static void main(String[] args) throws Exception
   {
      System.out.println("Hello World!");

      String s = "[{\"user\":\"TestCity\",\"role\":\"TestCountry\"},{\"user\":\"TestCity\",\"role\":\"TestCountry\"}]";
      StringReader sr = new StringReader("{\"user\":\"TestCity\",\"role\":\"TestCountry\"}");
      //UserRole user = mapper.readValue(sr, UserRole.class);

      mapJsonToObjectList(s,UserRole.class);

   }

   protected static <T> List<T> mapJsonToObjectList(String json, Class<T> clazz) throws Exception
   {
      List<T> list;
      ObjectMapper mapper = new ObjectMapper();
      System.out.println(json);
      TypeFactory t = TypeFactory.defaultInstance();
      list = mapper.readValue(json, t.constructCollectionType(ArrayList.class,clazz));

      System.out.println(list);
      System.out.println(list.get(0).getClass());
      return list;
   }
}

...

public class UserRole{

   private String user;
   private String role;

   public void setUser(String user) {
       this.user = user;
   }

   public void setRole(String role) {
       this.role = role;
   }

   public String getUser() {
       return user;
   }

   public String getRole() {
       return role;
   }

   @Override
   public String toString()
   {
      return "UserRole [user=" + user + ", role=" + role + "]";
   }
   
}

output...

 Hello World!
[{"user":"TestCity","role":"TestCountry"},{"user":"TestCity","role":"TestCountry"}]
[UserRole [user=TestCity, role=TestCountry], UserRole [user=TestCity, role=TestCountry]]
class com.test.so.fix.UserRole
developer747
  • 15,419
  • 26
  • 93
  • 147
nsfyn55
  • 14,875
  • 8
  • 50
  • 77
  • 2
    Correct. One minor note is that to get around deprecation issue, you can call 'objectMapper.getTypeFactory()' to use non-static methods; this change (to use TypeFactory instances) in Jackson 1.8 was necessary to support JVM languages like Scala which have their own Collection/Map types... – StaxMan Aug 13 '11 at 00:10
  • 1
    @nsfyn55 your answer includes two main points of that kind of questions. Using `T` and handling it with non deprecated methods. Voting up. – kamaci Nov 16 '11 at 21:43
  • Thank you so much, this works wonderfully! Even ChatGPT was not able to provide this kind of solution! – Crossoni Jul 07 '23 at 07:27