0

I was working with jackson lib in java to deserialize an json file to an array list. First I use this method and everything worked fine.

ObjectMapper objectMapper = new ObjectMapper();
ArrayList<User> users = (ArrayList<User>) objectMapper.readValue(new File("data.json"), new TypeReference<List<User>>() {});

Then I decided to refactor the code and write a generic method to use for any type of data.

public static <T> ArrayList<T> listFromJson(String filename) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        return (ArrayList<T>) objectMapper.readValue(new File(filename), new TypeReference<List<T>>() {});
}

This method returns the array list without any exceptions. But when I want to use an element of arraylist and store it in a variable the program throws exception like this.

User user = users.get(0);
Exception in thread "main" java.lang.ClassCastException: class java.util.LinkedHashMap cannot be cast to class org.example.User ...
    ....

I also tried to print out the element without casting and it wasn't an object reference. It was something like a hashmap.

I think it is related to generics but I don't know the cause. Thanks for your help.

1 Answer 1

1

Your object User is a JsonNode, something like this:

{
   "userName": "...",
   "email": "...",
   etc.
}

While this object can be mapped against a User.class if you specify so, when you don't say anything, the only guess that Jackson can take is that this is a Map<String, Object> (and the implementation a LinkedHashMap, meaning a map respecting its insertion order).

So when you refactored your method:

public static <T> ArrayList<T> listFromJson(String filename) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    return (ArrayList<T>) objectMapper.readValue(new File(filename), new TypeReference<List<T>>() {});
}

... you said to Jackson that it will find a List<T> where T can be any object. The only guess it can take is it will be a JsonNode (hence a Map.class).

To solve this issue, you should pass the concrete TypeReference to the method as well:

public static <T> ArrayList<T> listFromJson(String filename, TypeReference<?> expectedTypeReference) throws IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    return (List<T>) objectMapper.readValue(new File(filename), expectedTypeReference);
}

... and use it like this:

TypeReference<List<User>> expectedTypeRef = new TypeReference<>() {};
List<User> users = listFromJson(fileName, expectedTypeRef);
User user = users.get(0); // <-- this should work
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.