How to Retrieve Generic Types at Runtime with Gson’s TypeToken
This article explains Java's generic type erasure, why it exists, and demonstrates how to use Gson's TypeToken and reflection APIs to obtain actual generic type information at runtime, complete with code examples and a detailed walkthrough of the underlying mechanism.
Overview
By analyzing the principle of TypeToken, we deepen our understanding of generic type erasure, enabling us to know when and how we can obtain the actual generic type.
Generic Erasure
Java generics are only effective at compile time; at runtime the generic type is erased, so List<String> and List<Integer> both become List<Object>.
This design ensures backward compatibility of existing class files and allows generic and non‑generic code to interoperate, which is why Java adopted type erasure instead of preserving generic information.
TypeToken
Usage
When using Gson, you define a TypeToken to specify the target type for deserialization, for example:
private Type type = new TypeToken<List<Map<String, Foo>>>(){}.getType();
// Pass the type to fromJson; if it matches the JSON structure, Gson can deserialize correctly.
gson.fromJson(json, type);Three Questions
Why use TypeToken? Directly passing List<Map<String, Foo>> would be erased to List<Object> , causing Gson to default to LinkedTreeMap instead of the desired Map<String, Foo> .
Why the curly braces {} ? They create an anonymous subclass of TypeToken, which is essential for capturing the generic type.
Why obtain the generic type via a subclass? The subclass retains the generic parameter information in its class metadata, which can be accessed through reflection APIs such as Class.getGenericSuperclass() and ParameterizedType.getActualTypeArguments() .
Type mySuperClass = foo.getClass().getGenericSuperclass();
Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
System.out.println(type);The method Class.getGenericSuperclass() returns a ParameterizedType for classes with generic superclasses, or null for Object, interfaces, primitives, or arrays.
Principle
The core of TypeToken lies in its constructor, which calls getSuperclassTypeParameter(getClass()) to capture the actual type argument of the anonymous subclass.
public final Type getType() {
// directly returns the captured type
return type;
} protected TypeToken() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<?>) $Gson$Types.getRawType(type);
this.hashCode = type.hashCode();
}
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}Summary
After understanding the underlying mechanism, you can reliably retrieve generic type information at runtime using Gson's TypeToken and Java reflection.
References
https://www.cnblogs.com/doudouxiaoye/p/5688629.html
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
