IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> jackson的readValue和convertValue方法 -> 正文阅读

[开发工具]jackson的readValue和convertValue方法

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 {
    //bean
    User uu1 = new ObjectMapper().readValue(jsonStr, new TypeReference<User>(){});
    System.out.println(uu1); //User(name=a, nameEn=b)
    //map
    Map 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 无法构造
        
        //map
        Map<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>>
        
        //先构造内部结构innerType
        JavaType 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}}]
        
        //先构造右边部分rightType
        JavaType 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的value
    JavaType 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);

i例如:

// 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 > map
    User 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 > bean
    User 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 map
    Map describe = new BeanMap(u);
    System.out.println(describe); //BeanMap<JsonUtils.User(name=aaa, nameEn=bbb)>
    
    //bean to map
    Map<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 bean
    User 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

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2022-03-30 18:46:03  更:2022-03-30 18:49:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:49:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码