/
Platform.kt
154 lines (137 loc) · 5.81 KB
/
Platform.kt
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/*
* Copyright 2017-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package kotlinx.serialization.internal
import kotlinx.serialization.*
import java.lang.reflect.*
import kotlin.reflect.*
@Suppress("NOTHING_TO_INLINE")
internal actual inline fun <T> Array<T>.getChecked(index: Int): T {
return get(index)
}
@Suppress("NOTHING_TO_INLINE")
internal actual inline fun BooleanArray.getChecked(index: Int): Boolean {
return get(index)
}
@Suppress("UNCHECKED_CAST")
internal actual fun <T : Any> KClass<T>.compiledSerializerImpl(): KSerializer<T>? =
this.constructSerializerForGivenTypeArgs()
@Suppress("UNCHECKED_CAST")
internal actual fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KClass<T>): Array<E> =
toArray(java.lang.reflect.Array.newInstance(eClass.java, size) as Array<E>)
internal actual fun KClass<*>.platformSpecificSerializerNotRegistered(): Nothing = serializerNotRegistered()
@Suppress("UNCHECKED_CAST")
internal actual fun <T : Any> KClass<T>.constructSerializerForGivenTypeArgs(vararg args: KSerializer<Any?>): KSerializer<T>? {
val jClass = this.java
if (jClass.isEnum && jClass.isNotAnnotated()) {
return jClass.createEnumSerializer()
}
if (jClass.isInterface) {
return interfaceSerializer()
}
// Search for serializer defined on companion object.
val serializer = invokeSerializerOnCompanion<T>(jClass, *args)
if (serializer != null) return serializer
// Check whether it's serializable object
findObjectSerializer(jClass)?.let { return it }
// Search for default serializer if no serializer is defined in companion object.
// It is required for named companions
val fromNamedCompanion = try {
jClass.declaredClasses.singleOrNull { it.simpleName == ("\$serializer") }
?.getField("INSTANCE")?.get(null) as? KSerializer<T>
} catch (e: NoSuchFieldException) {
null
}
if (fromNamedCompanion != null) return fromNamedCompanion
// Check for polymorphic
return polymorphicSerializer()
}
private fun <T: Any> Class<T>.isNotAnnotated(): Boolean {
/*
* For annotated enums search serializer directly (or do not search at all?)
*/
return getAnnotation(Serializable::class.java) == null &&
getAnnotation(Polymorphic::class.java) == null
}
private fun <T: Any> KClass<T>.polymorphicSerializer(): KSerializer<T>? {
/*
* Last resort: check for @Polymorphic or Serializable(with = PolymorphicSerializer::class)
* annotations.
*/
val jClass = java
if (jClass.getAnnotation(Polymorphic::class.java) != null) {
return PolymorphicSerializer(this)
}
val serializable = jClass.getAnnotation(Serializable::class.java)
if (serializable != null && serializable.with == PolymorphicSerializer::class) {
return PolymorphicSerializer(this)
}
return null
}
private fun <T: Any> KClass<T>.interfaceSerializer(): KSerializer<T>? {
/*
* Interfaces are @Polymorphic by default.
* Check if it has no annotations or `@Serializable(with = PolymorphicSerializer::class)`,
* otherwise bailout.
*/
val serializable = java.getAnnotation(Serializable::class.java)
if (serializable == null || serializable.with == PolymorphicSerializer::class) {
return PolymorphicSerializer(this)
}
return null
}
@Suppress("UNCHECKED_CAST")
private fun <T : Any> invokeSerializerOnCompanion(jClass: Class<*>, vararg args: KSerializer<Any?>): KSerializer<T>? {
val companion = jClass.companionOrNull() ?: return null
return try {
val types = if (args.isEmpty()) emptyArray() else Array(args.size) { KSerializer::class.java }
companion.javaClass.getDeclaredMethod("serializer", *types)
.invoke(companion, *args) as? KSerializer<T>
} catch (e: NoSuchMethodException) {
null
} catch (e: InvocationTargetException) {
val cause = e.cause ?: throw e
throw InvocationTargetException(cause, cause.message ?: e.message)
}
}
private fun Class<*>.companionOrNull() =
try {
val companion = getDeclaredField("Companion")
companion.isAccessible = true
companion.get(null)
} catch (e: Throwable) {
null
}
@Suppress("UNCHECKED_CAST")
private fun <T : Any> Class<T>.createEnumSerializer(): KSerializer<T>? {
val constants = enumConstants
return EnumSerializer(canonicalName, constants as Array<out Enum<*>>) as? KSerializer<T>
}
private fun <T : Any> findObjectSerializer(jClass: Class<T>): KSerializer<T>? {
// Check it is an object without using kotlin-reflect
val field =
jClass.declaredFields.singleOrNull { it.name == "INSTANCE" && it.type == jClass && Modifier.isStatic(it.modifiers) }
?: return null
// Retrieve its instance and call serializer()
val instance = field.get(null)
val method =
jClass.methods.singleOrNull { it.name == "serializer" && it.parameterTypes.isEmpty() && it.returnType == KSerializer::class.java }
?: return null
val result = method.invoke(instance)
@Suppress("UNCHECKED_CAST")
return result as? KSerializer<T>
}
/**
* Checks if an [this@isInstanceOf] is an instance of a given [kclass].
*
* This check is a replacement for [KClass.isInstance] because
* on JVM it requires kotlin-reflect.jar in classpath
* (see https://youtrack.jetbrains.com/issue/KT-14720).
*
* On JS and Native, this function delegates to aforementioned
* [KClass.isInstance] since it is supported there out-of-the box;
* on JVM, it falls back to java.lang.Class.isInstance, which causes
* difference when applied to function types with big arity.
*/
internal actual fun Any.isInstanceOf(kclass: KClass<*>): Boolean = kclass.javaObjectType.isInstance(this)
internal actual fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass.java.isArray