假设有如下代码
data class Data(
val a: Int,
val b: Int=20
)
其中参数b有个默认值,如果我们定义一个json字符串,假设如下
val json="""{"a":45,"b":60}"""
那么,如果进行反序列化,时成功的
JSON.parseObject(json,Data::class.java)
这行代码能得到正确的结果,b的值是60
但是,假设我们的json字符串如下
val json="""{"a":45}"""
注意,和上面相比,去掉了b这个参数,那么,在没有提供b参数的情况下,我们希望b采用的是默认值,20,但是实际情况是,b的值为0,
如果b的类型比较特殊,比如是时间类型Date,那么就会直接抛出异常了,比如以下代码
data class Data(
val a: Int,
val b: Date=Date()
)
val json="""{"a":45}"""
val value = JSON.parseObject(json,Data::class.java)
如果调用,则直接抛出create instance error
Exception in thread "main" com.alibaba.fastjson.JSONException: create instance error, [Ljava.lang.String;@792b749c, public aaaa.Data(int,java.util.Date)
at ...........
12条答案
按热度按时间iih3973s1#
@lee87902407@wenshao 这个问题在fastJSON和GSON里都存在,确实应该提供这种策略,比如
{"a":45, "b":null}
,这时候,我可能想忽略掉b的null值,因为我认为null是无实际意义的,解析的时候,应该提供忽略null的这种策略,而且能够使用编写类的时候提供的默认值,而不是让fastjson赋一个默认值。当然,有的人会把null当成一种特定意义的情况,但是不建议这么用,因为对于kotlin的NULL safe和@NotNull造成破坏。umuewwlo2#
这个问题好像卡很久了,目前就是所有在data class构造函数创建参数都必须传入,如果需要可选的话只能放到body里面, @wenshao 大佬这个什么时候能修复呀 等好久了的
wbrvyc0a3#
@fangzhengjin 试一试加上@JVMOverloads
eivgtgni4#
@leleliu008 之前都试过了...目前暂时替代方法只能是将所有data class主构造函数中的字段都设置默认值,如果用到jpa的话还需要自己引入noarg插件
wlzqhblo5#
@fangzhengjin 您上面的例子有一处错误,应该是如下的写法:
我好奇的是,您为什么要这么写?虽然
Kotlin
语法允许这么写。为啥不写成如下:通常,我们的实体类不是自己手写的,而是使用工具生成的,因为实体类都是根据数据库或者定义好的协议自动生成的,往往生成的就是我的第二种写法,为了保持住
Kotlin
的NullSafty
这个特性,每个属性都会提供一个默认值,这是因为当Kotlin
的每个属性都有默认值的时候,编译时候就会自动生成无参数的构造方法,而fastJSON
和GSON
在反序列化的时候,它要构造示例出来的时候,首先检测有没有默认的构造方法,有的话就会反射那个无参数的构造方法,然后才是一个属性一个属性的反射设置的。另外:
翻译成
Java
就是如下的代码:其他的
getter
、setter
方法我没有写,otherField
这个属性实际上默认值就是null
,而在kotlin
里你的写法似乎想让它不是null
,这就矛盾了。rqdpfwrv6#
@leleliu008 otherField这个字段确实是表达有误,那我们可以只看构造函数部分
如果field1字段没有设置默认值,如果我使用下面的json串进行反序列化时,将会出现无法示例化的错误,即构造器要求提供三个参数
constructor(String, String, Int)
如果想使用FastJson反序列化只能
但是在使用jackjson时, 对kotlin提供了良好的互操作, 不会出现上述问题
7xzttuei7#
@fangzhengjin 这是因为
fastJSON
在没有默认的构造函数的时候,去尝试反射其他的构造函数导致的,所以,如果你想使用fastJSON
,还想不出错,最好的实践就是全部都提供默认的值,这就就不会有任何问题。我比较好奇的是,为啥不提供默认值?这个也不用您手写,都是工具生成的。
至于为啥
fastJSON
这么设计,可能他是出于效率的考虑,也或者是它压根儿就没有考虑到,总之,这个我们不得而知。如果您想使用这个库,就得接受这个事实。毕竟,fastJSON
引以为傲的是它的反序列化速度,多加一些功能进去就意味着很可能会降低速度,所以,他会作出一些取舍。您可以考虑使用https://github.com/square/moshi,这个库不会出现此问题。对
Kotlin
很友好,但是这些库都存在一个问题,就是在反序列化的时候,不能忽略null
,你非得修改他们的源代码不可,不过修改起来也很容易的。vfwfrxfs8#
@leleliu008
1、因为我们开发的项目中普遍使用JPA, 所以实体类是手工创建的, 数据库是自动创建的,所以必要参数不提供默认值,因为不允许为空.
2、我觉得应该是设计没有考虑到,我看是用java反射直接创建的,获取到的构造器可能不是预期的,毕竟有其他先例在前,实现肯定是没问题的
41zrol4v9#
@fangzhengjin
1、你们使用的是
Spring Data JPA
,它根据实体类自动创建数据库的表,这个我明白,但是,难到不事先进行数据库的设计吗?一般的数据库设计软件都有导出各种语言和各种结构化数据的插件。我指的是这个,当然,以前不使用自动创建数据库表的时候,连接上数据库也能直接从数据库表生成实体类。2、
所以必要参数不提供默认值,因为不允许为空
,这句话没理解,我觉得提供默认值和null
不冲突的嘛,现在我不明白的是,您纠结在构造函数上还是null
的问题上,实际上,您提供默认值最好不要是null
,就是您的代码里压根儿不要使用null
,字符串儿使用"",数字使用-1、0,之类的不就可以了嘛new9mtju10#
请问这个问题什么时候能解决?
当json为
{content: "test"}
时,在Android中会直接报异常崩溃create instance error
(与issue中的异常一致),gmtCreate如果设为Date?(可为null的类型),就可以运行,但是要在程序中判断是否为空,并且gmtCreate的默认值也失去了作用。希望尽快解决!谢谢
k2fxgqgv11#
@15050050972
{content: 'test'}
并不是标准的JSON
,标准的JSON
字符串应该用双引号,你用的单引号。to94eoyn12#
@leleliu008 问题1,2已经修改。
3:没有强迫
4:曲线救国,治标不治本
多谢建议