“This is the 21st day of my participation in the First Challenge 2022. For details: First Challenge 2022.”
Author: Tangyuan
Personal blog: Javalover.cc
preface
Jackson parsing collections is exactly the same as parsing Java objects, only slightly different;
If the data type in the collection is primitive, such as String, then we can parse it directly, readValue(s, list.class), and output will be fine;
But if the data type in the collection is a Java class, such as User, then parsing becomes problematic because Jackson erases the class information and prints data such as Map.
Let’s do an example;
directory
- Parses a collection of primitive types
- Parse a collection of Java classes
The body of the
1. Parse a collection of primitive types
This can be done directly by looking at the code, as shown below:
List<String> list = Arrays.asList("a"."b");
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(list);
List<String> list1 = objectMapper.readValue(s, List.class);
System.out.println(list1);
Copy the code
The output is as follows:
As you can see, as expected, no objections;
2. Parse a collection of Java classes
Here we create a User entity class:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String username;
private String password;
}
Copy the code
The main program then builds multiple User objects to test:
User user = new User("jalon"."xiaowang");
User user2 = new User("jalon2"."xiaowang2");
List<User> list = Arrays.asList(user, user2);
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writeValueAsString(list);
List<User> list1 = objectMapper.readValue(s, List.class);
System.out.println( list1.get(0).getUsername());
Copy the code
Here we want to display the username of the first User, but we get an error:
Problem Description:
Error: LinkedHashMap cannot be converted to User, indicating that the User attribute in the parsed list has been erased and LinkedHashMap has been replaced.
Solutions:
There are two solutions: construct TypeReference and CollectionType. The core of both methods is to wrap the collection to be serialized and then process it accordingly.
Method 1: TypeReference wrapper
TypeReference takes a generic T as a parameter. We can pass List
as an argument and then read TypeReference data as follows:
TypeReference<List<User>> typeReference = new TypeReference<List<User>>() {};
List<User> list1 = objectMapper.readValue(s, typeReference);
Copy the code
ReadValue converts TypeReference to JavaType.
As you can see, a JavaType is essentially constructed with the typeReference parameter
Then we run the following output:
As you can see, we successfully accessed the user. username property. If we printed the entire List, we would print all the User objects:
System.out.println( list1);
Copy the code
Option 2: CollectionType wrapper
The CollectionType wrapper wraps the attributes of the List collection and the User entity class separately, and then reads them, as shown below:
CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, User.class);
List<User> list = objectMapper.readValue(s, collectionType);
Copy the code
At this point, run the output, the same result as above, is normal output;
The core of both the CollectionType wrapper and the TypeReference wrapper is to wrap collections and element types to be serialized, and then convert them when read.
conclusion
If the parsed collection element is a primitive type, it can be parsed without any processing.
If the parsed collection element is a Java class, then the collection needs to be wrapped with TypeReference or CollectionType and then read.