1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
|
/*
* Copyright 2018 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package kotlinx.serialization
import kotlinx.serialization.internal.*
import java.lang.reflect.*
import kotlin.reflect.KClass
@PublishedApi
internal open class TypeBase<T>
inline fun <reified T> typeTokenOf(): Type {
val base = object : TypeBase<T>() {}
val superType = base::class.java.genericSuperclass!!
return (superType as ParameterizedType).actualTypeArguments.first()!!
}
/**
* This method uses reflection to construct serializer for given type. However,
* since it accepts type token, it is available only on JVM by design,
* and it can work correctly even with generics, so
* it is not annotated with [ImplicitReflectionSerializer].
*
* Keep in mind that this is a 'heavy' call, so result probably should be cached somewhere else.
*
* This method intended for static, format-agnostic resolving (e.g. in adapter factories) so context is not used here.
*/
@Suppress("UNCHECKED_CAST")
@UseExperimental(ImplicitReflectionSerializer::class)
fun serializerByTypeToken(type: Type): KSerializer<Any> = when (type) {
is GenericArrayType -> {
val eType = type.genericComponentType.let {
when (it) {
is WildcardType -> it.upperBounds.first()
else -> it
}
}
val serializer = serializerByTypeToken(eType)
val kclass = when (eType) {
is ParameterizedType -> (eType.rawType as Class<*>).kotlin
is KClass<*> -> eType
else -> throw IllegalStateException("unsupported type in GenericArray: ${eType::class}")
} as KClass<Any>
ReferenceArraySerializer(kclass, serializer) as KSerializer<Any>
}
is Class<*> -> if (!type.isArray) {
requireNotNull<KSerializer<out Any>>((type.kotlin as KClass<Any>).serializer<Any>()) as KSerializer<Any>
} else {
val eType: Class<*> = type.componentType
val s = serializerByTypeToken(eType)
val arraySerializer = ReferenceArraySerializer(eType.kotlin as KClass<Any>, s)
arraySerializer as KSerializer<Any>
}
is ParameterizedType -> {
val rootClass = (type.rawType as Class<*>)
val args = (type.actualTypeArguments)
when {
List::class.java.isAssignableFrom(rootClass) -> ArrayListSerializer(serializerByTypeToken(args[0])) as KSerializer<Any>
Set::class.java.isAssignableFrom(rootClass) -> HashSetSerializer(serializerByTypeToken(args[0])) as KSerializer<Any>
Map::class.java.isAssignableFrom(rootClass) -> HashMapSerializer(
serializerByTypeToken(args[0]),
serializerByTypeToken(args[1])
) as KSerializer<Any>
Map.Entry::class.java.isAssignableFrom(rootClass) -> MapEntrySerializer(
serializerByTypeToken(args[0]),
serializerByTypeToken(args[1])
) as KSerializer<Any>
else -> {
val varargs = args.map { serializerByTypeToken(it) }.toTypedArray()
(rootClass.invokeSerializerGetter(*varargs) as? KSerializer<Any>) ?: requireNotNull<KSerializer<out Any>>(
(rootClass.kotlin as KClass<Any>)
.serializer()) as KSerializer<Any>
}
}
}
is WildcardType -> serializerByTypeToken(type.upperBounds.first())
else -> throw IllegalArgumentException("typeToken should be an instance of Class<?>, GenericArray, ParametrizedType or WildcardType, but actual type is $type ${type::class}")
}
|