@@ -4,9 +4,13 @@ import com.fasterxml.jackson.databind.JavaType
44import com.fasterxml.jackson.databind.deser.std.StdDelegatingDeserializer
55import com.fasterxml.jackson.databind.ser.std.StdDelegatingSerializer
66import com.fasterxml.jackson.databind.type.TypeFactory
7- import com.fasterxml.jackson.databind.util.ClassUtil
87import 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
1014import kotlin.time.toJavaDuration
1115import kotlin.time.toKotlinDuration
1216import java.time.Duration as JavaDuration
@@ -23,7 +27,7 @@ internal class SequenceToIteratorConverter(private val input: JavaType) : StdCon
2327}
2428
2529internal 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) }
2731
2832 override fun convert (value : Long ): JavaDuration = KotlinToJavaDurationConverter .convert(boxConverter.convert(value))
2933}
@@ -45,18 +49,163 @@ internal object JavaToKotlinDurationConverter : StdConverter<JavaDuration, Kotli
4549 }
4650}
4751
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+ }
5677 }
5778
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+
58133 @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)
60144
61145 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)
62211}
0 commit comments