前言
在jackson中,最常见的就是通过ObjectMapper进行序列化和反序列化。ObjectMapper是一个通用的对象,它不仅可以对JSON格式进行操作,也可以对其它数据格式进行操作。而JSonMapper是JSON格式的专用操作对象
序列化与反序列化
把ObjectMapper的序列化和反序列化操作封装成一个工具类,供全局使用,因为ObjectMapper里面的序列化和反序列化逻辑都做了同步处理,因此不用担心出现线程安全的问题。
public class JsonUtil {
private static final ObjectMapper objectMapper = new ObjectMapper();
static {
objectMapper.enable(MapperFeature.PROPAGATE_TRANSIENT_MARKER);
}
// 序列化
public static <T> String obj2String(T obj) {
if (obj == null) {
return null;
}
try {
return obj instanceof String ? (String) obj : objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(obj);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 反序列化
public static <T> T string2Obj(String str, Class<T> clazz) {
if (StringUtils.isEmpty(str) || clazz == null) {
return null;
}
try {
return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
===
Student类
public class Student {
@JsonProperty(value = "studentName")
private String name;
@JsonProperty(value = "studentAge")
private Integer age;
private String profileImageUrl;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date birthdate;
public String getName() {
return name;
}
public Student setName(String name) {
this.name = name;
return this;
}
public Integer getAge() {
return age;
}
public Student setAge(Integer age) {
this.age = age;
return this;
}
public String getProfileImageUrl() {
return profileImageUrl;
}
public Student setProfileImageUrl(String profileImageUrl) {
this.profileImageUrl = profileImageUrl;
return this;
}
public Date getBirthdate() {
return birthdate;
}
public Student setBirthdate(Date birthdate) {
this.birthdate = birthdate;
return this;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", profileImageUrl='" + profileImageUrl + '\'' +
", birthdate=" + birthdate +
'}';
}
}
===
@Test
public void obj2String() {
Student student = new Student();
student.setAge(20);
student.setName("json");
student.setProfileImageUrl("www.baidu.com");
student.setBirthdate(new Date());
System.out.println(JsonUtil.obj2String(student));
}
@Test
void string2Obj() {
String json = "{\n" +
" \"profileImageUrl\" : \"www.baidu.com\",\n" +
" \"birthdate\" : \"2020-08-07 00:13:07\",\n" +
" \"studentName\" : \"jhon\",\n" +
" \"studentAge\" : 20,\n" +
" \"father\": {\n" +
" \"name\": \"mac\"\n" +
" }\n" +
"}";
Student student = JsonUtil.string2Obj(json, Student.class);
System.out.println(student);
}
泛型擦除问题
@Test
public void testRead() throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String idsStr = "[1,2,3]";
List<Long> list = objectMapper.readValue(idsStr, List.class);
Long i1 = list.get(0);
System.out.println(list);
}
上面的例子会抛出如下错误:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
所以解决办法有两个
- 使用成员变量保存泛型
public class data {
private List<Long> numbers;
public List<Long> getNumbers() {
return numbers;
}
public data setNumbers(List<Long> numbers) {
this.numbers = numbers;
return this;
}
}
@Test
public void readGeneric() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String numbers = "{\"numbers\" : [1,2,3]}";
Data d = objectMapper.readValue(numbers, Data.class);
Long i1 = d.getNumbers().get(0);
System.out.println(i1);
}
但是这种方式不直接,还得把json数据包一层 2. 使用TypeReference
@Test
public void readGeneric() throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
String numbers = "{\"numbers\" : [1,2,3]}";
List<Long> longList = objectMapper.readValue(numbers, new TypeReference<List<Long>>() {
});
Long i1 = longList.get(0);
System.out.println(i1);
}
TypeReference能够将泛型的类型保存下来,比如如果想反序列化成Map<String,String>,那么提供下面
objectMapper.readValue(jsonStr,new TpeReference<Map<String,String>>(){}
树模型
在一个json字符串中,如果只想取某一个属性的值,树模型可以非常简单的实现
{"name":"generator-test","age":22,"object":{"name":"nested-object","value":"this is a test"},"list":["computer","helicopter"]}
如果只想获得list
@Test
void treeNode() throws JsonProcessingException {
String jsonStr = "{\"name\":\"generator-test\",\"age\":22,\"object\":{\"name\":\"nested-object\",\"value\":\"this is a test\"},\"list\":[\"computer\",\"helicopter\"]}";
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(jsonStr).get("list");
int i = 0;
while (jsonNode.hasNonNull(i)) {
System.out.println(jsonNode.get(i).asText());
i++;
}
}
这样就不用专门构造POJO来接受list啦