Type Token
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
Problem That TypeToken solves
// Consider these two lists
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
// At runtime, due to type erasure, Java sees both as just List
// This means we can't directly tell Gson what type to deserialize to
// with the help of TypeToken we tell Gson about type of data in process of ser and desr.
// Creating a TypeToken for a List of Strings
Type listType = new TypeToken<List<String>>(){}.getType();
// Using it with Gson
List<String> strings = gson.fromJson(jsonString, listType);
Different Ways to Use TypeToken
Simple Generic Types
// For List<String>
Type stringListType = new TypeToken<List<String>>(){}.getType();
// For Set<Integer>
Type integerSetType = new TypeToken<Set<Integer>>(){}.getType();
// For Map<String, Boolean>
Type mapType = new TypeToken<Map<String, Boolean>>(){}.getType();
Nested Generic Types
// For List<List<String>>
Type nestedListType = new TypeToken<List<List<String>>>(){}.getType();
// For Map<String, List<User>>
Type complexMapType = new TypeToken<Map<String, List<User>>>(){}.getType();
Custom Generic Classes
// Generic response wrapper
public class ApiResponse<T> {
private int status;
private T data;
// getters and setters
}
// Usage
Type responseType = new TypeToken<ApiResponse<User>>(){}.getType();
ApiResponse<User> response = gson.fromJson(json, responseType);
Creating Reusable TypeTokens
public class TypeTokens {
// Private constructor to prevent instantiation
private TypeTokens() {}
// Reusable TypeToken for List<String>
public static final Type STRING_LIST_TYPE = new TypeToken<List<String>>(){}.getType();
// Reusable TypeToken for Map<String, User>
public static final Type STRING_USER_MAP_TYPE = new TypeToken<Map<String, User>>(){}.getType();
}
// Usage
List<String> strings = gson.fromJson(json, TypeTokens.STRING_LIST_TYPE);
Advanced Usage with Parameterized Types
public class GenericTypeHandler<T> {
private final Type type;
public GenericTypeHandler() {
// Capture the actual type parameter
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof ParameterizedType) {
this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
} else {
throw new RuntimeException("Missing type parameter.");
}
}
public T fromJson(String json) {
return new Gson().fromJson(json, type);
}
}
// Usage
public class UserListHandler extends GenericTypeHandler<List<User>> {}
UserListHandler handler = new UserListHandler();
List<User> users = handler.fromJson(jsonString);
Working with Complex Nested Structures
public class ComplexTypeExample {
public static void main(String[] args) {
Gson gson = new Gson();
// Complex nested structure
Type complexType = new TypeToken<Map<String, List<Set<User>>>>(){}.getType();
// Creating sample data
Map<String, List<Set<User>>> data = new HashMap<>();
// ... populate data ...
// Serialization
String json = gson.toJson(data, complexType);
// Deserialization
Map<String, List<Set<User>>> parsed = gson.fromJson(json, complexType);
}
}
Some points to consider -
Insure proper type safety.
Do proper error handling.
Create type tokens and reuse them.
Last updated