kotlin1.8.10问题导致gson报错TypeToken type argument must not contain a type variable

news2024/10/7 16:20:01

书接上回,https://blog.csdn.net/jzlhll123/article/details/139302991。
之前我发现gson报错后:
gson在2.11.0给我的kotlin项目代码报错了。

IllegalArgumentException: TypeToken type argument must not contain a type variable

上次解释原因是因为,gson内部有了报错,根本原因就是二级嵌套泛型获取的解析方式问题。而且写下了解决办法和参考代码。 是错误的。
我后来又通过在demo工程中尝试,怎么都无法复现,困扰了我好几天。我又去研究了字节码和反编译。
最后发现,

public class ApiBean {
    public String type;
    public String name;
    public String url;
}

public class CmdBean<T>  { //T就可以传入ApiBean做为二层嵌套泛型
    public String cmdId;
    public long ts;
    public String pro;
    public T apiBean;
}

//二层嵌套解析 //暂时有问题。后面会讲到他没问题
inline fun <reified T> parse(jsonStr: String?): CmdBean<T>? {
    return jsonStr?.fromJson<CmdBean<T>>()
}

//二层嵌套解析 //暂时有问题。后面会讲到他没问题
inline fun <reified T> parseList(jsonStr: String?): List<T>? {
    return jsonStr?.fromJson<List<T>>()
}

//通用函数 //暂时有问题。后面会讲到他没问题
inline fun <reified T> String.fromJson(): T {
    return Globals.gson.fromJson(this, object : TypeToken<T>() {}.type)
}

class Action {
    fun test() {
        val json = """
{"apiBean":{"name":"nameX","type":"typeX","url":"htpps://api.....com/.../..xxx"},"cmdId":"cmdId010102394","pro":"aaaa","ts":1029301291023}
        """.trimIndent()
        val cmd = parse<ApiBean>(json)
        println("cmd $cmd")
    }

    fun testList() {
        val json = """
[{"name":"icon1","type":"type1","url":"https://.......png"},{"name":"icon2","type":"type2","url":"https://..xx.....png"}]
        """.trimIndent()
        val cmd = parseList<ApiBean>(json)
        println("list $cmd")
    }
}

上述代码是很简单的,主要就是有一个嵌套的解析:
parse<ApiBean>(json), parse函数内部,就是jsonStr?.fromJson<CmdBean<T>>()这样嵌套去解析。然后这个函数又经过一个普通的封装函数fromJson来解析。
在本地kotlin版本

 id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
 //也可能写作:
 kotlin = "1.8.10"
 jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

在1.8.10之下:
编译查看class:
请添加图片描述请添加图片描述请添加图片描述由此,我们就能知道为什么会报错了。原因就是字节码写了new出来的匿名内部类是个带T的,所以因为JVM上泛型擦除出现了T,gson的TypeToken就无法解析到真实的类,因此出现了问题。当我反复对比找各种原因,最后终于怀疑到了版本上。修改到kotlin1.8.20,kotlin1.9.0, kotlin 1.9.24均发现ok 了。对比的图如下:请添加图片描述
请添加图片描述
请添加图片描述
很明显,对于这种嵌套型的inline+reified从kotlin1.8.20开始,生成的内部类就不会再有问题。

并且,gson官方文档提到的解决方案:

Use TypeToken.getParameterized(...), for example TypeToken.getParameterized(List.class, elementType) where elementType is a type you have to provide separately.
For Kotlin users: Use reified type parameters, that means change <T> to <reified T>, if possible. If you have a chain of functions with type parameters you will probably have to make all of them reified.

其实对于kotlin项目而言,

inline fun <reified T> String.fromJson(): T {
    return Globals.gson.fromJson(this, object : TypeToken<T>() {}.type)
}

这个函数就是完美的,
你可以直接传入fromJson<List<Bean>(), 可以传入fromJson<CmdBean<InnerBean>()的形式,他就能给你处理好。
而1.8.10的kotlin,在inline+reified嵌套后就会出现问题。
大于1.8.10的kotlin版本,则可以嵌套传导正确,就不会出现问题了。

而非kotlin的java项目,你就不得不按照官方

public static <T> T parse(String jsonStr, Class<T> t) {
    return new GsonBuilder().create().fromJson(jsonStr, t);
}

public static <T, T2> MyCmd<T2> parseLv2(String jsonStr, Class<T> t, Class<T2> t2) {
    Type typeToken = TypeToken.getParameterized(t, t2).getType();
    return new GsonBuilder().create().fromJson(jsonStr, typeToken);
}

或者参考我上篇帖子https://blog.csdn.net/jzlhll123/article/details/139302991的三个解决方案。
java中就不会遇到kotlin编译内部类的问题了。而是可能会犯低级错误:
比如

        var json = """
{"apiBean":{"name":"nameX","type":"typeX","url":"htpps://api.....com/.../..xxx"},"cmdId":"cmdId010102394","pro":"aaaa","ts":1029301291023}
        """;
        var cmd = parse(json, CmdBean.class); //错误,没有提供二级泛型。需要TypeToken.getParameterized等方式解析。
        System.out.printf("cmd " + cmd);

		val listCmd = parse(json, List.class) //错误,没有提供二级泛型。需要TypeToken.getParameterized等方式解析。

而kotlin,由于inline和reified就可以解决它,前提是你要注意kotlin的版本哟,1.8.10有坑!1.8.20开始好的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1795834.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WALT算法简介

WALT(Windows-Assist Load Tracing)算法是由Qcom开发&#xff0c; 通过把时间划分为窗口&#xff0c;对 task运行时间和CPU负载进行跟踪计算的方法。为任务调度、迁移、负载均衡及CPU调频 提供输入。 WALT相对PELT算法&#xff0c;更能及时反映负载变化&#xff0c; 更适用于…

PasteCode系列系统说明

定义 PasteCode系列是指项目是基于PasteTemplate构建的五层以上项目&#xff0c;包括不仅限于 Domain EntityFrameworkCore Application.Contracts Application HttpApi.Host 熟悉ABP vNext就很好理解了&#xff0c;因为PasteTemplate就是基于ABP的框架精简而来&#xff01;在…

CVE-2022-4230

CVE-2022-4230 漏洞介绍 WP Statistics WordPress 插件13.2.9之前的版本不会转义参数&#xff0c;这可能允许经过身份验证的用户执行 SQL 注入攻击。默认情况下&#xff0c;具有管理选项功能 (admin) 的用户可以使用受影响的功能&#xff0c;但是该插件有一个设置允许低权限用…

绘画参数配置及使用

绘画参数配置及使用 路径&#xff1a;站点后台-功能-AI绘画 进入参数配置 接口选择&#xff1a;多种接口自主选择&#xff08;需自己准备key&#xff09;&#xff0c;对应接口的key对话和绘画通用 存储空间&#xff1a; 位置在超管后台-存储空间 自主选择存储&#xff08;需…

Python画图(多图展示在一个平面)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

Go实战 | 使用Go-Fiber采用分层架构搭建一个简单的Web服务

前言 &#x1f4e2;博客主页&#xff1a;程序源⠀-CSDN博客 &#x1f4e2;欢迎点赞&#x1f44d;收藏⭐留言&#x1f4dd;如有错误敬请指正&#xff01; 一、环境准备、示例介绍 Go语言安装&#xff0c;GoLand编辑器 这个示例实现了一个简单的待办事项&#xff08;todo&#xf…

应用解析 | 面向智能网联汽车的产教融合解决方案

背景介绍 随着科技的飞速发展&#xff0c;智能网联汽车已成为汽车产业的新宠&#xff0c;引领着未来出行的潮流。然而&#xff0c;行业的高速发展也带来了对高素质技术技能人才的迫切需求。为满足这一需求&#xff0c;推动教育链、人才链与产业链、创新链的深度融合&#xff0…

【Java】static 修饰变量

static 一种java内置关键字&#xff0c;静态关键字&#xff0c;可以修饰成员变量、成员方法。 static 成员变量 1.static 成员变量2.类变量图解3.类变量的访问4.类变量的内存原理5.类变量的应用 1.static 成员变量 成员变量按照有无static修饰&#xff0c;可以分为 类变量…

AGP8+ android.useNewApkCreator‘ is deprecated 打包失败

问题 新建一个项目&#xff0c;默认使用最新版的 AGP 和 Gradle&#xff0c;打包构建立马失败&#xff01; 错误日志 Caused by: com.android.builder.errors.EvalIssueException: The option android.useNewApkCreator is deprecated. An exception occurred applying plu…

STM32-16-ADC

STM32-01-认识单片机 STM32-02-基础知识 STM32-03-HAL库 STM32-04-时钟树 STM32-05-SYSTEM文件夹 STM32-06-GPIO STM32-07-外部中断 STM32-08-串口 STM32-09-IWDG和WWDG STM32-10-定时器 STM32-11-电容触摸按键 STM32-12-OLED模块 STM32-13-MPU STM32-14-FSMC_LCD STM32-15-DMA…

关于2024中国海洋装备博览会(福州)的参展通知

2024中国航洋装备博览会 2024世界航海装备大会 2024中国船舶供应链大会 2024中国航洋装备博览会2024世界航海装备大会 时间地点、规模、主题、定位 1.时间&#xff1a;2024年11月15日至18日 2.地点&#xff1a;福州海峡国际会展中心、冠城大通游艇码头 3.规模&#xff1…

Seed-TTS语音编辑有多强?对比实测结果让你惊叹!

GLM-4-9B 开源系列模型 前言 就在最近&#xff0c;ByteDance的研究人员最近推出了一系列名为Seed-TTS的大规模自回归文本转语音(TTS)模型,能够合成几乎与人类语音无法区分的高质量语音。那么Seed-TTS的表现究竟有多强呢?让我们一起来感受下Seed-TTS带来的惊喜吧! 介绍Seed-TTS…

Vivado 设置关联使用第三方仿真软件 Modelsim

目录 1.前言2.Vivado 设置关联使用第三方仿真软件 Modelsim 微信公众号获取更多FPGA相关源码&#xff1a; 1.前言 Vivado 软件自带有仿真功能,该功能使用还是比较方便的,初学者可以直接使用自带的仿真功能。 Modelsim仿真工具是Model公司开发的。它支持Verilog、VHDL以及他…

27 - 求关注者的数量(高频 SQL 50 题基础版)

27 - 求关注者的数量 selectuser_id,count(*) followers_count fromFollowers group byuser_id;

什么是阻塞IO和非阻塞IO

一、IO模型 五种&#xff1a;阻塞IO、非阻塞IO、多路复用IO、信号驱动IO、异步IO 1.阻塞IO&#xff1a;一个应用程序执行I/O操作时&#xff0c;会被阻塞&#xff0c;直到数据准备好或操作完成。这种模型通常简单易用&#xff0c;但会造成资源浪费。因为CPU在等待I/O操作完成时…

为什么要学习扣子(Coze)

&#x1f9d9;‍♂️ 诸位好&#xff0c;吾乃斜杠君&#xff0c;编程界之翘楚&#xff0c;代码之大师。算法如流水&#xff0c;逻辑如棋局。 &#x1f4dc; 吾之笔记&#xff0c;内含诸般技术之秘诀。吾欲以此笔记&#xff0c;传授编程之道&#xff0c;助汝解技术难题。 &#…

2024大模型如何学习【附学习资料】

摘要&#xff1a; 通过深入了解本文中的这些细节&#xff0c;并在实际项目中应用相关知识&#xff0c;将能够更好地理解和利用大模型的潜力&#xff0c;不仅在学术研究中&#xff0c;也在工程实践中。通过不断探索新方法、参与项目和保持热情&#xff0c;并将其应用于各种领域&…

【Spring框架全系列】SpringBoot_基础_先知(详细)

文章目录 1.SpringBoot介绍2.创建一个SpringBoot项目3.parent标签 - 父工程4.starter依赖5.启动类和文件打包6.默认配置 1.SpringBoot介绍 Spring阶段最困扰大家的事情是什么&#xff1f; 配置 → 配置魔鬼 快速搭建一个独立的生产级别的Spring应用 快速引入项目相关依赖 开箱…

开源!过程控制与自动化系统

软件介绍 ProviewR是一个基于GPL许可的过程控制与自动化系统&#xff0c;最初由瑞典的Mandator和SSAB Oxelsund开发。作为一个成熟、集成且低成本的自动化解决方案&#xff0c;ProviewR在以Linux作为操作系统的标准PC上运行。该系统包含了顺序控制、调整、数据采集、通信、监控…

16、matlab求导、求偏导、求定积分、不定积分、数值积分和数值二重积分

1、matlab求导&#xff0c;diff()函数 1&#xff09;一阶导数 语法&#xff1a;diff(f(x)):求一阶导数 //diff(f(x),n):求n阶导数(n为具体正整数) 以函数&#xff08;cos(x)sin(x)-x^2&#xff09;的一阶导数为例 一阶导数代码&#xff1a; yms x;%声明符号变量x f(x)cos(…