Part 1: TypeReference, and what List.class actually produces
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
package com.ankurm.jackson3.part1objectmapper;
|
||||
|
||||
import tools.jackson.core.type.TypeReference;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Post: Jackson ObjectMapper Guide — https://ankurm.com/jackson-objectmapper-guide/
|
||||
* Section: "Working with Collections and Generic Types"
|
||||
*
|
||||
* Why TypeReference is required, and what actually happens without it.
|
||||
*
|
||||
* Note the import: TypeReference lives in tools.jackson.core.type in Jackson 3.
|
||||
*/
|
||||
public class B03GenericCollections {
|
||||
|
||||
public record Article(Long articleId, String title) { }
|
||||
|
||||
public static void main(String[] args) {
|
||||
JsonMapper mapper = JsonMapper.builder().build();
|
||||
|
||||
String jsonArray = "[{\"articleId\":1,\"title\":\"First\"},"
|
||||
+ "{\"articleId\":2,\"title\":\"Second\"}]";
|
||||
|
||||
// CORRECT: TypeReference captures List<Article> through an anonymous subclass,
|
||||
// so the parameterised type survives erasure and reaches Jackson at runtime.
|
||||
List<Article> articles = mapper.readValue(jsonArray, new TypeReference<List<Article>>() { });
|
||||
System.out.println("size : " + articles.size());
|
||||
System.out.println("element class : " + articles.get(0).getClass().getSimpleName());
|
||||
System.out.println("first title : " + articles.get(0).title());
|
||||
|
||||
// WRONG: List.class erases the element type. This COMPILES and does not throw
|
||||
// here — the failure is deferred to the first time you treat an element as an
|
||||
// Article, which is what makes it such an unpleasant bug.
|
||||
@SuppressWarnings("rawtypes")
|
||||
List raw = mapper.readValue(jsonArray, List.class);
|
||||
System.out.println("raw element : " + raw.get(0).getClass().getSimpleName()
|
||||
+ " <- not Article");
|
||||
try {
|
||||
Article boom = (Article) raw.get(0);
|
||||
System.out.println("unreachable: " + boom);
|
||||
} catch (ClassCastException e) {
|
||||
System.out.println("cast fails : ClassCastException, as expected");
|
||||
}
|
||||
|
||||
// A Map value type needs the same treatment.
|
||||
String jsonObject = "{\"a\":{\"articleId\":9,\"title\":\"Nine\"}}";
|
||||
Map<String, Article> byKey =
|
||||
mapper.readValue(jsonObject, new TypeReference<Map<String, Article>>() { });
|
||||
System.out.println("map value : " + byKey.get("a").title());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user