Skip to content

Commit b1cd3cf

Browse files
committed
fix for unboxed cases
1 parent cc2a337 commit b1cd3cf

File tree

2 files changed

+37
-4
lines changed

2 files changed

+37
-4
lines changed

src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinAnnotationIntrospector.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.Module
77
import com.fasterxml.jackson.databind.cfg.MapperConfig
88
import com.fasterxml.jackson.databind.introspect.*
99
import com.fasterxml.jackson.databind.jsontype.NamedType
10+
import com.fasterxml.jackson.databind.ser.std.StdSerializer
1011
import java.lang.reflect.AccessibleObject
1112
import java.lang.reflect.Constructor
1213
import java.lang.reflect.Field
@@ -62,7 +63,7 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
6263
}
6364

6465
// Find a serializer to handle the case where the getter returns an unboxed value from the value class.
65-
override fun findSerializer(am: Annotated): ValueClassBoxSerializer<*>? = when (am) {
66+
override fun findSerializer(am: Annotated): StdSerializer<*>? = when (am) {
6667
is AnnotatedMethod -> {
6768
val getter = am.member.apply {
6869
// If the return value of the getter is a value class,
@@ -87,8 +88,10 @@ internal class KotlinAnnotationIntrospector(private val context: Module.SetupCon
8788
?.takeIf { it.isValue }
8889
?.java
8990
?.let { outerClazz ->
90-
@Suppress("UNCHECKED_CAST")
91-
ValueClassBoxSerializer(outerClazz, getter.returnType)
91+
val innerClazz = getter.returnType
92+
93+
ValueClassStaticJsonValueSerializer.createdOrNull(outerClazz, innerClazz)
94+
?: @Suppress("UNCHECKED_CAST") ValueClassBoxSerializer(outerClazz, innerClazz)
9295
}
9396
}
9497
// Ignore the case of AnnotatedField, because JvmField cannot be set in the field of value class.

src/main/kotlin/com/fasterxml/jackson/module/kotlin/KotlinSerializers.kt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.fasterxml.jackson.module.kotlin
22

3+
import com.fasterxml.jackson.annotation.JsonValue
34
import com.fasterxml.jackson.core.JsonGenerator
45
import com.fasterxml.jackson.databind.BeanDescription
56
import com.fasterxml.jackson.databind.JavaType
@@ -8,8 +9,9 @@ import com.fasterxml.jackson.databind.SerializationConfig
89
import com.fasterxml.jackson.databind.SerializerProvider
910
import com.fasterxml.jackson.databind.ser.Serializers
1011
import com.fasterxml.jackson.databind.ser.std.StdSerializer
12+
import java.lang.reflect.Method
13+
import java.lang.reflect.Modifier
1114
import java.math.BigInteger
12-
import kotlin.reflect.KClass
1315

1416
object SequenceSerializer : StdSerializer<Sequence<*>>(Sequence::class.java) {
1517
override fun serialize(value: Sequence<*>, gen: JsonGenerator, provider: SerializerProvider) {
@@ -43,6 +45,10 @@ object ULongSerializer : StdSerializer<ULong>(ULong::class.java) {
4345
}
4446
}
4547

48+
// Class must be UnboxableValueClass.
49+
private fun Class<*>.getStaticJsonValueGetter(): Method? = this.declaredMethods
50+
.find { method -> Modifier.isStatic(method.modifiers) && method.annotations.any { it is JsonValue } }
51+
4652
object ValueClassUnboxSerializer : StdSerializer<Any>(Any::class.java) {
4753
override fun serialize(value: Any, gen: JsonGenerator, provider: SerializerProvider) {
4854
val unboxed = value::class.java.getMethod("unbox-impl").invoke(value)
@@ -89,3 +95,27 @@ internal class ValueClassBoxSerializer<T : Any>(
8995
provider.findValueSerializer(outerClazz).serialize(boxed, gen, provider)
9096
}
9197
}
98+
99+
internal class ValueClassStaticJsonValueSerializer<T> private constructor(
100+
innerClazz: Class<T>,
101+
private val staticJsonValueGetter: Method
102+
) : StdSerializer<T>(innerClazz) {
103+
override fun serialize(value: T?, gen: JsonGenerator, provider: SerializerProvider) {
104+
// As shown in the processing of the factory function, jsonValueGetter is always a static method.
105+
val jsonValue: Any? = staticJsonValueGetter.invoke(null, value)
106+
jsonValue
107+
?.let { provider.findValueSerializer(it::class.java).serialize(it, gen, provider) }
108+
?: provider.findNullValueSerializer(null).serialize(null, gen, provider)
109+
}
110+
111+
// Since JsonValue can be processed correctly if it is given to a non-static getter/field,
112+
// this class will only process if it is a `static` method.
113+
companion object {
114+
fun <T> createdOrNull(
115+
outerClazz: Class<out Any>,
116+
innerClazz: Class<T>
117+
): ValueClassStaticJsonValueSerializer<T>? = outerClazz
118+
.getStaticJsonValueGetter()
119+
?.let { ValueClassStaticJsonValueSerializer(innerClazz, it) }
120+
}
121+
}

0 commit comments

Comments
 (0)