当前位置: 首页 > news >正文

【java基础】根据泛型动态构造jackson的TypeReference(json反序列化为带泛型的类的对象)

根据泛型动态构造jackson的TypeReference

  • 引出问题
  • 使用TypeReference反序列化的例子
  • 根据泛型动态构造TypeReference
    • 带泛型的类如何表示?
    • 完成HttpClient的实现

引出问题

  1. 将json字符串反序列化为带泛型的类的对象怎么操作?
  2. 怎么根据TypeReference<List<People>>对象动态构造TypeReference<Result<List<People>>>对象

使用TypeReference反序列化的例子

有以下类定义:

class Result<T> {private long code;private T data;
}class People {private String name;
}

实例化以下对象:

Result<List<People>> result = new Result<>();
List<People> peopleList = new ArrayList<>();
People xiaoHong = new People("小红");
People xiaoMing = new People("小明");
peopleList.add(xiaoHong);
peopleList.add(xiaoMing);
result.setData(peopleList);

其对应的JSON字符串为:

{"code":0,"data":[{"name":"小红"},{"name":"小明"}]}

下面使用jackson的TypeReference来反序列化字符串为以上的对象:

String jsonStr =  "{\"code\":0,\"data\":[{\"name\":\"小红\"},{\"name\":\"小明\"}]}";
TypeReference<Result<List<People>>> typeReference = new TypeReference<Result<List<People>>>() {};
ObjectMapper objectMapper = new ObjectMapper();
Result<List<People>> listResult = objectMapper.readValue(jsonStr, typeReference);

当我们构造http客户端的时候,有时候不想让用户看到类似Result<List<People>>这样的返回,只想给用户List<People>这样的数据,那怎么动态构造TypeReference呢?

根据泛型动态构造TypeReference

假设我们提供了一个http客户端工具,它的定义是这样的。

class HttpClient {public <T> T get(String url, Map<String,Object> params, TypeReference<T> typeR) {//获取jsonStr, 假设这里获取到的是:{"code":0,"data":[{"name":"小红"},{"name":"小明"}]}String jsonStr = execute(url, params);//todo 解析为枚举类型,下面会讲解如何实现}
}

假设我们这样调用HttpClient:

HttpClient client = new HttpClient();
//注意这里的TypeReference的泛型
List<People> result = client.get("http://xxxx", params, new TypeReference<List<People>>());

额额额???为啥不是TypeReference<Result<List<People>>> ???
这就是我们要达到的目的,即用户不关注外层包裹的Result,只需要指定实际想要的类型即可。下面我们来看下如何实现。

带泛型的类如何表示?

首先我们实现一个ParameterizedType的子类,至于这个类的作用请往下看:

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;public class ParameterizedTypeImpl implements ParameterizedType, Serializable {private final Type[] actualTypeArguments;private final Type ownerType;private final Type rawType;public ParameterizedTypeImpl(Type[] actualTypeArguments, Type ownerType, Type rawType) {this.actualTypeArguments = actualTypeArguments;this.ownerType = ownerType;this.rawType = rawType;}@Overridepublic Type[] getActualTypeArguments() {return this.actualTypeArguments;}@Overridepublic Type getRawType() {return this.rawType;}@Overridepublic Type getOwnerType() {return this.ownerType;}
}

我们来解释一下这个类,先看一下这个类的继承链:

ParameterizedTypeImpl implements ParameterizedType extends Type
  • Type接口的语义是指:类型,标识java里的所有类。(注意:Class类也是Type的实现类,下面会用到)
  • ParameterizedType接口的语义是:带泛型的类。

在java9之前jdk是包含了ParameterizedTypeImpl的实现的,但在jdk9及以后就没了,所以保险起见我们自己需要实现一下。

我们再看一下TypeReference的定义:

public abstract class TypeReference<T> implements Comparable<TypeReference<T>> {protected final Type _type;protected TypeReference() {Type superClass = this.getClass().getGenericSuperclass();if (superClass instanceof Class) {throw new IllegalArgumentException("Internal error: TypeReference constructed without actual type information");} else {this._type = ((ParameterizedType)superClass).getActualTypeArguments()[0];}}public Type getType() {return this._type;}public int compareTo(TypeReference<T> o) {return 0;}
}

这里的_type成员变量即ParameterizedTypeImpl类型。

我们继续看ParameterizedTypeImpl几个成员变量的意思:(此处以:new TypeReference<Result<List<People>>>为例)

  • rawType
    此处的rowType=Result.class,即原始的类是什么
  • actualTypeArguments
    此处的actualTypeArguments=new Type[]{List<People>.class},为什么是数组类型,是因为泛型里面可以放多个类型,我可以这么放:Result<List<People>,Set<People>>,那么这里的actualTypeArguments=new Type[]{List<People>.class,Set<People.class>},因为是一个Type数组,而每个Type又是一个ParameterizedType,所以可以向下继续查看(嵌套)。
  • ownerType
    所谓的ownerType只在嵌套类中会出现,其他情况为空。举个例子:I<T>.S<E>,则S<E>ownerType=I<T>

完成HttpClient的实现

class HttpClient {public <T> T get(String url, Map<String,Object> params, TypeReference<T> typeR) {//获取jsonStr, 假设这里获取到的是:{"code":0,"data":[{"name":"小红"},{"name":"小明"}]}String jsonStr = execute(url, params);ObjectMapper objectMapper = new ObjectMapper();//在此处偷梁换柱TypeReference<Result<T>> resultType = new TypeReference<Result<T>>>() {@Overridepublic Type getType() {//在外层再包一层Result,就是所谓的动态构造,是不是很简单!!!return new ParameterizedTypeImpl(new Type[]{typeR.getType()},null, Result.class);}};Result<T> listResult = objectMapper.readValue(jsonStr, resultType);//此处省略了一下异常判断,不可直接这么使用return listResult.getData();}
}

然后我们就可以这么调用了:

HttpClient client = new HttpClient();
//注意这里的TypeReference的泛型
List<People> result = client.get("http://xxxx", params, new TypeReference<List<People>>());

OK,完结!

相关文章:

【java基础】根据泛型动态构造jackson的TypeReference(json反序列化为带泛型的类的对象)

根据泛型动态构造jackson的TypeReference引出问题使用TypeReference反序列化的例子根据泛型动态构造TypeReference带泛型的类如何表示&#xff1f;完成HttpClient的实现引出问题 将json字符串反序列化为带泛型的类的对象怎么操作&#xff1f;怎么根据TypeReference<List<…...

为什么VMware会给我多创建了两个网络呢?Windows和Linux为什么可以彼此ping的通呢

为什么VMware会给我多创建了两个网络呢&#xff1f;Windows和Linux为什么可以彼此ping的通呢 文章目录为什么VMware会给我多创建了两个网络呢&#xff1f;Windows和Linux为什么可以彼此ping的通呢桥接模式ANT模式&#xff08;VMnet8&#xff09;仅主机模式&#xff08;VMnet1&a…...

服务器带宽承载多少人同时访问计算方法-浏览器中查看当前网页所有资源数据大小-客服系统高并发承载人数【唯一客服】...

浏览器中怎么查看当前网页所有资源的数据大小 在开发者工具的“网络”选项卡中&#xff0c;可以看到所有请求和响应的详细信息&#xff0c;包括每个资源的大小。如果需要查看网页所有资源的总大小&#xff0c;可以按照以下步骤操作&#xff1a; 打开要查看的网页。打开开发者工…...

给新手----编译VSOMEIP保姆级别教程

前言&#xff1a;当你学习了SOMEIP理论基础后&#xff0c;一定很希望上手实操一波吧&#xff0c;本文档以SOMEIP协议里比较成熟的VSOMEIP开源框架为例&#xff0c;带你从0到1实现开源框架的下载到上手&#xff0c;坐稳啦&#xff0c;开车&#xff01;&#xff01;&#xff01;&…...

MarkDown设置上下标

上标&#xff1a;$a^{2-5}$ 下标&#xff1a;$a_{n-1}$显示&#xff1a;结果 上标&#xff1a;a2−5a^{2-5}a2−5 下标&#xff1a;an−1a_{n-1}an−1​ 如果上下标中需要多个显示&#xff0c;需要用{}括起来&#xff0c;否则就像下面一样 上标&#xff1a;$a^2-5$ 下标&…...

Python批量爬取游戏卡牌信息

文章目录前言一、需求二、分析三、处理四、运行结果前言 本系列文章来源于真实的需求本系列文章你来提我来做本系列文章仅供学习参考阅读人群&#xff1a;有Python基础、Scrapy框架基础 一、需求 全站爬取游戏卡牌信息 二、分析 查看网页源代码&#xff0c;图片资源是否存在…...

什么是PCB走线的3W原则

在设计PCB的时候我们会经常说到3W原则&#xff0c; 它指的是两个PCB走线它们的中心间距不小于3倍线宽&#xff0c;这个W就是PCB走线的宽度。这样做的目的主要是为了减小走线1和走线2之间的串扰&#xff0c;一般对于时钟信号&#xff0c;复位信号等一些关键信号需要遵循3W原则。…...

计算机网络面试总结

计算机网络 1.计算机网络 2.计算机网络拓扑结构 3.计算机网络覆盖 4.时延 5.交换技术 6.单工、半双工、全双工 7.OSI模型 8.TCP/IP模型 9.物理层有哪些设备 10.数据链路层介质访问控制 11.数据链路层有哪些设备 12.数据链路层流量控制 13.数据链路层的三个基本问题和解决方法 1…...

VsCode SSH远程连接服务器【内网穿透公网连接】

文章目录1.前言2.VS code的安装和设置2.1 VS code的下载安装2.2 OpenSSH的启用2.3 为VS code配置ssh2.4 局域网内测试VS code的ssh连接2.5 Cpolar下载安装3.Cpolar端口设置3.1 Cpolar云端设置3.2 Cpolar本地设置4.公网访问测试5.结语1.前言 记得笔者小时候看电视&#xff0c;看…...

十八、动画与canvas

1.RequestAnimationFrame 早期定时动画 setTimeout和setInterval不能保证时间精度&#xff0c;第二个参数只能保证何时将代码添加到浏览器的任务队列 requestAnimationFrame(cb)的cb在浏览器重绘屏幕前调用 function updateProgress(){const div document.getElementById(d…...

自动化测试学习-Day4-selenium的安装和8种定位方法

哈喽&#xff0c;大家好&#xff01; 本人21年毕业&#xff0c;软件工程专业&#xff0c;毕业后一直从事金融行业的软件测试。 希望大家一起见证一名卑微测试的成长之路。 目录 一、环境准备 1.浏览器下载 2.浏览器驱动下载 3.下载selenium 二、Selenium定位元素的8种方法…...

【Kubernetes】第二十五篇 - 布署 nodejs 后端项目(下)

一&#xff0c;前言 上一篇&#xff0c;介绍了部署后端项目之前&#xff0c;需要的准备的相关配置信息&#xff1b; 本篇&#xff0c;创建 Deployment、Service 完成后端项目布署&#xff1b; 二&#xff0c;解决 jenkins 安全问题 构建 docker 镜像之后&#xff0c;登录 do…...

贪心算法之区间问题总结

一、跳跃游戏跳跃游戏类的问题&#xff0c;不关心每一步怎么跳&#xff0c;只需要关心最大覆盖范围这里注意i是在当前最大可覆盖范围内遍历&#xff0c;如{2,1,0,1}&#xff0c;就是在0~2范围内遍历&#xff0c;千万不能0~numsSize-1范围内遍历&#xff01;&#xff01;&#x…...

无线WiFi安全渗透与攻防(七)之WIFI07-WEP-wifite自动化渗透WEP加密

WIFI07-WEP-wifite自动化渗透WEP加密 1.wifite介绍 wifite是一款自动化wep、wpa以及wps破解工具&#xff0c;不支持windows和osx。wifite的特点是可以同时攻击多个采用wep和wpa加密的网络。wifite只需简单的配置即可自动化运行&#xff0c;期间无需人工干预。 目前支持任何li…...

震撼,支持多模态模型的ChatGPT 4.0发布了

最近几个月&#xff0c;互联网和科技圈几乎ChatGPT刷屏了&#xff0c;各种关于ChatGPT的概念和应用的帖子也是围绕在周围。当去年年底ChatGPT发布的那几天&#xff0c;ChatGPT确实震撼到了所有人&#xff0c;原来AI还可以这么玩&#xff0c;并且对国内的那些所谓的人工智能公司…...

IDEA常用插件列表

一 背景 IDEA常用插件列表&#xff0c;用来提供工作效率。你都安装了吗 IntelliJ IDEA 默认安装并提供了非常多的工具&#xff0c;比如 Maven Integration、Markdown support、SSH Remote Run 等。其中有很多好用&#xff0c;但是不为人知的工具。 二 插件列表 阿里代码规约…...

比df更好用的命令!

大家好&#xff0c;我是良许。 对于分析磁盘使用情况&#xff0c;有两个非常好用的命令&#xff1a;du 和 df 。简单来说&#xff0c;这两个命令的作用是这样的&#xff1a; du 命令&#xff1a;它是英文单词 disk usage 的简写&#xff0c;主要用于查看文件与目录占用多少磁…...

【Git使用学习】记录学习过程(1)

安装就省略了&#xff0c;安装结果如下。 Git Bash&#xff1a;这是一个模拟Linux环境的命令行工具&#xff0c;可以使用Git的所有功能。Git GUI&#xff1a;这是一个图形化界面的工具&#xff0c;可以方便地执行Git的常用操作。Git CMD&#xff1a;这是一个Windows命令行工具&…...

K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示

K_A18_001 基于STM32等单片机采集MQ2传感参数串口与OLED0.96双显示一、资源说明二、基本参数参数引脚说明三、驱动说明IIC地址/采集通道选择/时序对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCMQ2传感参模块1.2、STM32F103C8T6MQ2传感参模块五、基础知识学习与相关…...

【云原生·Docker】常用命令

目录 &#x1f341;1、管理命令 &#x1f341;2、帮助命令 &#x1f341;3、镜像命令 &#x1f341;4、容器命令 &#x1f342;4.1.查看容器 &#x1f342;4.2.创建容器 &#x1f342;4.3.删除容器 &#x1f342;4.4.拷贝文件 &#x1f342;4.5.查看容器IP &#x1f341;5、部署…...

DockerHub与私有镜像仓库在容器化中的应用与管理

哈喽&#xff0c;大家好&#xff0c;我是左手python&#xff01; Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库&#xff0c;用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

ESP32读取DHT11温湿度数据

芯片&#xff1a;ESP32 环境&#xff1a;Arduino 一、安装DHT11传感器库 红框的库&#xff0c;别安装错了 二、代码 注意&#xff0c;DATA口要连接在D15上 #include "DHT.h" // 包含DHT库#define DHTPIN 15 // 定义DHT11数据引脚连接到ESP32的GPIO15 #define D…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

管理学院权限管理系统开发总结

文章目录 &#x1f393; 管理学院权限管理系统开发总结 - 现代化Web应用实践之路&#x1f4dd; 项目概述&#x1f3d7;️ 技术架构设计后端技术栈前端技术栈 &#x1f4a1; 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 &#x1f5c4;️ 数据库设…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)

第一篇&#xff1a;Liunx环境下搭建PaddlePaddle 3.0基础环境&#xff08;Liunx Centos8.5安装Python3.10pip3.10&#xff09; 一&#xff1a;前言二&#xff1a;安装编译依赖二&#xff1a;安装Python3.10三&#xff1a;安装PIP3.10四&#xff1a;安装Paddlepaddle基础框架4.1…...

使用SSE解决获取状态不一致问题

使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件&#xff0c;这个上传文件是整体功能的一部分&#xff0c;文件在上传的过程中…...