@@ -4,9 +4,13 @@ import com.fasterxml.jackson.databind.JavaType
4
4
import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer
5
5
import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer
6
6
import com.fasterxml.jackson.databind.type.TypeFactory
7
- import com.fasterxml.jackson.databind.util.ClassUtil
8
7
import com.fasterxml.jackson.databind.util.StdConverter
9
- import kotlin.reflect.KClass
8
+ import java.lang.invoke.MethodHandle
9
+ import java.lang.invoke.MethodHandles
10
+ import java.lang.invoke.MethodType
11
+ import java.lang.reflect.Method
12
+ import java.lang.reflect.Type
13
+ import java.util.UUID
10
14
import kotlin.time.toJavaDuration
11
15
import kotlin.time.toKotlinDuration
12
16
import java.time.Duration as JavaDuration
@@ -23,7 +27,7 @@ internal class SequenceToIteratorConverter(private val input: JavaType) : StdCon
23
27
}
24
28
25
29
internal object KotlinDurationValueToJavaDurationConverter : StdConverter<Long, JavaDuration>() {
26
- private val boxConverter by lazy { ValueClassBoxConverter ( Long ::class .java, KotlinDuration :: class ) }
30
+ private val boxConverter by lazy { LongValueClassBoxConverter ( KotlinDuration ::class .java) }
27
31
28
32
override fun convert (value : Long ): JavaDuration = KotlinToJavaDurationConverter .convert(boxConverter.convert(value))
29
33
}
@@ -45,18 +49,163 @@ internal object JavaToKotlinDurationConverter : StdConverter<JavaDuration, Kotli
45
49
}
46
50
}
47
51
48
- // S is nullable because value corresponds to a nullable value class
49
- // @see KotlinNamesAnnotationIntrospector.findNullSerializer
50
- internal class ValueClassBoxConverter <S : Any ?, D : Any >(
51
- unboxedClass : Class <S >,
52
- val boxedClass : KClass <D >
53
- ) : StdConverter<S, D>() {
54
- private val boxMethod = boxedClass.java.getDeclaredMethod(" box-impl" , unboxedClass).apply {
55
- ClassUtil .checkAndFixAccess(this , false )
52
+ internal sealed class ValueClassBoxConverter <S : Any ?, D : Any > : StdConverter <S , D >() {
53
+ abstract val boxedClass: Class <D >
54
+ abstract val boxHandle: MethodHandle
55
+
56
+ protected fun rawBoxHandle (
57
+ unboxedClass : Class <* >,
58
+ ): MethodHandle = MethodHandles .lookup().findStatic(
59
+ boxedClass,
60
+ " box-impl" ,
61
+ MethodType .methodType(boxedClass, unboxedClass),
62
+ )
63
+
64
+ val delegatingSerializer: StdDelegatingSerializer by lazy { StdDelegatingSerializer (this ) }
65
+
66
+ companion object {
67
+ fun create (
68
+ unboxedClass : Class <* >,
69
+ valueClass : Class <* >,
70
+ ): ValueClassBoxConverter <* , * > = when (unboxedClass) {
71
+ Int ::class .java -> IntValueClassBoxConverter (valueClass)
72
+ Long ::class .java -> LongValueClassBoxConverter (valueClass)
73
+ String ::class .java -> StringValueClassBoxConverter (valueClass)
74
+ UUID ::class .java -> JavaUuidValueClassBoxConverter (valueClass)
75
+ else -> GenericValueClassBoxConverter (unboxedClass, valueClass)
76
+ }
56
77
}
57
78
79
+ // If the wrapped type is explicitly specified, it is inherited for the sake of distinction
80
+ internal sealed class Specified <S : Any ?, D : Any > : ValueClassBoxConverter <S , D >()
81
+ }
82
+
83
+ // region: Converters for common classes as wrapped values, add as needed.
84
+ internal class IntValueClassBoxConverter <D : Any >(
85
+ override val boxedClass : Class <D >,
86
+ ) : ValueClassBoxConverter.Specified<Int, D>() {
87
+ override val boxHandle: MethodHandle = rawBoxHandle(Int ::class .java).asType(INT_TO_ANY_METHOD_TYPE )
88
+
89
+ @Suppress(" UNCHECKED_CAST" )
90
+ override fun convert (value : Int ): D = boxHandle.invokeExact(value) as D
91
+ }
92
+
93
+ internal class LongValueClassBoxConverter <D : Any >(
94
+ override val boxedClass : Class <D >,
95
+ ) : ValueClassBoxConverter.Specified<Long, D>() {
96
+ override val boxHandle: MethodHandle = rawBoxHandle(Long ::class .java).asType(LONG_TO_ANY_METHOD_TYPE )
97
+
98
+ @Suppress(" UNCHECKED_CAST" )
99
+ override fun convert (value : Long ): D = boxHandle.invokeExact(value) as D
100
+ }
101
+
102
+ internal class StringValueClassBoxConverter <D : Any >(
103
+ override val boxedClass : Class <D >,
104
+ ) : ValueClassBoxConverter.Specified<String?, D>() {
105
+ override val boxHandle: MethodHandle = rawBoxHandle(String ::class .java).asType(STRING_TO_ANY_METHOD_TYPE )
106
+
107
+ @Suppress(" UNCHECKED_CAST" )
108
+ override fun convert (value : String? ): D = boxHandle.invokeExact(value) as D
109
+ }
110
+
111
+ internal class JavaUuidValueClassBoxConverter <D : Any >(
112
+ override val boxedClass : Class <D >,
113
+ ) : ValueClassBoxConverter.Specified<UUID?, D>() {
114
+ override val boxHandle: MethodHandle = rawBoxHandle(UUID ::class .java).asType(JAVA_UUID_TO_ANY_METHOD_TYPE )
115
+
116
+ @Suppress(" UNCHECKED_CAST" )
117
+ override fun convert (value : UUID ? ): D = boxHandle.invokeExact(value) as D
118
+ }
119
+ // endregion
120
+
121
+ /* *
122
+ * A converter that only performs box processing for the value class.
123
+ * Note that constructor-impl is not called.
124
+ * @param S is nullable because value corresponds to a nullable value class.
125
+ * see [io.github.projectmapk.jackson.module.kogera.annotationIntrospector.KotlinFallbackAnnotationIntrospector.findNullSerializer]
126
+ */
127
+ internal class GenericValueClassBoxConverter <S : Any ?, D : Any >(
128
+ unboxedClass : Class <S >,
129
+ override val boxedClass : Class <D >,
130
+ ) : ValueClassBoxConverter<S, D>() {
131
+ override val boxHandle: MethodHandle = rawBoxHandle(unboxedClass).asType(ANY_TO_ANY_METHOD_TYPE )
132
+
58
133
@Suppress(" UNCHECKED_CAST" )
59
- override fun convert (value : S ): D = boxMethod.invoke(null , value) as D
134
+ override fun convert (value : S ): D = boxHandle.invokeExact(value) as D
135
+ }
136
+
137
+ internal sealed class ValueClassUnboxConverter <S : Any , D : Any ?> : StdConverter <S , D >() {
138
+ abstract val valueClass: Class <S >
139
+ abstract val unboxedType: Type
140
+ abstract val unboxHandle: MethodHandle
141
+
142
+ final override fun getInputType (typeFactory : TypeFactory ): JavaType = typeFactory.constructType(valueClass)
143
+ final override fun getOutputType (typeFactory : TypeFactory ): JavaType = typeFactory.constructType(unboxedType)
60
144
61
145
val delegatingSerializer: StdDelegatingSerializer by lazy { StdDelegatingSerializer (this ) }
146
+
147
+ companion object {
148
+ fun create (valueClass : Class <* >): ValueClassUnboxConverter <* , * > {
149
+ val unboxMethod = valueClass.getDeclaredMethod(" unbox-impl" )
150
+ val unboxedType = unboxMethod.genericReturnType
151
+
152
+ return when (unboxedType) {
153
+ Int ::class .java -> IntValueClassUnboxConverter (valueClass, unboxMethod)
154
+ Long ::class .java -> LongValueClassUnboxConverter (valueClass, unboxMethod)
155
+ String ::class .java -> StringValueClassUnboxConverter (valueClass, unboxMethod)
156
+ UUID ::class .java -> JavaUuidValueClassUnboxConverter (valueClass, unboxMethod)
157
+ else -> GenericValueClassUnboxConverter (valueClass, unboxedType, unboxMethod)
158
+ }
159
+ }
160
+ }
161
+ }
162
+
163
+ internal class IntValueClassUnboxConverter <T : Any >(
164
+ override val valueClass : Class <T >,
165
+ unboxMethod : Method ,
166
+ ) : ValueClassUnboxConverter<T, Int>() {
167
+ override val unboxedType: Type get() = Int ::class .java
168
+ override val unboxHandle: MethodHandle = unreflectAsType(unboxMethod, ANY_TO_INT_METHOD_TYPE )
169
+
170
+ override fun convert (value : T ): Int = unboxHandle.invokeExact(value) as Int
171
+ }
172
+
173
+ internal class LongValueClassUnboxConverter <T : Any >(
174
+ override val valueClass : Class <T >,
175
+ unboxMethod : Method ,
176
+ ) : ValueClassUnboxConverter<T, Long>() {
177
+ override val unboxedType: Type get() = Long ::class .java
178
+ override val unboxHandle: MethodHandle = unreflectAsType(unboxMethod, ANY_TO_LONG_METHOD_TYPE )
179
+
180
+ override fun convert (value : T ): Long = unboxHandle.invokeExact(value) as Long
181
+ }
182
+
183
+ internal class StringValueClassUnboxConverter <T : Any >(
184
+ override val valueClass : Class <T >,
185
+ unboxMethod : Method ,
186
+ ) : ValueClassUnboxConverter<T, String?>() {
187
+ override val unboxedType: Type get() = String ::class .java
188
+ override val unboxHandle: MethodHandle = unreflectAsType(unboxMethod, ANY_TO_STRING_METHOD_TYPE )
189
+
190
+ override fun convert (value : T ): String? = unboxHandle.invokeExact(value) as String?
191
+ }
192
+
193
+ internal class JavaUuidValueClassUnboxConverter <T : Any >(
194
+ override val valueClass : Class <T >,
195
+ unboxMethod : Method ,
196
+ ) : ValueClassUnboxConverter<T, UUID?>() {
197
+ override val unboxedType: Type get() = UUID ::class .java
198
+ override val unboxHandle: MethodHandle = unreflectAsType(unboxMethod, ANY_TO_JAVA_UUID_METHOD_TYPE )
199
+
200
+ override fun convert (value : T ): UUID ? = unboxHandle.invokeExact(value) as UUID ?
201
+ }
202
+
203
+ internal class GenericValueClassUnboxConverter <T : Any >(
204
+ override val valueClass : Class <T >,
205
+ override val unboxedType : Type ,
206
+ unboxMethod : Method ,
207
+ ) : ValueClassUnboxConverter<T, Any?>() {
208
+ override val unboxHandle: MethodHandle = unreflectAsType(unboxMethod, ANY_TO_ANY_METHOD_TYPE )
209
+
210
+ override fun convert (value : T ): Any? = unboxHandle.invokeExact(value)
62
211
}
0 commit comments