summaryrefslogtreecommitdiff
path: root/core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt
diff options
context:
space:
mode:
Diffstat (limited to 'core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt')
-rw-r--r--core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt107
1 files changed, 69 insertions, 38 deletions
diff --git a/core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt b/core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt
index b110f121..b2d8da7c 100644
--- a/core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt
+++ b/core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt
@@ -17,65 +17,90 @@ import java.lang.reflect.*
import kotlin.reflect.*
/**
- * Reflectively constructs a serializer for the given reflective Java [type].
- * [serializer] is intended to be used as an interoperability layer for libraries like GSON and Retrofit,
- * that operate with reflective Java [Type] and cannot use [typeOf].
+ * Reflectively retrieves a serializer for the given [type].
*
- * For application-level serialization, it is recommended to use `serializer<T>()` instead as it is aware of
+ * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
+ * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
+ * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
+ * Note that because [Type] does not contain any information about nullability, all created serializers
+ * work only with non-nullable data.
+ *
+ * Not all [Type] implementations are supported.
+ * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
+ *
* @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
+ * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
-@ExperimentalSerializationApi
-public fun serializer(type: Type): KSerializer<Any> = EmptySerializersModule.serializer(type)
+public fun serializer(type: Type): KSerializer<Any> = EmptySerializersModule().serializer(type)
/**
- * Reflectively constructs a serializer for the given reflective Java [type].
- * [serializer] is intended to be used as an interoperability layer for libraries like GSON and Retrofit,
- * that operate with reflective Java [Type] and cannot use [typeOf].
+ * Reflectively retrieves a serializer for the given [type].
*
- * For application-level serialization, it is recommended to use `serializer<T>()` instead as it is aware of
+ * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
+ * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
+ * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
- * Returns `null` if serializer cannot be created (provided [type] or its type argument is not serializable).
+ * Note that because [Type] does not contain any information about nullability, all created serializers
+ * work only with non-nullable data.
+ *
+ * Not all [Type] implementations are supported.
+ * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
+ *
+ * @return [KSerializer] for given [type] or `null` if serializer cannot be created (given [type] or its type argument is not serializable).
+ * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
-@ExperimentalSerializationApi
-public fun serializerOrNull(type: Type): KSerializer<Any>? = EmptySerializersModule.serializerOrNull(type)
+public fun serializerOrNull(type: Type): KSerializer<Any>? = EmptySerializersModule().serializerOrNull(type)
/**
- * Retrieves serializer for the given reflective Java [type] using
- * reflective construction and [contextual][SerializersModule.getContextual] lookup for non-serializable types.
+ * Retrieves a serializer for the given [type] using
+ * reflective construction and [contextual][SerializersModule.getContextual] lookup as a fallback for non-serializable types.
*
- * [serializer] is intended to be used as an interoperability layer for libraries like GSON and Retrofit,
- * that operate with reflective Java [Type] and cannot use [typeOf].
- *
- * For application-level serialization, it is recommended to use `serializer<T>()` instead as it is aware of
+ * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
+ * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
+ * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
+ * Note that because [Type] does not contain any information about nullability, all created serializers
+ * work only with non-nullable data.
+ *
+ * Not all [Type] implementations are supported.
+ * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
+ *
* @throws SerializationException if serializer cannot be created (provided [type] or its type argument is not serializable).
+ * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
-@ExperimentalSerializationApi
public fun SerializersModule.serializer(type: Type): KSerializer<Any> =
- serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true) ?: type.prettyClass().serializerNotRegistered()
+ serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true)
+ ?: type.prettyClass().serializerNotRegistered()
/**
- * Retrieves serializer for the given reflective Java [type] using
- * reflective construction and [contextual][SerializersModule.getContextual] lookup for non-serializable types.
+ * Retrieves a serializer for the given [type] using
+ * reflective construction and [contextual][SerializersModule.getContextual] lookup as a fallback for non-serializable types.
*
- * [serializer] is intended to be used as an interoperability layer for libraries like GSON and Retrofit,
- * that operate with reflective Java [Type] and cannot use [typeOf].
- *
- * For application-level serialization, it is recommended to use `serializer<T>()` instead as it is aware of
+ * This overload is intended to be used as an interoperability layer for JVM-centric libraries,
+ * that operate with Java's type tokens and cannot use Kotlin's [KType] or [typeOf].
+ * For application-level serialization, it is recommended to use `serializer<T>()` or `serializer(KType)` instead as it is aware of
* Kotlin-specific type information, such as nullability, sealed classes and object singletons.
*
- * Returns `null` if serializer cannot be created (provided [type] or its type argument is not serializable).
+ * Note that because [Type] does not contain any information about nullability, all created serializers
+ * work only with non-nullable data.
+ *
+ * Not all [Type] implementations are supported.
+ * [type] must be an instance of [Class], [GenericArrayType], [ParameterizedType] or [WildcardType].
+ *
+ * @return [KSerializer] for given [type] or `null` if serializer cannot be created (given [type] or its type argument is not serializable).
+ * @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
*/
-@ExperimentalSerializationApi
public fun SerializersModule.serializerOrNull(type: Type): KSerializer<Any>? =
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = false)
-@OptIn(ExperimentalSerializationApi::class)
-private fun SerializersModule.serializerByJavaTypeImpl(type: Type, failOnMissingTypeArgSerializer: Boolean = true): KSerializer<Any>? =
+private fun SerializersModule.serializerByJavaTypeImpl(
+ type: Type,
+ failOnMissingTypeArgSerializer: Boolean = true
+): KSerializer<Any>? =
when (type) {
is GenericArrayType -> {
genericArraySerializer(type, failOnMissingTypeArgSerializer)
@@ -85,7 +110,9 @@ private fun SerializersModule.serializerByJavaTypeImpl(type: Type, failOnMissing
val rootClass = (type.rawType as Class<*>)
val args = (type.actualTypeArguments)
val argsSerializers =
- if (failOnMissingTypeArgSerializer) args.map { serializer(it) } else args.map { serializerOrNull(it) ?: return null }
+ if (failOnMissingTypeArgSerializer) args.map { serializer(it) } else args.map {
+ serializerOrNull(it) ?: return null
+ }
when {
Set::class.java.isAssignableFrom(rootClass) -> SetSerializer(argsSerializers[0]) as KSerializer<Any>
List::class.java.isAssignableFrom(rootClass) || Collection::class.java.isAssignableFrom(rootClass) -> ListSerializer(
@@ -110,19 +137,20 @@ private fun SerializersModule.serializerByJavaTypeImpl(type: Type, failOnMissing
) as KSerializer<Any>
else -> {
- // probably we should deprecate this method because it can't differ nullable vs non-nullable types
- // since it uses Java TypeToken, not Kotlin one
val varargs = argsSerializers.map { it as KSerializer<Any?> }
reflectiveOrContextual(rootClass as Class<Any>, varargs)
}
}
}
is WildcardType -> serializerByJavaTypeImpl(type.upperBounds.first())
- else -> throw IllegalArgumentException("typeToken should be an instance of Class<?>, GenericArray, ParametrizedType or WildcardType, but actual type is $type ${type::class}")
+ else -> throw IllegalArgumentException("type should be an instance of Class<?>, GenericArrayType, ParametrizedType or WildcardType, but actual argument $type has type ${type::class}")
}
@OptIn(ExperimentalSerializationApi::class)
-private fun SerializersModule.typeSerializer(type: Class<*>, failOnMissingTypeArgSerializer: Boolean): KSerializer<Any>? {
+private fun SerializersModule.typeSerializer(
+ type: Class<*>,
+ failOnMissingTypeArgSerializer: Boolean
+): KSerializer<Any>? {
return if (type.isArray && !type.componentType.isPrimitive) {
val eType: Class<*> = type.componentType
val s = if (failOnMissingTypeArgSerializer) serializer(eType) else (serializerOrNull(eType) ?: return null)
@@ -134,7 +162,10 @@ private fun SerializersModule.typeSerializer(type: Class<*>, failOnMissingTypeAr
}
@OptIn(ExperimentalSerializationApi::class)
-private fun <T : Any> SerializersModule.reflectiveOrContextual(jClass: Class<T>, typeArgumentsSerializers: List<KSerializer<Any?>>): KSerializer<T>? {
+private fun <T : Any> SerializersModule.reflectiveOrContextual(
+ jClass: Class<T>,
+ typeArgumentsSerializers: List<KSerializer<Any?>>
+): KSerializer<T>? {
jClass.constructSerializerForGivenTypeArgs(*typeArgumentsSerializers.toTypedArray())?.let { return it }
val kClass = jClass.kotlin
return kClass.builtinSerializerOrNull() ?: getContextual(kClass, typeArgumentsSerializers)
@@ -165,5 +196,5 @@ private fun Type.prettyClass(): Class<*> = when (val it = this) {
is ParameterizedType -> it.rawType.prettyClass()
is WildcardType -> it.upperBounds.first().prettyClass()
is GenericArrayType -> it.genericComponentType.prettyClass()
- else -> throw IllegalArgumentException("typeToken should be an instance of Class<?>, GenericArray, ParametrizedType or WildcardType, but actual type is $it ${it::class}")
+ else -> throw IllegalArgumentException("type should be an instance of Class<?>, GenericArrayType, ParametrizedType or WildcardType, but actual argument $it has type ${it::class}")
}