A service does `List<User> users = mapper.readValue(json, List.class);`. It compiles with an unchecked warning nobody reads, passes every test that checks `users.size()`, and then three files away, `users.get(0).getName()` throws `ClassCastException: LinkedHashMap cannot be cast to User`. Explain exactly what happened, and why the exception fires three files from the actual mistake.
At compile time, List<User> is checked as a distinct type from plain List<Object>-shaped things, but at run time none of that survives — the JVM only ever sees one class, List, with its type parameter erased to Object. That's why mapper.readValue(json, List.class) — asking Jackson for a List with no element type at all — is the only thing Jackson can build for an unknown element type: an ArrayList of raw LinkedHashMaps, one per JSON object, because there's no User anywhere in that call for it to construct instead. Assigning that result to List<User> users compiles with only a warning, not an error, precisely because erasure means List and List<User> are the same class at run time — there's nothing to actually check at the point of assignment, so no cast is inserted there. The real cast is inserted later, at the first place the compiler has to trust that the list really holds Users: users.get(0).getName() compiles to a checkcast User instruction right after the get() call, and that's where the mismatch between what's actually in the list (a LinkedHashMap) and what the code has been treating it as (a User) finally gets caught — three files and possibly several method calls away from the line that actually put the wrong thing in, because that's simply where the first read that needed the real type happened to be.