1
1
package com.fasterxml.jackson.module.kotlin
2
2
3
+ import com.fasterxml.jackson.annotation.JsonValue
3
4
import com.fasterxml.jackson.core.JsonGenerator
4
5
import com.fasterxml.jackson.databind.BeanDescription
5
6
import com.fasterxml.jackson.databind.JavaType
@@ -8,8 +9,9 @@ import com.fasterxml.jackson.databind.SerializationConfig
8
9
import com.fasterxml.jackson.databind.SerializerProvider
9
10
import com.fasterxml.jackson.databind.ser.Serializers
10
11
import com.fasterxml.jackson.databind.ser.std.StdSerializer
12
+ import java.lang.reflect.Method
13
+ import java.lang.reflect.Modifier
11
14
import java.math.BigInteger
12
- import kotlin.reflect.KClass
13
15
14
16
object SequenceSerializer : StdSerializer<Sequence<*>>(Sequence : :class.java) {
15
17
override fun serialize (value : Sequence <* >, gen : JsonGenerator , provider : SerializerProvider ) {
@@ -43,16 +45,47 @@ object ULongSerializer : StdSerializer<ULong>(ULong::class.java) {
43
45
}
44
46
}
45
47
46
- object ValueClassUnboxSerializer : StdSerializer<Any>( Any : :class.java) {
47
- override fun serialize ( value : Any , gen : JsonGenerator , provider : SerializerProvider ) {
48
- val unboxed = value:: class .java.getMethod( " unbox-impl " ).invoke(value)
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 } }
49
51
50
- if (unboxed == null ) {
51
- provider.findNullValueSerializer(null ).serialize(unboxed, gen, provider)
52
- return
52
+ internal sealed class ValueClassSerializer <T : Any >(t : Class <T >) : StdSerializer<T>(t) {
53
+ object Unbox : ValueClassSerializer<Any>(Any : :class.java) {
54
+ override fun serialize (value : Any , gen : JsonGenerator , provider : SerializerProvider ) {
55
+ val unboxed = value::class .java.getMethod(" unbox-impl" ).invoke(value)
56
+
57
+ if (unboxed == null ) {
58
+ provider.findNullValueSerializer(null ).serialize(unboxed, gen, provider)
59
+ return
60
+ }
61
+
62
+ provider.findValueSerializer(unboxed::class .java).serialize(unboxed, gen, provider)
63
+ }
64
+ }
65
+
66
+ class StaticJsonValue <T : Any >(
67
+ t : Class <T >, private val staticJsonValueGetter : Method
68
+ ) : ValueClassSerializer<T>(t) {
69
+ private val unboxMethod: Method = t.getMethod(" unbox-impl" )
70
+
71
+ override fun serialize (value : T , gen : JsonGenerator , provider : SerializerProvider ) {
72
+ val unboxed = unboxMethod.invoke(value)
73
+ // As shown in the processing of the factory function, jsonValueGetter is always a static method.
74
+ val jsonValue: Any? = staticJsonValueGetter.invoke(null , unboxed)
75
+ jsonValue
76
+ ?.let { provider.findValueSerializer(it::class .java).serialize(it, gen, provider) }
77
+ ? : provider.findNullValueSerializer(null ).serialize(null , gen, provider)
53
78
}
79
+ }
54
80
55
- provider.findValueSerializer(unboxed::class .java).serialize(unboxed, gen, provider)
81
+ companion object {
82
+ // `t` must be UnboxableValueClass.
83
+ // If create a function with a JsonValue in the value class,
84
+ // it will be compiled as a static method (= cannot be processed properly by Jackson),
85
+ // so use a ValueClassSerializer.StaticJsonValue to handle this.
86
+ fun from (t : Class <* >): ValueClassSerializer <* > = t.getStaticJsonValueGetter()
87
+ ?.let { StaticJsonValue (t, it) }
88
+ ? : Unbox
56
89
}
57
90
}
58
91
@@ -61,15 +94,19 @@ internal class KotlinSerializers : Serializers.Base() {
61
94
config : SerializationConfig ? ,
62
95
type : JavaType ,
63
96
beanDesc : BeanDescription ?
64
- ): JsonSerializer <* >? = when {
65
- Sequence ::class .java.isAssignableFrom(type.rawClass) -> SequenceSerializer
66
- UByte ::class .java.isAssignableFrom(type.rawClass) -> UByteSerializer
67
- UShort ::class .java.isAssignableFrom(type.rawClass) -> UShortSerializer
68
- UInt ::class .java.isAssignableFrom(type.rawClass) -> UIntSerializer
69
- ULong ::class .java.isAssignableFrom(type.rawClass) -> ULongSerializer
70
- // The priority of Unboxing needs to be lowered so as not to break the serialization of Unsigned Integers.
71
- type.rawClass.isUnboxableValueClass() -> ValueClassUnboxSerializer
72
- else -> null
97
+ ): JsonSerializer <* >? {
98
+ val rawClass = type.rawClass
99
+
100
+ return when {
101
+ Sequence ::class .java.isAssignableFrom(rawClass) -> SequenceSerializer
102
+ UByte ::class .java.isAssignableFrom(rawClass) -> UByteSerializer
103
+ UShort ::class .java.isAssignableFrom(rawClass) -> UShortSerializer
104
+ UInt ::class .java.isAssignableFrom(rawClass) -> UIntSerializer
105
+ ULong ::class .java.isAssignableFrom(rawClass) -> ULongSerializer
106
+ // The priority of Unboxing needs to be lowered so as not to break the serialization of Unsigned Integers.
107
+ rawClass.isUnboxableValueClass() -> ValueClassSerializer .from(rawClass)
108
+ else -> null
109
+ }
73
110
}
74
111
}
75
112
@@ -89,3 +126,27 @@ internal class ValueClassBoxSerializer<T : Any>(
89
126
provider.findValueSerializer(outerClazz).serialize(boxed, gen, provider)
90
127
}
91
128
}
129
+
130
+ internal class ValueClassStaticJsonValueSerializer <T > private constructor(
131
+ innerClazz : Class <T >,
132
+ private val staticJsonValueGetter : Method
133
+ ) : StdSerializer<T>(innerClazz) {
134
+ override fun serialize (value : T ? , gen : JsonGenerator , provider : SerializerProvider ) {
135
+ // As shown in the processing of the factory function, jsonValueGetter is always a static method.
136
+ val jsonValue: Any? = staticJsonValueGetter.invoke(null , value)
137
+ jsonValue
138
+ ?.let { provider.findValueSerializer(it::class .java).serialize(it, gen, provider) }
139
+ ? : provider.findNullValueSerializer(null ).serialize(null , gen, provider)
140
+ }
141
+
142
+ // Since JsonValue can be processed correctly if it is given to a non-static getter/field,
143
+ // this class will only process if it is a `static` method.
144
+ companion object {
145
+ fun <T > createdOrNull (
146
+ outerClazz : Class <out Any >,
147
+ innerClazz : Class <T >
148
+ ): ValueClassStaticJsonValueSerializer <T >? = outerClazz
149
+ .getStaticJsonValueGetter()
150
+ ?.let { ValueClassStaticJsonValueSerializer (innerClazz, it) }
151
+ }
152
+ }
0 commit comments