In Java generics are more or less gone at runtime. This is called type erasure. So your HashMap<String, Object> will just be HashMap<?, ?> when your programme runs. So Jackson cannot determine the types Stringand Object. That is why you have to create a TypeReference which will preserve that information at runtime so Jackson can deserialise your JSON String into the correct classes.

If you don't specify a type Jackson will still be able to correctly deserialise simple objects like String or numbers but when a more complex object is encountered it will simply deserialise them into LinkedHashMap which will then most likely lead to a ClassCastException when you try to access the deserialised object.

Answer from geanakuch on Stack Overflow
Top answer
1 of 2
26

In Java generics are more or less gone at runtime. This is called type erasure. So your HashMap<String, Object> will just be HashMap<?, ?> when your programme runs. So Jackson cannot determine the types Stringand Object. That is why you have to create a TypeReference which will preserve that information at runtime so Jackson can deserialise your JSON String into the correct classes.

If you don't specify a type Jackson will still be able to correctly deserialise simple objects like String or numbers but when a more complex object is encountered it will simply deserialise them into LinkedHashMap which will then most likely lead to a ClassCastException when you try to access the deserialised object.

2 of 2
9

This TypeReference<T> implements Comparable<TypeReference<T>> is part of jackon library. And this is part of com.fasterxml.jackson.core.type. From the API documentation:

This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" bundle) to be used. Class is based on ideas from http://gafter.blogspot.com/2006/12/super-type-tokens.html, Additional idea (from a suggestion made in comments of the article) is to require bogus implementation of Comparable (any such generic interface would do, as long as it forces a method with generic type to be implemented). to ensure that a Type argument is indeed given. Usage is by sub-classing: here is one way to instantiate reference to generic type List:

TypeReference ref = new TypeReference<List>() { }; which can be passed to methods that accept TypeReference, or resolved using TypeFactory to obtain ResolvedType.

This is basically used to de-serialize the Generic type of JSON objects, for example the JAVA Collection objects as below:

public List<Double> getDoubleList() {

  return getObjectFromJson(new TypeReference<List<Double>>() {
  });
}


public <T> T getObjectFromJson(String jsonString, final TypeReference<T> typeReference) {
  try {
    return new ObjectMapper().readValue(jsonString, typeReference);
  } catch (JsonProcessingException e) {
    // TODO
  }
}
🌐
Fasterxml
fasterxml.github.io › jackson-core › javadoc › 2.2.0 › com › fasterxml › jackson › core › type › TypeReference.html
TypeReference (Jackson-core 2.2.0 API)
Index · Help · Prev Class · ... extends Object implements Comparable<TypeReference<T>> This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" ...
🌐
DEV Community
dev.to › emilossola › a-comprehensive-guide-for-java-typereference-249m
A Comprehensive Guide for Java TypeReference - DEV Community
July 10, 2023 - For example, if you have a List, ... type erasure. TypeReference is typically used in scenarios where you want to capture the generic type information at compile time and use it later at runtime....
🌐
Quora
quora.com › What-is-TypeReference-in-Java
What is TypeReference in Java? - Quora
Answer (1 of 2): I don’t think that java by default comes with any TypeReference class or interface. Although Jackson, which is a pretty popular Json parsing library, has TypeReference abstract class. It is used with object mapper to give a reference of what type of data you want after the ...
🌐
Oracle
docs.oracle.com › en › middleware › developer-tools › adf › 12.2.1.4 › api-reference-model › oracle › adf › internal › model › rest › json › util › TypeReference.html
TypeReference (Oracle Fusion Middleware Java API Reference for Oracle ADF Model)
java.lang.Object · oracle.adf.internal.model.rest.json.util.TypeReference<T> Type Parameters: T - type to be used for JSON mapper · public abstract class TypeReference<T> extends java.lang.Object · clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait ·
🌐
Medium
medium.com › @poojaauma › enhancing-deserialization-safety-in-java-with-typereference-ea110ece6994
Enhancing Deserialization Safety in Java with TypeReference | by Umadevi R | Medium
November 7, 2024 - In this article, we’ll explore what TypeReference does, why it’s essential for safe deserialization, and how it can help avoid common pitfalls in handling JSON data. When using Jackson’s ObjectMapper to deserialize JSON, specifying the type directly using .readValue(json, Class<T>) works well for simple types. But if your target type is a generic, like List<User> or Map<String, User>, Java’s type erasure removes generic information at runtime.
🌐
Baeldung
baeldung.com › home › json › jackson › deserialize generic type with jackson
Deserialize Generic Type with Jackson | Baeldung
September 17, 2025 - As well known, Java erases generic type information during compilation, but we can take advantage of the power of anonymous inner classes to preserve the type information during compile time. Jackson provides the abstract class TypeReference to obtain the type information from the derivated subclasses:
Find elsewhere
🌐
Spring
docs.spring.io › spring-framework › docs › current › javadoc-api › org › springframework › asm › TypeReference.html
TypeReference (Spring Framework 7.0.8 API)
java.lang.Object · org.springframework.asm.TypeReference · public class TypeReference extends Object · A reference to a type appearing in a class, field or method declaration, or on an instruction.
🌐
Spring
docs.spring.io › spring-framework › docs › 5.1.8.RELEASE_to_5.1.9.RELEASE › Spring Framework 5.1.9.RELEASE › org › springframework › asm › TypeReference.html
TypeReference
The target_type and target_info structures - as defined in the Java Virtual Machine Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all the target_info union fields use up to 3 bytes (except localvar_target, handled with the specific method MethodVisitor.visitLocalVariableAnnotation(int, org.springframework.asm.TypePath, org.springframework.asm.Label[], org.springframework.asm.Label[], int[], java.lang.String, boolean)). Thus, both structures can be stored in an int. This int field stores target_type (called the TypeReference 'sort' in the public API of this class) in its most significant byte, followed by the target_info fields.
🌐
Java Tips
javatips.net › api › com.fasterxml.jackson.core.type.typereference
Java Examples for com.fasterxml.jackson.core.type.TypeReference
public static void main(String[] args) { try { TestHttpClient productClient = new TestHttpClient(SERVER_RESOURCE).init(); // Add products String productJson = Resources.toString(getResource(DEFAULT_PATH), UTF_8); TypeReference<List<ProductDto>> listOfProductRequests = new TypeReference<List<ProductDto>>() { }; List<ProductDto> products = OBJECT_MAPPER.readValue(productJson, listOfProductRequests); for (ProductDto product : products) { productClient.post(OBJECT_MAPPER.writeValueAsString(product)); } System.out.println("Imported [" + products.size() + "] products..."); } catch (Exception e) { e.printStackTrace(); } }
🌐
Javadoc.io
javadoc.io › doc › com.fasterxml.jackson.core › jackson-core › latest › com › fasterxml › jackson › core › type › TypeReference.html
TypeReference - jackson-core 2.22.3 javadoc
https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core · Current version 2.22.3 · https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.22.3 · package-list path (used for javadoc generation -link option) https://javadoc.io/doc/com.fasterxml.jackson.core/jackson-core/2.22.3/package-list ·
Top answer
1 of 3
267

This is a well-known problem with Java type erasure: T is just a type variable, and you must indicate actual class, usually as Class argument. Without such information, best that can be done is to use bounds; and plain T is roughly same as 'T extends Object'. And Jackson will then bind JSON Objects as Maps.

In this case, tester method needs to have access to Class, and you can construct

JavaType type = mapper.getTypeFactory().
  constructCollectionType(List.class, Foo.class)

and then

List<Foo> list = mapper.readValue(new File("input.json"), type);
2 of 3
12

'JavaType' works !! I was trying to unmarshall (deserialize) a List in json String to ArrayList java Objects and was struggling to find a solution since days.
Below is the code that finally gave me solution. Code:

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 ;
    }  
}
🌐
Adobe Developer
developer.adobe.com › experience-manager › reference-materials › 6-5 › javadoc › com › fasterxml › jackson › core › type › TypeReference.html
TypeReference (The Adobe AEM Quickstart and Web Application.)
Index · Help · Prev Class · ... implements java.lang.Comparable<TypeReference<T>> This generic abstract class is used for obtaining full generics type information by sub-classing; it must be converted to ResolvedType implementation (implemented by JavaType from "databind" ...
🌐
Northcoder
northcoder.com › post › jackson-object-mapper-which-way-is
Jackson's ObjectMapper and TypeReference | northCoder
January 15, 2021 - In fact there is nothing at all in the anonymous class - it is completely empty. I think this double-brace syntax is relatively rare. I have never seen it outside of tutorials and Stack Overflow questions. And blog posts discouraging its use. ... Final note: The TypeReference class implements Comparable. The javadoc states that this is because doing so forces a compile-time check to ensure you have provided a type when instantiating a new TypeReference object:
🌐
Itechguides
itechguides.com › home › blog › understanding typereference in java for converting json to map
Understanding TypeReference in Java for Converting JSON to Map
August 18, 2026 - Jackson’s ObjectMapper provides readValue overloads for a plain Class<T>, a Jackson JavaType, and a TypeReference<T>. The ObjectMapper API documentation describes the TypeReference overload as the option for types whose generic information cannot be represented by one Class object.
🌐
Baeldung
baeldung.com › home › java › core java › super type tokens in java generics
Super Type Tokens in Java Generics | Baeldung
June 21, 2025 - TypeReference<Map<String, Integer>> token = new TypeReference<Map<String, Integer>>() {}; Type type = token.getType(); assertEquals("java.util.Map<java.lang.String, java.lang.Integer>", type.getTypeName()); Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments(); assertEquals("java.lang.String", typeArguments[0].getTypeName()); assertEquals("java.lang.Integer", typeArguments[1].getTypeName()); Using super type tokens, we know that the container type is Map, and also, its type parameters are String and Integer.
🌐
CodingTechRoom
codingtechroom.com › question › -java-jackson-typereference-explained
Understanding TypeReference in Java with Jackson - CodingTechRoom
TypeReference is a utility class in Jackson that enables developers to define generic types when working with serialization and deserialization. It retains type information during run-time, which is otherwise erased due to Java's type erasure ...