[Bug]:data class 默认值碰到的问题
框架版本【必填】
9.6
问题描述【必填】
Kotlin data class 里设置的默认值在 agp 版本升级到 8.7.0 后开启混淆打包默认值都会失效,我之前的 agp 版本是 8.5.0,没有这个问题
复现步骤【必填】
agp 升级到 8.7.0 就行
是否必现【必填】
是
项目 targetSdkVersion【必填】
34
出现问题的手机信息【必填】
Redmi K50 Ultra
出现问题的安卓版本【必填】
Android 14
问题信息的来源渠道【必填】
自己遇到的
是部分机型还是所有机型都会出现【必答】
所有机型
框架最新的版本是否存在这个问题【必答】
是
框架文档是否提及了该问题【必答】
否
是否已经查阅框架文档但还未能解决的【必答】
是
issue 列表中是否有人曾提过类似的问题【必答】
否
是否已经搜索过了 issue 列表但还未能解决的【必答】
是
是否可以通过 Demo 来复现该问题【必答】
是
提供报错堆栈
No response
提供截图或视频
No response
提供解决方案
No response
@skywolfwen 如果不用框架进行解析,你在 data class 定义的默认值是否也能生效?
@skywolfwen 如果不用框架进行解析,你在 data class 定义的默认值是否也能生效?
那不行,默认的gson不支持这个功能
@skywolfwen 如果不用框架进行解析,你在 data class 定义的默认值是否也能生效?
那不行,默认的gson不支持这个功能
我的意思是不用解析框架,直接 new 一个 data class 对象默认值是否能生效?
@skywolfwen 如果不用框架进行解析,你在 data class 定义的默认值是否也能生效?
那不行,默认的gson不支持这个功能
我的意思是不用解析框架,直接 new 一个 data class 对象默认值是否能生效?
new 的对象默认值是生效的
@getActivity 我发现好像是因为有些属性有默认值,有些属性没有默认值才有这个问题,如果属性都有默认值那解析也是没问题的
@getActivity 我发现好像是因为有些属性有默认值,有些属性没有默认值才有这个问题,如果属性都有默认值那解析也是没问题的
没听懂你这句话是什么意思?
@getActivity 我发现好像是因为有些属性有默认值,有些属性没有默认值才有这个问题,如果属性都有默认值那解析也是没问题的
没听懂你这句话是什么意思?
就是一个data class里,并不是所有属性都设置了默认值,有些属性是需要在创建对象时必须明确传值的,这种data class在agp 8.7.0然后开启代码混淆的情况下使用框架解析默认值会失效,但如果所有属性都设置了默认值那在同等条件下使用框架解析默认值是生效的
我测试发现是没有问题的,data class 默认值都是生效的。
我测试发现是没有问题的,data class 默认值都是生效的。
Android Studio 是最新的 Ladybug 这个版本,build.gradle 中是8.7.0,gradle-wrapper.properties 中是8.9。如果在这种环境下您测试还是没问题,那我过两天给您发个demo
@getActivity
GsonDemo.zip
试试这个demo可以复现不
你这种写法本身存在问题,userId 是不可变的常量,类型为 String 的写法代表值不能为空,但是你在 data class 类中字段上面没有给它赋值。
你这种写法本身存在问题,userId 是不可变的常量,类型为 String 的写法代表值不能为空,但是你在 data class 类中字段上面没有给它赋值。
因为想要的效果是这个属性值完全由接口返回值来赋值。不过即便这种写法有问题,那框架在agp 8.5.0下也能赋上默认值,估计是升级插件版本后某些东西被混淆了,因为安装包都比以前小了些。当然如果您觉得这样不算是bug,那我也可以都加上默认值避免这个问题,只是不知道能否在文档里说明一下
我最近针对这个问题进行了反复测试和验证,最终得出以下结论:
-
这个问题出现 Gradle Android 插件(高版本名称为
com.android.application低版本名称为com.android.tools.build:gradle)在8.6.0及以上的版本会出现,之前的版本不会出现,例如8.5.0版本不会有该问题,另外这个问题和纯 Gradle 版本没有关系,只和 Gradle Android 插件有关系。 -
问题出现的原因是在于,这个 Gradle Android 高版本的插件会去除 kotlin data class 类字节码中的 Metadata 信息,间接导致
org.jetbrains.kotlin:kotlin-reflect这个库在获取不到kotlin data class类的主函数(rawTypeKotlin.primaryConstructor),最终导致框架无法通过KotlinDataClassDefaultValueConstructor类创建 kotlin data class 类。
- 另外解答一个疑问,为什么你提供的 demo 工程里面的
LoginResult类为什么没有正常解析出来kotlin data class的默认值,而LoginResult2类却可以正常解析出来呢?它本质上不是通过KotlinDataClassDefaultValueConstructor类来创建kotlin data class类对象的,原本就应该交给它创建才对,但是因为它判断到kotlin data class类的主函数(rawTypeKotlin.primaryConstructor)为空就不往下执行了,接下来就是框架分别交由了ReflectSafeCreatorConstructor和ReflectCreatorConstructor类来创建对象,这两个类最根本的区别就是,ReflectCreatorConstructor类是负责创建那种空参的构造函数;而ReflectSafeCreatorConstructor类是负责的创建那种没有空参的构造函数,但是仅限只是简单粗暴创建对象,不会对类的字段进行初始化;由于你在LoginResult类定义的userId字段写法不准确,导致运行过程找不到空参的构造函数(可能是编译过程就没有生成,但是这个不是重点),所以交给了ReflectSafeCreatorConstructor类去创建,而LoginResult2类因为所有字段的写法都没有问题,在运行过程能找到对应空参的构造函数, 所以交给了ReflectCreatorConstructor类创建对象。
- 关于这个问题的解决方案,目前框架无法代码的方式来兼容该问题,只能在文档中注明该问题提醒后面使用的人。
我最近针对这个问题进行了反复测试和验证,最终得出以下结论:
- 这个问题出现 Gradle Android 插件(高版本名称为
com.android.application低版本名称为com.android.tools.build:gradle)在8.6.0及以上的版本会出现,之前的版本不会出现,例如8.5.0版本不会有该问题,另外这个问题和纯 Gradle 版本没有关系,只和 Gradle Android 插件有关系。- 问题出现的原因是在于,这个 Gradle Android 高版本的插件会去除 kotlin data class 类字节码中的 Metadata 信息,间接导致
org.jetbrains.kotlin:kotlin-reflect这个库在获取不到kotlin data class类的主函数(rawTypeKotlin.primaryConstructor),最终导致框架无法通过KotlinDataClassDefaultValueConstructor类创建 kotlin data class 类。
![]()
3. 另外解答一个疑问,为什么你提供的 demo 工程里面的
LoginResult类为什么没有正常解析出来kotlin data class的默认值,而LoginResult2类却可以正常解析出来呢?它本质上不是通过KotlinDataClassDefaultValueConstructor类来创建kotlin data class类对象的,原本就应该交给它创建才对,但是因为它判断到kotlin data class类的主函数(rawTypeKotlin.primaryConstructor)为空就不往下执行了,接下来就是框架分别交由了ReflectSafeCreatorConstructor和ReflectCreatorConstructor类来创建对象,这两个类最根本的区别就是,ReflectCreatorConstructor类是负责创建那种空参的构造函数;而ReflectSafeCreatorConstructor类是负责的创建那种没有空参的构造函数,但是仅限只是简单粗暴创建对象,不会对类的字段进行初始化;由于你在LoginResult类定义的userId字段写法不准确,导致运行过程找不到空参的构造函数(可能是编译过程就没有生成,但是这个不是重点),所以交给了ReflectSafeCreatorConstructor类去创建,而LoginResult2类因为所有字段的写法都没有问题,在运行过程能找到对应空参的构造函数, 所以交给了ReflectCreatorConstructor类创建对象。
![]()
![]()
![]()
4. 关于这个问题的解决方案,目前框架无法代码的方式来兼容该问题,只能在文档中注明该问题提醒后面使用的人。
辛苦大神了,解释得非常详细。之后的使用中我也会注意用法的,库很好用,帮我免了很多隐患
3. 另外解答一个疑问,为什么你提供的 demo 工程里面的
4. 关于这个问题的解决方案,目前框架无法代码的方式来兼容该问题,只能在文档中注明该问题提醒后面使用的人。