Jackson在Kotlin下全局自定义序列化器Long转String不生效

起因

雪花算法生成的主键传到前段后发生精度丢失,例如后端传入1397844263642378242,前端接收后变成1397844263642378000

因为Number的精度是16位,而雪花ID是19位

找了网上很多Java下配自定义序列化器的,改成Kotlin语法,如下

@Configuration
class JacksonConfig {
    @Bean
    fun jacksonObjectMapper(builder: Jackson2ObjectMapperBuilder): ObjectMapper {
        val objectMapper: ObjectMapper = builder.createXmlMapper(false).build()
        val simpleModule = SimpleModule()
            .addSerializer(Long::class.java, ToStringSerializer.instance)
            .addSerializer(java.lang.Long.TYPE, ToStringSerializer.instance)
        objectMapper.registerModule(simpleModule)
        return objectMapper
    }
}

在Kotlin下怎么试都不生效,但是在字段上指定就可以

@JsonSerialize(using=ToStringSerializer.class)
val id: Long?;

解决

中文互联网找了几遍没找到,去SO一下就找到答案了

How to use springboot + kotlin + jackson to globally set a custom Long type serializer?

答主是这样解释的:The issue with your code is that the val Long and val Long? from Kotlin are treated differently. The first will become a long whereas the second will become a Long (as it can be null).

但是这个回答提供的构造Bean的方式我不是很喜欢,因此我又找到了另一个帖子

Custom json serialization java primitives from kotlin by Jackson

最后的解决方案:

@Configuration
class JacksonConfig {
    @Bean
    fun jacksonObjectMapper(builder: Jackson2ObjectMapperBuilder): ObjectMapper {
        val objectMapper: ObjectMapper = builder.createXmlMapper(false).build()
        val simpleModule = SimpleModule()
            .addSerializer(Long::class.javaPrimitiveType, ToStringSerializer.instance)
            .addSerializer(Long::class.javaObjectType, ToStringSerializer.instance)
        objectMapper.registerModule(simpleModule)
        return objectMapper
    }
}

相关:

val <T : Any> KClass<T>.javaPrimitiveType: Class<T>?

返回一个 JavaClass实例,表示对应于给定KClass的基本类型(如果存在)。

val <T : Any> KClass<T>.javaObjectType: Class<T>

返回对应于给定KClass实例的 Java Class实例。在原始类型的情况下,它返回相应的包装类。

ねぇ,あなたは何色になりたい