jackson是一个强大的json工具库,但api不够直观(至少不如fastJson),使用起来总是没有那么友好。本文介绍readValue和convertValue这两个方法的使用和区别。

在使用jackson对json处理之前, 首先要创建ObjectMapper对象:

ObjectMapper objectMapper = new ObjectMapper()

说明:这个对象是线程安全的,在网上看到过,在高并发环境下,为了保证线程安全会有较高的锁竞争,所以很多时候都是每次通过new来创建ObjectMapper。

一、readValue()方法:

这个方法有很多个重载,但是总的来说都是用来将json字符串,转换成一个object(bean、map、List<bean/map>)。

先来看一些准备数据:

@Data
public class User {private String name;private String nameEn;
}//简单类型
String arrayStr = "[{\"name\":\"Zhangsan\"},{\"nameEn\":\"Lisi\"}]";
String jsonStr = "{\"name\":\"a\",\"nameEn\":\"b\"}";//复杂类型
private static String getComplex1() throws Exception{List<Map<String,User>> list = new ArrayList<>();Map<String,User> m1 = new HashMap<>();m1.put("1", new User("zs","zs_en"));Map<String,User> m2 = new HashMap<>();m2.put("3", new User("ls","ls_en"));list.add(m1);list.add(m2);return new ObjectMapper().writeValueAsString(list);
}
private static String getComplex2() throws Exception{Map<String,List<User>> m = new HashMap<>();List<User> list1 = new ArrayList<>();list1.add(new User("tt","tt1"));m.put("1", list1);List<User> list2 = new ArrayList<>();list2.add(new User("ww","ww1"));m.put("2", list2);return new ObjectMapper().writeValueAsString(m);
}

readValue支持一下三种api:

  • readValue(String content, Class<T>  valueType)

  • readValue(String content, TypeReference<T> valueTypeRef)

  • readValue(String content, JavaType valueType)

1、readValue(String content, Class<T>  valueType)使用:

/**
* readValue(String content, Class<T>  valueType)
*///bean
User uu = new ObjectMapper().readValue(jsonStr, User.class);
System.out.println(uu);//User(name=a, nameEn=b)
//map
Map mm = new ObjectMapper().readValue(jsonStr, Map.class);
System.out.println(mm);//{name=a, nameEn=b}//默认jackson将每个json对象封装成LinkedHashMap,然后放到list中
List<Map> readValue = new ObjectMapper().readValue(arrayStr, List.class);
System.out.println(readValue);//[{name=Zhangsan}, {nameEn=Lisi}]//List<bean> 无法构造//复杂类型
String complexStr1 = getComplex1(); //List<Map<String, User>>
String complexStr2 = getComplex2(); //Map<String,List<User>>List<Map> list1 = new ObjectMapper().readValue(complexStr1, List.class);
System.out.println(list1); //[{1={name=zs, nameEn=zs_en}}, {3={name=ls, nameEn=ls_en}}]Map map1 = new ObjectMapper().readValue(complexStr2, Map.class);
System.out.println(map1); //{1=[{name=tt, nameEn=tt1}], 2=[{name=ww, nameEn=ww1}]}

说明:该api主要是用来将json字符串装成bean或者map,对于json数组的情况,默认是转成LinkedHashMap放到list中(无法指定list元素类型),所以对于List<Bean>这种结构,推荐使用下面两种方式。

2、readValue(String content, TypeReference valueTypeRef)使用:

TypeReference可以用来指定反序列化时数据类型,支持json对象和json数组。

示例:

/*** readValue(String content, TypeReference valueTypeRef) */
private static  void typeReference() throws Exception {//beanUser uu1 = new ObjectMapper().readValue(jsonStr, new TypeReference<User>(){});System.out.println(uu1); //User(name=a, nameEn=b)//mapMap mm1 = new ObjectMapper().readValue(jsonStr, new TypeReference<Map>(){});System.out.println(mm1); //{name=a, nameEn=b}//list<bean/map>List<User> userList = new ObjectMapper().readValue(arrayStr, new TypeReference<List<User>>(){});System.out.println(userList); //[User(name=Zhangsan, nameEn=null), User(name=null, nameEn=Lisi)]List<Map> mapList = new ObjectMapper().readValue(arrayStr, new TypeReference<List<Map>>(){});System.out.println(mapList); //[{name=Zhangsan}, {nameEn=Lisi}]//复杂类型String complexStr1 = getComplex1(); //List<Map<String, User>>String complexStr2 = getComplex2(); //Map<String,List<User>>List<Map<String, User>> list1 = new ObjectMapper().readValue(complexStr1, new TypeReference<List<Map<String, User>>>(){});System.out.println(list1); //[{1=User(name=zs, nameEn=zs_en)}, {3=User(name=ls, nameEn=ls_en)}]Map<String, List<User>> map1 = new ObjectMapper().readValue(complexStr2, new TypeReference<Map<String,List<User>>>(){});System.out.println(map1); //{1=[User(name=tt, nameEn=tt1)], 2=[User(name=ww, nameEn=ww1)]}
}

说明:该api可以将json对象和json数组的字符串转成对应的bean/map 和 List<bean/map>。

3、readValue(String content, JavaType valueType)使用:

利用 TypeFactory.constructParametricType()进行JavaType的类型构造

3.1)通过TypeFactory构造不同的JavaType:

1)constructMapType(Class<? extends Map> mapClass, Class<?> keyClass, Class<?> valueClass):

转换成map,同时指定key和value类型;

注:无法通过TypeFactory直接构造出一个Bean

2)constructCollectionType(Class<? extends Collection> collectionClass, Class<?> elementClass):

转成成list,并指定元素类型;

3)constructParametricType:

这个方法可以处理各种复杂结构,主要有以下两个声明:

public JavaType constructParametricType(Class<?> parametrized, Class<?>... parameterClasses)
public JavaType constructParametricType(Class<?> rawType, JavaType... parameterTypes)

方法中后面的可变形参参数必须一致。JavaType可以通过调用getRawClass方法来变成Class类型。对于复杂结构,核心思路:从内到外构造类型,从右到左,一步一步来!

3.2)示例:

/*** readValue(String content, JavaType valueType) */private static void javaTypeTest() throws Exception {System.out.println("--------JavaType---------");//bean 无法构造//mapMap<String,String> mm = new ObjectMapper().readValue(jsonStr, new ObjectMapper().getTypeFactory().constructMapType(HashMap.class, String.class, String.class));System.out.println(mm);//List<bean>CollectionType userListType = new ObjectMapper().getTypeFactory().constructCollectionType(ArrayList.class, User.class);List<User> userList2 = new ObjectMapper().readValue(arrayStr, userListType);System.out.println(userList2);//[User(name=Zhangsan, nameEn=null), User(name=null, nameEn=Lisi)]//List<Map>CollectionType mapListType = new ObjectMapper().getTypeFactory().constructCollectionType(ArrayList.class, Map.class);List<Map> mapList2 = new ObjectMapper().readValue(arrayStr, mapListType);System.out.println(mapList2);//[{name=Zhangsan}, {nameEn=Lisi}]//复杂类型String complexStr1 = getComplex1(); //List<Map<String, User>>String complexStr2 = getComplex2(); //Map<String,List<User>>//先构造内部结构innerTypeJavaType innerType = objectMapper.getTypeFactory().constructParametricType(Map.class, String.class, User.class);//再构造List<innerType>结构JavaType resultType = objectMapper.getTypeFactory().constructParametricType(List.class, innerType);List<Map<String,User>> list1 = objectMapper.readValue(complexStr1, resultType);System.out.println(list1); //[{1={name=zs, nameEn=zs_en}}, {3={name=ls, nameEn=ls_en}}]//先构造右边部分rightTypeJavaType rightType = objectMapper.getTypeFactory().constructParametricType(List.class, User.class);//在构造全局Map<String,rightType>JavaType resultType1 = objectMapper.getTypeFactory().constructParametricType(Map.class, String.class, rightType.getRawClass());Map<String,List<User>> map1 = objectMapper.readValue(complexStr2, resultType1);System.out.println(map1); //{1=[{name=tt, nameEn=tt1}], 2=[{name=ww, nameEn=ww1}]}}

3.3)TyepReference和JavaType区别:

TypeReference比javaType模式更加方便,代码也更加简洁,看一下例子:

//JavaType list<bean>
@Test
public void test4() throws Exception {ObjectMapper mapper = new ObjectMapper();JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, Student.class);List<Student> list = new ArrayList<>();list.add(new Student("adai",21));list.add(new Student("apei",22));String json = mapper.writeValueAsString(list);List<Student> student2 = mapper.readValue(json, javaType);System.out.println(student2.get(0).getName());
}//JavaType Map<String,Bean>
@Test
public void test5() throws Exception {ObjectMapper mapper = new ObjectMapper();// 第二个参数是Map的key,第三个参数是Map的valueJavaType javaType = mapper.getTypeFactory().constructParametricType(Map.class, String.class, Student.class); Map<String, Student> map = new HashMap<>();map.put("first",new Student("adai",21));map.put("second",new Student("apei",22));String json = mapper.writeValueAsString(map);Map<String, Student> result = mapper.readValue(json, javaType);System.out.println(result.get("first").getName());
}//TypeReference list<bean>
@Test
public void test6() throws Exception {ObjectMapper mapper = new ObjectMapper();List<Student> list = new ArrayList<>();list.add(new Student("adai",21));list.add(new Student("apei",22));String json = mapper.writeValueAsString(list);List<Student> student2 = mapper.readValue(json, new TypeReference<List<Student>>(){}); System.out.println(student2.get(0).getName());
}
//TypeReference Map<Strin,bean>
@Test
public void test7() throws Exception {ObjectMapper mapper = new ObjectMapper();Map<String, Student> map = new HashMap<>();map.put("first",new Student("adai",21));map.put("second",new Student("apei",22));String json = mapper.writeValueAsString(map);Map<String, Student> result = mapper.readValue(json, new TypeReference<Map<String,Student>>(){});System.out.println(result.get("first").getName());
}

4、其他

readValue出了上面从String读取json字符串外,还支持从InputStrea、URL等源读取json字符串,然后进行转换。例如:

InputStream in = null;
Map m = objectMapper.readValue(in, Map.class);

Jackson还有一个很有意思的功能,虽然没有广泛的被人所知道。那就是POJO和POJO之间的转换。概念性的可以理解成POJO1->JSON->POJO2,但是实际上会省略中间这一步,不会真正的生成JSON,而会用其他更高效的实现:

ResultType result = mapper.convertValue(sourceObject, ResultType.class);

例如:

// List<Integer> -> int[]
List<Integer> sourceList = ...;
int[] ints = mapper.convertValue(sourceList, int[].class);
// POJO -> Map
Map<String,Object> propertyMap = mapper.convertValue(pojoValue, Map.class);
// Map -> POJO
PojoType pojo = mapper.convertValue(propertyMap, PojoType.class);
// decode Base64! (default byte[] representation is base64-encoded String)

设置,还可以做base64

//解码
String base64 = "TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz";
byte[] binary = mapper.convertValue(base64, byte[].class);
System.out.println(new String(binary));
//编码
String str = "Man is distinguished, not only by his reason, but by this";
String base = mapper.convertValue(str.getBytes(), String.class);
System.out.println(base);

二、convertValue()方法

从方法名字上来看,该方法是用来做转换的,将一个object转成其他object或List<object>,不能将json字符串转成object。所以和readValue有个本质的区别是:convertValue方法输入的是对象,而不是字符串。

convertValue同readValue一样,也有三个重载:

  • convertValue(Object fromValue, Class<T> toValueType)
  • convertValue(Object fromValue, TypeReference<T> valueTypeRef)
  • convertValue(Object fromValue, JavaType javaType)

接下来只以convertValue(Object fromValue, TypeReference<T> valueTypeRef)  为例看一下:

private static void convertTest() {System.out.println("-----------------");//convertValue三种用法:将object转成object 或 List<object>//注:不能将string转成object 下面这两种都会报错//        User uu = new ObjectMapper().convertValue(jsonStr, User.class);//        System.out.println(uu);//        //        Map mm = new ObjectMapper().convertValue(jsonStr, Map.class);//        System.out.println(mm);//bean > mapUser u = new User("aaa","aaa_en");Map<String,String> map1 = new ObjectMapper().convertValue(u, new TypeReference<Map<String,String>>(){});System.out.println(map1); //{name=aaa, nameEn=aaa_en}//map > beanUser user1 = new ObjectMapper().convertValue(map1, new TypeReference<User>(){});System.out.println(user1); //User(name=aaa, nameEn=aaa_en)//List<bean> > List<Map>List<User> list1 = new ArrayList<>();list1.add(user1);List<Map<String,String>> list2 = new ObjectMapper().convertValue(list1, new TypeReference<List<Map<String,String>>>(){});System.out.println(list2); //[{name=aaa, nameEn=aaa_en}]//list<Map> > list<Bean>List<User> list3 = new ObjectMapper().convertValue(list1, new TypeReference<List<User>>(){});System.out.println(list3); //[User(name=aaa, nameEn=aaa_en)]
}

三、bean和map之间的转换方法

根据上面可知使用jackson的convertValue方法可以在bean和map之间进行转换。此外,还可以通过如下方法:

1、Apache commons-beanutils工具:

<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
<dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.3</version>
</dependency>

示例:

public static void main(String... strings) throws Exception {User u = new User();u.setName("aaa");u.setNameEn("bbb");//bean to mapMap describe = new BeanMap(u);System.out.println(describe); //BeanMap<JsonUtils.User(name=aaa, nameEn=bbb)>//bean to mapMap<String, String> map = BeanUtils.describe(u);//{name=aaa, nameEn=bbb, class=class com.tencent.rating.common.utils.JsonUtils$User}System.out.println(map);//map to beanUser uu = new User();BeanUtils.populate(uu, describe);System.out.println(uu); //JsonUtils.User(name=aaa, nameEn=bbb)
}@Data
public static class User {private String name;private String nameEn;
}

注:使用describe方法将bean转成map时,会多一个class信息在map中。

https://www.hicode.club/articles/2018/03/18/1550590751627.html

https://juejin.cn/post/6844903694379548679

https://www.cnblogs.com/AdaiCoffee/p/10933091.html#3-jackson-%E5%A4%84%E7%90%86%E6%B3%9B%E5%9E%8B%E8%BD%AC%E6%8D%A2

jackson的readValue和convertValue方法相关推荐

  1. 程序验证Jackson反序列化的规则、Jackson序列化与反序列化关键方法程序详细分析

    目录 0. 为什么要做这个分析 1. Jackson反序列化时,无参构造.有参构造的执行顺序[附程序截图] 1.1 没有无参构造时: 1.2 无参构造和有参构造方法都有的时候先走无参构造: 2. Ja ...

  2. Jackson ObjectMapper readValue过程

    1.整体调用栈 2.看一下调用栈的两个方法 resolve 方法中通过 Iterator i$ = this._beanProperties.iterator() 遍历属性的所有子属性,缓存对应的 d ...

  3. jackson序列化错误 get类型方法名的坑 [com.fasterxml.jackson.databind.exc.InvalidDefinitionException]

    错误:com.fasterxml.jackson.databind.exc.InvalidDefinitionException com.fasterxml.jackson.databind.exc. ...

  4. java.lang.ClassNotFoundException: com.fasterxml.jackson.databind.exc.InvalidDefinitionException解决方法

    今天做项目的时候,需要通过SpringMVC返回Map<String,User>的json字符串,但是启动服务器访问却发现报错500,错误信息如下: 严重: Context initial ...

  5. 【Java】用Jackson进行JSON序列化/反序列化操作

    Java类和JSON Speaker类: import java.util.ArrayList; import java.util.Arrays; import java.util.List;publ ...

  6. Jackson:Cannot construct instance of **** (although at least one Creator exists):

    Jackson:nested exception is java.lang.IllegalArgumentException: Cannot construct instance of **** (a ...

  7. Jackson的简单用法

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1简介 Jackson具有比较高的序列化和反序列化效率,据测试,无论是 ...

  8. jackson - @JsonProperty的使用

    jackson的maven依赖 <dependency><groupId>com.fasterxml.jackson.core</groupId><artif ...

  9. Json学习总结(9)——放弃FastJson!Jackson的功能原来如此之牛

    什么是Jackson Jackson是比较主流的基于Java的JSON类库,可用于Json和XML与JavaBean之间的序列化和反序列化.没看错,Jackson也可以处理JavaBean与XML之间 ...

最新文章

  1. Python MemoryError 问题
  2. 基于卷积神经网络(CNN)的仙人掌图像分类
  3. Science:综述肠道菌群如何影响社交行为
  4. 浅谈 Python 的 with 语句
  5. 12、oracle数据库下的存储过程和函数
  6. 蓝军HVV实用工具和网站总结
  7. java系列4:数组初始化(省略格式)
  8. 各种乐器与人声的频率特性说明
  9. Windows系统下使用Jenkins自动化发布.NET core程序到Linux平台下利用Docker快速启动
  10. 动图展示16个Sublime Text快捷键用法 ---------------物化的sublime
  11. MongoDB 覆盖索引查询
  12. RS485转USB插电脑上通讯不上
  13. 西门子与源讯联手打造网络安全技术;全球首个5G全息国际通话打通 | IoT黑板报...
  14. C++关键字—this
  15. 教学目标四个维度_教学目标很重要
  16. 打卡记录根据排班表每人每日排班上下班时间自动获取结果打卡记录是属于那是区间
  17. 网络唤醒 php,php远程网络唤醒计算机及WOL唤醒魔术包格式原理
  18. 不错的每日站会的一个实践
  19. PreSonus Studio One 5 Professional v5.5.0 WiN-MAC 音乐制作宿主软件
  20. 计算机三级英语词汇,【2009年成人英语三级英语词汇短语表(M2)】- 环球网校...

热门文章

  1. 聚簇索引与非聚簇索引详解
  2. 《终极海报——23位创意大咖的设计评论与思想》目录—导读
  3. 360搜索蝴蝶效应:与搜狗必有一战 百度先布防
  4. Python第七章课后作业
  5. 实践-oracle中出现:ORA-00911: invalid character的问题
  6. 数据分析之Pandas变形操作总结
  7. 什么是mvc设计模式 (附代码示例)
  8. java spring getbean_spring getbean 方法分析(很实用!)
  9. 【分隔结构】主谓分离
  10. php编程使用的软件下载,php编程软件下载