[alibaba/fastjson]kotlin在多线程下反序列化会报错

2025-11-13 149 views
5

kotlin 1.1.4-3 jdk 1.8-112 fastjson 1.2.38 场景是开多线程,反序列化同一个data class,使用的方法是JSON.parseObject(String, Class) 线程数在1-3的时候正常,从4个线程开始,出现报错: com.alibaba.fastjson.JSONException: default constructor not found. class com.haiziwang.platform.krediskt.common.pojo.info.Server at com.alibaba.fastjson.util.JavaBeanInfo.build(JavaBeanInfo.java:409) at com.alibaba.fastjson.util.JavaBeanInfo.build(JavaBeanInfo.java:175) at com.alibaba.fastjson.parser.ParserConfig.createJavaBeanDeserializer(ParserConfig.java:602) at com.alibaba.fastjson.parser.ParserConfig.getDeserializer(ParserConfig.java:519) at com.alibaba.fastjson.parser.ParserConfig.getDeserializer(ParserConfig.java:341) at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:623) at com.alibaba.fastjson.JSON.parseObject(JSON.java:348) at com.alibaba.fastjson.JSON.parseObject(JSON.java:252) at com.alibaba.fastjson.JSON.parseObject(JSON.java:471)

跟了下代码,发现应该是TypeUtils.getKoltinConstructorParameters(Class)这个方法的问题 刚进入这个方法,TypeUtils类中kotlin_kclass_constructor属性就不为空,但是kotlin_kclass_getConstructors为空,导致在TypeUtils.java的2091行报错空指针,导致这个方法返回null,然后出现上述问题

回答

5

附上我报错的data class,就是封装了redis命令:info Server的返回内容

data class Server(
        @JSONField(name = "redis_version")
        var redisVersion: String? = null,

        @JSONField(name = "redis_git_sha1")
        var redisGitSha1: String? = null,

        @JSONField(name = "redis_git_dirty")
        var redisGitDirty: String? = null,

        @JSONField(name = "redis_build_id")
        var redisBuildId: String? = null,

        @JSONField(name = "redis_mode")
        var redisMode: String? = null,

        var os: String? = null,

        @JSONField(name = "arch_bits")
        var archBits: String? = null,

        @JSONField(name = "multiplexingApi")
        var multiplexing_api: String? = null,

        @JSONField(name = "gcc_version")
        var gccVersion: String? = null,

        @JSONField(name = "process_id")
        var processId: Int? = null,

        @JSONField(name = "run_id")
        var runId: String? = null,

        @JSONField(name = "tcp_port")
        var tcpPort: Int? = null,

        @JSONField(name = "uptime_in_seconds")
        var uptimeInSeconds: Int? = null,

        @JSONField(name = "uptime_in_days")
        var uptimeInDays: Int? = null,

        var hz: String? = null,

        @JSONField(name = "lru_clock")
        var lruClock: String? = null,

        @JSONField(name = "config_file")
        var configFile: String? = null
)
3

TypeUtils.getKoltinConstructorParameters(Class)这个方法貌似确实不是线程安全的,主要是方法里使用到的几个静态变量的初始化问题

5

不应该哈,报错应该是别的原因导致的

5

我的整个代码只调整了线程数,其他都没有动,当线程数变大后,开始出现这个异常的,也通过断点跟踪了代码,确实是TypeUtils类中kotlin_kclass_constructor属性就不为空,但是kotlin_kclass_getConstructors为空,导致在TypeUtils.java的2091行报错空指针

TypeUtils.getKoltinConstructorParameters(Class)这个方法所初始化的那几个静态变量,只是各自是volatile的,但是整个方法并不是线程安全啊,我觉得原因可能是出在这

6

我写了个测试例子,线程数小的时候(<3),出现的概率很小,基本可以正常执行,但是线程数调大(>10),基本是必现,@wenshao 你可以用这个试试看

const val THREAD_NUMBER = 10

fun main(args: Array<String>) {
    val threadPool = Executors.newScheduledThreadPool(THREAD_NUMBER)
    for (i in 1..THREAD_NUMBER) {
        println("start....")
        threadPool.scheduleAtFixedRate({
            val map = mapOf("id" to 1, "name" to "test1")
            try {
                println(JSON.parseObject(JSON.toJSONString(map), User::class.javaObjectType))
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }, 1, 1, TimeUnit.SECONDS)
    }
}

data class User(val id: Int, val name: String)
6

我写了测试,问题没有重现

0

你这个例子是java写的哇,我这个问题是使用kotlin调用时出现的,我上面发的那段代码,问题是必现的呀

3

问题重现并修复,非常感谢反馈问题