fix for unboxed cases
MODIFY
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.Module
import com.fasterxml.jackson.databind.cfg.MapperConfig
import com.fasterxml.jackson.databind.introspect.*
import com.fasterxml.jackson.databind.jsontype.NamedType
+import com.fasterxml.jackson.databind.ser.std.StdSerializer
import java.lang.reflect.AccessibleObject
import java.lang.reflect.Constructor
import java.lang.reflect.Field
@@ -62,7 +63,7 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
}
// Find a serializer to handle the case where the getter returns an unboxed value from the value class.
- override fun findSerializer(am: Annotated): ValueClassBoxSerializer<*>? = when (am) {
+ override fun findSerializer(am: Annotated): StdSerializer<*>? = when (am) {
is AnnotatedMethod -> {
val getter = am.member.apply {
// If the return value of the getter is a value class,
@@ -87,8 +88,10 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
?.takeIf { it.isValue }
?.java
?.let { outerClazz ->
- @Suppress("UNCHECKED_CAST")
- ValueClassBoxSerializer(outerClazz, getter.returnType)
+ val innerClazz = getter.returnType
+
+ ValueClassStaticJsonValueSerializer.createdOrNull(outerClazz, innerClazz)
+ ?: @Suppress("UNCHECKED_CAST") ValueClassBoxSerializer(outerClazz, innerClazz)
}
}
// Ignore the case of AnnotatedField, because JvmField cannot be set in the field of value class.

MODIFY
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinSerializers.kt
src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinSerializers.kt
package com.fasterxml.jackson.module.kotlin
+import com.fasterxml.jackson.annotation.JsonValue
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.BeanDescription
import com.fasterxml.jackson.databind.JavaType
@@ -8,8 +9,9 @@ import com.fasterxml.jackson.databind.SerializationConfig
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.Serializers
import com.fasterxml.jackson.databind.ser.std.StdSerializer
+import java.lang.reflect.Method
+import java.lang.reflect.Modifier
import java.math.BigInteger
-import kotlin.reflect.KClass
object SequenceSerializer : StdSerializer<Sequence<*>>(Sequence::class.java) {
override fun serialize(value: Sequence<*>, gen: JsonGenerator, provider: SerializerProvider) {
@@ -43,6 +45,10 @@ object ULongSerializer : StdSerializer<ULong>(ULong::class.java) {
}
}
+// Class must be UnboxableValueClass.
+private fun Class<*>.getStaticJsonValueGetter(): Method? = this.declaredMethods
+ .find { method -> Modifier.isStatic(method.modifiers) && method.annotations.any { it is JsonValue } }
+
object ValueClassUnboxSerializer : StdSerializer<Any>(Any::class.java) {
override fun serialize(value: Any, gen: JsonGenerator, provider: SerializerProvider) {
val unboxed = value::class.java.getMethod("unbox-impl").invoke(value)
@@ -89,3 +95,27 @@ internal class ValueClassBoxSerializer<T : Any>(
provider.findValueSerializer(outerClazz).serialize(boxed, gen, provider)
}
}
+
+internal class ValueClassStaticJsonValueSerializer<T> private constructor(
+ innerClazz: Class<T>,
+ private val staticJsonValueGetter: Method
+) : StdSerializer<T>(innerClazz) {
+ override fun serialize(value: T?, gen: JsonGenerator, provider: SerializerProvider) {
+ // As shown in the processing of the factory function, jsonValueGetter is always a static method.
+ val jsonValue: Any? = staticJsonValueGetter.invoke(null, value)
+ jsonValue
+ ?.let { provider.findValueSerializer(it::class.java).serialize(it, gen, provider) }
+ ?: provider.findNullValueSerializer(null).serialize(null, gen, provider)
+ }
+
+ // Since JsonValue can be processed correctly if it is given to a non-static getter/field,
+ // this class will only process if it is a `static` method.
+ companion object {
+ fun <T> createdOrNull(
+ outerClazz: Class<out Any>,
+ innerClazz: Class<T>
+ ): ValueClassStaticJsonValueSerializer<T>? = outerClazz
+ .getStaticJsonValueGetter()
+ ?.let { ValueClassStaticJsonValueSerializer(innerClazz, it) }
+ }
+}

fix for unboxed cases