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