Jackson: Deserializing an Array of Objects in Java in 2025 — A Pro Guide

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Every Java Developer Should Know This Trick



Imagine: you receive JSON from a server, containing dozens of similar objects. Clients, products, logs — it doesn't matter. You grab ObjectMapper, write readValue(json, MyClass[].class) — and it works. But a month later, the code crashes with a ClassCastException because someone replaced the array with a List. Sound familiar?



The question “How to use Jackson to deserialise an array of objects” on Stack Overflow has gathered tens of thousands of views. And this is no coincidence: deserializing an array of objects in Java is one of those tasks that seems simple until you encounter generics and Type Erasure. In 2025, Jackson remains the de facto standard for working with JSON, but best practices have changed. In this article, we will cover not only the basic approaches but also modern techniques that will save you headaches.



Basic Approach: Array or List?



The simplest way is to use an array. Jackson perfectly understands that MyClass[].class is an array of objects:



ObjectMapper mapper = new ObjectMapper();String json = "[{\\"id\\":1,\\"name\\":\\"Alice\\"},{\\"id\\":2,\\"name\\":\\"Bob\\"}]";MyClass[] array = mapper.readValue(json, MyClass[].class);


Does it work? Yes. But this approach has drawbacks:

  • Fixed-size array — inconvenient for dynamic data.
  • No collection methods (stream(), filter(), remove()).
  • Harder to extend if you later need a List.


Therefore, in 90% of cases, you will want to get a List<MyClass>. And here's where the fun begins — Type Erasure in Java. If you write:



List<MyClass> list = mapper.readValue(json, List.class); // warning: unchecked


The compiler will complain, and at runtime you will get a List<LinkedHashMap>, not a List<MyClass>. Generics are erased, and Jackson doesn't know what type to map the elements to.



TypeReference: The Correct Way for List



The solution is to use TypeReference. This is an anonymous inner class that preserves generic type information through reflection:



List<MyClass> list = mapper.readValue(json, new TypeReference<List<MyClass>>() {});


Note the {} — this creates an anonymous class that captures the type. Jackson, via TypeFactory, understands that it needs to deserialize a List of MyClass. This approach is the gold standard in 2025.



When is TypeReference inconvenient?

  • If you dynamically construct the type (e.g., from configuration).
  • If you need to deserialize the same thing many times — creating an anonymous class each time is costly.


For these cases, there is an alternative — CollectionType.



CollectionType: The Power of JavaType



Jackson provides TypeFactory for constructing complex types:



JavaType type = mapper.getTypeFactory()    .constructCollectionType(List.class, MyClass.class);List<MyClass> list = mapper.readValue(json, type);


This method:

  • Does not create anonymous classes (less overhead).
  • Allows constructing types dynamically: constructParametricType(Map.class, String.class, MyClass.class).
  • Ideal for libraries and frameworks where types are unknown at compile time.


Best practice 2025: use TypeReference for simple cases, CollectionType when flexibility or performance is needed.



Reader and InputStream: Don't Forget About Resources



Blogs

Book Recommendations