Skip to content

Commit

Permalink
Ignore NoClassDefFoundError when initializing builtins map for serial…
Browse files Browse the repository at this point in the history
…izer() function.

Normally they should not occur, but in rare setups when runtime stdlib may be lower than 2.0, we may want to ignore errors about experimental classes.

Fixes #2803
  • Loading branch information
sandwwraith committed Aug 30, 2024
1 parent 8c84a5b commit 0b015e1
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 32 deletions.
35 changes: 3 additions & 32 deletions core/commonMain/src/kotlinx/serialization/internal/Primitives.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,9 @@ import kotlin.reflect.*
import kotlin.time.Duration
import kotlin.uuid.*

@OptIn(ExperimentalUnsignedTypes::class, ExperimentalUuidApi::class)
private val BUILTIN_SERIALIZERS = mapOf(
String::class to String.serializer(),
Char::class to Char.serializer(),
CharArray::class to CharArraySerializer(),
Double::class to Double.serializer(),
DoubleArray::class to DoubleArraySerializer(),
Float::class to Float.serializer(),
FloatArray::class to FloatArraySerializer(),
Long::class to Long.serializer(),
LongArray::class to LongArraySerializer(),
ULong::class to ULong.serializer(),
ULongArray::class to ULongArraySerializer(),
Int::class to Int.serializer(),
IntArray::class to IntArraySerializer(),
UInt::class to UInt.serializer(),
UIntArray::class to UIntArraySerializer(),
Short::class to Short.serializer(),
ShortArray::class to ShortArraySerializer(),
UShort::class to UShort.serializer(),
UShortArray::class to UShortArraySerializer(),
Byte::class to Byte.serializer(),
ByteArray::class to ByteArraySerializer(),
UByte::class to UByte.serializer(),
UByteArray::class to UByteArraySerializer(),
Boolean::class to Boolean.serializer(),
BooleanArray::class to BooleanArraySerializer(),
Unit::class to Unit.serializer(),
Nothing::class to NothingSerializer(),
Duration::class to Duration.serializer(),
Uuid::class to Uuid.serializer()
)
private val BUILTIN_SERIALIZERS = initBuiltins()

internal expect fun initBuiltins(): Map<KClass<*>, KSerializer<*>>

internal class PrimitiveSerialDescriptor(
override val serialName: String,
Expand Down
36 changes: 36 additions & 0 deletions core/jsMain/src/kotlinx/serialization/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
package kotlinx.serialization.internal

import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlin.reflect.*
import kotlin.time.*
import kotlin.uuid.*

internal actual fun <T> Array<T>.getChecked(index: Int): T {
if (index !in indices) throw IndexOutOfBoundsException("Index $index out of bounds $indices")
Expand Down Expand Up @@ -77,3 +80,36 @@ private val KClass<*>.isInterface: Boolean
if (this === Nothing::class) return false
return js.asDynamic().`$metadata$`?.kind == "interface"
}

@OptIn(ExperimentalUnsignedTypes::class, ExperimentalUuidApi::class, ExperimentalSerializationApi::class)
internal actual fun initBuiltins(): Map<KClass<*>, KSerializer<*>> = mapOf(
String::class to String.serializer(),
Char::class to Char.serializer(),
CharArray::class to CharArraySerializer(),
Double::class to Double.serializer(),
DoubleArray::class to DoubleArraySerializer(),
Float::class to Float.serializer(),
FloatArray::class to FloatArraySerializer(),
Long::class to Long.serializer(),
LongArray::class to LongArraySerializer(),
ULong::class to ULong.serializer(),
ULongArray::class to ULongArraySerializer(),
Int::class to Int.serializer(),
IntArray::class to IntArraySerializer(),
UInt::class to UInt.serializer(),
UIntArray::class to UIntArraySerializer(),
Short::class to Short.serializer(),
ShortArray::class to ShortArraySerializer(),
UShort::class to UShort.serializer(),
UShortArray::class to UShortArraySerializer(),
Byte::class to Byte.serializer(),
ByteArray::class to ByteArraySerializer(),
UByte::class to UByte.serializer(),
UByteArray::class to UByteArraySerializer(),
Boolean::class to Boolean.serializer(),
BooleanArray::class to BooleanArraySerializer(),
Unit::class to Unit.serializer(),
Nothing::class to NothingSerializer(),
Duration::class to Duration.serializer(),
Uuid::class to Uuid.serializer()
)
53 changes: 53 additions & 0 deletions core/jvmMain/src/kotlinx/serialization/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@
package kotlinx.serialization.internal

import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import java.lang.reflect.*
import kotlin.reflect.*
import kotlin.time.*
import kotlin.uuid.*

@Suppress("NOTHING_TO_INLINE")
internal actual inline fun <T> Array<T>.getChecked(index: Int): T {
Expand Down Expand Up @@ -158,3 +161,53 @@ private fun <T : Any> Class<T>.findObjectSerializer(): KSerializer<T>? {
}

internal actual fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass.java.isArray

@OptIn(ExperimentalSerializationApi::class)
internal actual fun initBuiltins(): Map<KClass<*>, KSerializer<*>> = buildMap {
// Standard classes are always present
put(String::class, String.serializer())
put(Char::class, Char.serializer())
put(CharArray::class, CharArraySerializer())
put(Double::class, Double.serializer())
put(DoubleArray::class, DoubleArraySerializer())
put(Float::class, Float.serializer())
put(FloatArray::class, FloatArraySerializer())
put(Long::class, Long.serializer())
put(LongArray::class, LongArraySerializer())
put(ULong::class, ULong.serializer())
put(Int::class, Int.serializer())
put(IntArray::class, IntArraySerializer())
put(UInt::class, UInt.serializer())
put(Short::class, Short.serializer())
put(ShortArray::class, ShortArraySerializer())
put(UShort::class, UShort.serializer())
put(Byte::class, Byte.serializer())
put(ByteArray::class, ByteArraySerializer())
put(UByte::class, UByte.serializer())
put(Boolean::class, Boolean.serializer())
put(BooleanArray::class, BooleanArraySerializer())
put(Unit::class, Unit.serializer())
put(Nothing::class, NothingSerializer())

// Duration is a stable class, but may be missing in very old stdlibs
loadSafe { put(Duration::class, Duration.serializer()) }

// Experimental types that may be missing
@OptIn(ExperimentalUnsignedTypes::class) run {
loadSafe { put(ULongArray::class, ULongArraySerializer()) }
loadSafe { put(UIntArray::class, UIntArraySerializer()) }
loadSafe { put(UShortArray::class, UShortArraySerializer()) }
loadSafe { put(UByteArray::class, UByteArraySerializer()) }
}
@OptIn(ExperimentalUuidApi::class)
loadSafe { put(Uuid::class, Uuid.serializer()) }
}

// Reference classes in [block] ignoring any exceptions related to class loading
private inline fun loadSafe(block: () -> Unit) {
try {
block()
} catch (_: NoClassDefFoundError) {
} catch (_: ClassNotFoundException) {
}
}
36 changes: 36 additions & 0 deletions core/nativeMain/src/kotlinx/serialization/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
package kotlinx.serialization.internal

import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlin.reflect.*
import kotlin.time.*
import kotlin.uuid.*

@Suppress("NOTHING_TO_INLINE")
internal actual inline fun <T> Array<T>.getChecked(index: Int): T {
Expand Down Expand Up @@ -71,3 +74,36 @@ internal actual fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KCl
private fun <T> arrayOfAnyNulls(size: Int): Array<T> = arrayOfNulls<Any>(size) as Array<T>

internal actual fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass == Array::class

@OptIn(ExperimentalUnsignedTypes::class, ExperimentalUuidApi::class, ExperimentalSerializationApi::class)
internal actual fun initBuiltins(): Map<KClass<*>, KSerializer<*>> = mapOf(
String::class to String.serializer(),
Char::class to Char.serializer(),
CharArray::class to CharArraySerializer(),
Double::class to Double.serializer(),
DoubleArray::class to DoubleArraySerializer(),
Float::class to Float.serializer(),
FloatArray::class to FloatArraySerializer(),
Long::class to Long.serializer(),
LongArray::class to LongArraySerializer(),
ULong::class to ULong.serializer(),
ULongArray::class to ULongArraySerializer(),
Int::class to Int.serializer(),
IntArray::class to IntArraySerializer(),
UInt::class to UInt.serializer(),
UIntArray::class to UIntArraySerializer(),
Short::class to Short.serializer(),
ShortArray::class to ShortArraySerializer(),
UShort::class to UShort.serializer(),
UShortArray::class to UShortArraySerializer(),
Byte::class to Byte.serializer(),
ByteArray::class to ByteArraySerializer(),
UByte::class to UByte.serializer(),
UByteArray::class to UByteArraySerializer(),
Boolean::class to Boolean.serializer(),
BooleanArray::class to BooleanArraySerializer(),
Unit::class to Unit.serializer(),
Nothing::class to NothingSerializer(),
Duration::class to Duration.serializer(),
Uuid::class to Uuid.serializer()
)
36 changes: 36 additions & 0 deletions core/wasmMain/src/kotlinx/serialization/internal/Platform.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
package kotlinx.serialization.internal

import kotlinx.serialization.*
import kotlinx.serialization.builtins.*
import kotlin.reflect.*
import kotlin.time.*
import kotlin.uuid.*

@Suppress("NOTHING_TO_INLINE")
internal actual inline fun <T> Array<T>.getChecked(index: Int): T {
Expand Down Expand Up @@ -61,3 +64,36 @@ internal actual fun <T> createParametrizedCache(factory: (KClass<Any>, List<KTyp
internal actual fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KClass<T>): Array<E> = toTypedArray()

internal actual fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass == Array::class

@OptIn(ExperimentalUnsignedTypes::class, ExperimentalUuidApi::class, ExperimentalSerializationApi::class)
internal actual fun initBuiltins(): Map<KClass<*>, KSerializer<*>> = mapOf(
String::class to String.serializer(),
Char::class to Char.serializer(),
CharArray::class to CharArraySerializer(),
Double::class to Double.serializer(),
DoubleArray::class to DoubleArraySerializer(),
Float::class to Float.serializer(),
FloatArray::class to FloatArraySerializer(),
Long::class to Long.serializer(),
LongArray::class to LongArraySerializer(),
ULong::class to ULong.serializer(),
ULongArray::class to ULongArraySerializer(),
Int::class to Int.serializer(),
IntArray::class to IntArraySerializer(),
UInt::class to UInt.serializer(),
UIntArray::class to UIntArraySerializer(),
Short::class to Short.serializer(),
ShortArray::class to ShortArraySerializer(),
UShort::class to UShort.serializer(),
UShortArray::class to UShortArraySerializer(),
Byte::class to Byte.serializer(),
ByteArray::class to ByteArraySerializer(),
UByte::class to UByte.serializer(),
UByteArray::class to UByteArraySerializer(),
Boolean::class to Boolean.serializer(),
BooleanArray::class to BooleanArraySerializer(),
Unit::class to Unit.serializer(),
Nothing::class to NothingSerializer(),
Duration::class to Duration.serializer(),
Uuid::class to Uuid.serializer()
)

0 comments on commit 0b015e1

Please sign in to comment.