Skip to content

Commit 3000afc

Browse files
authored
Consolidate exception message and improve it (#2068)
Fixes #2066
1 parent 52218e8 commit 3000afc

File tree

12 files changed

+31
-65
lines changed

12 files changed

+31
-65
lines changed

core/commonMain/src/kotlinx/serialization/internal/Platform.common.kt

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ internal object InternalHexConverter {
2121
while (i < len) {
2222
val h = hexToInt(s[i])
2323
val l = hexToInt(s[i + 1])
24-
require(!(h == -1 || l == -1)) { "Invalid hex chars: ${s[i]}${s[i+1]}" }
24+
require(!(h == -1 || l == -1)) { "Invalid hex chars: ${s[i]}${s[i + 1]}" }
2525

2626
bytes[i / 2] = ((h shl 4) + l).toByte()
2727
i += 2
@@ -85,25 +85,29 @@ internal inline fun <T> SerializationStrategy<*>.cast(): SerializationStrategy<T
8585

8686
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
8787
@PublishedApi
88-
internal inline fun <T> DeserializationStrategy<*>.cast(): DeserializationStrategy<T> = this as DeserializationStrategy<T>
88+
internal inline fun <T> DeserializationStrategy<*>.cast(): DeserializationStrategy<T> =
89+
this as DeserializationStrategy<T>
8990

9091
internal fun KClass<*>.serializerNotRegistered(): Nothing {
91-
throw SerializationException(
92-
"Serializer for class '${simpleName}' is not found.\n" +
93-
"Mark the class as @Serializable or provide the serializer explicitly."
94-
)
92+
throw SerializationException(notRegisteredMessage())
9593
}
9694

95+
internal fun KClass<*>.notRegisteredMessage(): String = "Serializer for class '${simpleName}' is not found.\n" +
96+
"Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
97+
9798
internal expect fun KClass<*>.platformSpecificSerializerNotRegistered(): Nothing
9899

99100
@Suppress("UNCHECKED_CAST")
100101
internal fun KType.kclass() = when (val t = classifier) {
101102
is KClass<*> -> t
102103
is KTypeParameter -> {
103-
error("Captured type paramerer $t from generic non-reified function. " +
104-
"Such functionality cannot be supported as $t is erased, either specify serializer explicitly or make " +
105-
"calling function inline with reified $t")
104+
error(
105+
"Captured type parameter $t from generic non-reified function. " +
106+
"Such functionality cannot be supported as $t is erased, either specify serializer explicitly or make " +
107+
"calling function inline with reified $t"
108+
)
106109
}
110+
107111
else -> error("Only KClass supported as classifier, got $t")
108112
} as KClass<Any>
109113

@@ -144,16 +148,6 @@ internal expect fun <T> createParametrizedCache(factory: (KClass<Any>, List<KTyp
144148

145149
internal expect fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KClass<T>): Array<E>
146150

147-
/**
148-
* Checks whether the receiver is an instance of a given kclass.
149-
*
150-
* This check is a replacement for [KClass.isInstance] because on JVM it requires kotlin-reflect.jar in classpath (see KT-14720).
151-
*
152-
* On JS and Native, this function delegates to aforementioned [KClass.isInstance] since it is supported there out-of-the-box;
153-
* on JVM, it falls back to `java.lang.Class.isInstance`, which causes difference when applied to function types with big arity.
154-
*/
155-
internal expect fun Any.isInstanceOf(kclass: KClass<*>): Boolean
156-
157151
internal inline fun <T, K> Iterable<T>.elementsHashCodeBy(selector: (T) -> K): Int {
158152
return fold(1) { hash, element -> 31 * hash + selector(element).hashCode() }
159153
}

core/commonMain/src/kotlinx/serialization/modules/SerializersModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ internal class SerialModuleImpl(
153153
) : SerializersModule() {
154154

155155
override fun <T : Any> getPolymorphic(baseClass: KClass<in T>, value: T): SerializationStrategy<T>? {
156-
if (!value.isInstanceOf(baseClass)) return null
156+
if (!baseClass.isInstance(value)) return null
157157
// Registered
158158
val registered = polyBase2Serializers[baseClass]?.get(value::class) as? SerializationStrategy<T>
159159
if (registered != null) return registered

core/jsMain/src/kotlinx/serialization/internal/Platform.kt

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,9 @@ internal actual fun <T> createParametrizedCache(factory: (KClass<Any>, List<KTyp
3838

3939
internal actual fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KClass<T>): Array<E> = toTypedArray()
4040

41-
internal actual fun Any.isInstanceOf(kclass: KClass<*>): Boolean = kclass.isInstance(this)
42-
4341
internal actual fun KClass<*>.platformSpecificSerializerNotRegistered(): Nothing {
4442
throw SerializationException(
45-
"Serializer for class '${simpleName}' is not found.\n" +
46-
"Mark the class as @Serializable or provide the serializer explicitly.\n" +
43+
"${notRegisteredMessage()}\n" +
4744
"On Kotlin/JS explicitly declared serializer should be used for interfaces and enums without @Serializable annotation"
4845
)
4946
}

core/jvmMain/src/kotlinx/serialization/SerializersJvm.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ public fun serializerOrNull(type: Type): KSerializer<Any>? = EmptySerializersMod
7373
* @throws IllegalArgumentException if an unsupported subclass of [Type] is provided.
7474
*/
7575
public fun SerializersModule.serializer(type: Type): KSerializer<Any> =
76-
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true) ?: type.prettyClass()
77-
.serializerNotRegistered()
76+
serializerByJavaTypeImpl(type, failOnMissingTypeArgSerializer = true)
77+
?: type.prettyClass().serializerNotRegistered()
7878

7979
/**
8080
* Retrieves a serializer for the given [type] using

core/jvmMain/src/kotlinx/serialization/internal/Platform.kt

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ internal actual inline fun BooleanArray.getChecked(index: Int): Boolean {
1818
return get(index)
1919
}
2020

21-
@Suppress("UNCHECKED_CAST")
2221
internal actual fun <T : Any> KClass<T>.compiledSerializerImpl(): KSerializer<T>? =
2322
this.constructSerializerForGivenTypeArgs()
2423

@@ -29,10 +28,7 @@ internal actual fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KCl
2928
internal actual fun KClass<*>.platformSpecificSerializerNotRegistered(): Nothing = serializerNotRegistered()
3029

3130
internal fun Class<*>.serializerNotRegistered(): Nothing {
32-
throw SerializationException(
33-
"Serializer for class '${simpleName}' is not found.\n" +
34-
"Mark the class as @Serializable or provide the serializer explicitly."
35-
)
31+
throw SerializationException(this.kotlin.notRegisteredMessage())
3632
}
3733

3834
internal actual fun <T : Any> KClass<T>.constructSerializerForGivenTypeArgs(vararg args: KSerializer<Any?>): KSerializer<T>? {
@@ -149,18 +145,4 @@ private fun <T : Any> Class<T>.findObjectSerializer(): KSerializer<T>? {
149145
return result as? KSerializer<T>
150146
}
151147

152-
/**
153-
* Checks if an [this@isInstanceOf] is an instance of a given [kclass].
154-
*
155-
* This check is a replacement for [KClass.isInstance] because
156-
* on JVM it requires kotlin-reflect.jar in classpath
157-
* (see https://youtrack.jetbrains.com/issue/KT-14720).
158-
*
159-
* On JS and Native, this function delegates to aforementioned
160-
* [KClass.isInstance] since it is supported there out-of-the box;
161-
* on JVM, it falls back to java.lang.Class.isInstance, which causes
162-
* difference when applied to function types with big arity.
163-
*/
164-
internal actual fun Any.isInstanceOf(kclass: KClass<*>): Boolean = kclass.javaObjectType.isInstance(this)
165-
166148
internal actual fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass.java.isArray

core/nativeMain/src/kotlinx/serialization/internal/Platform.kt

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ internal actual inline fun BooleanArray.getChecked(index: Int): Boolean {
1919

2020
internal actual fun KClass<*>.platformSpecificSerializerNotRegistered(): Nothing {
2121
throw SerializationException(
22-
"Serializer for class '${simpleName}' is not found.\n" +
23-
"Mark the class as @Serializable or provide the serializer explicitly.\n" +
22+
"${notRegisteredMessage()}\n" +
2423
"On Kotlin/Native explicitly declared serializer should be used for interfaces and enums without @Serializable annotation"
2524
)
2625
}
@@ -37,11 +36,7 @@ internal actual fun <T : Any> KClass<T>.constructSerializerForGivenTypeArgs(vara
3736
else -> null
3837
}
3938

40-
@Suppress(
41-
"UNCHECKED_CAST",
42-
"DEPRECATION_ERROR"
43-
)
44-
@OptIn(ExperimentalAssociatedObjects::class)
39+
@Suppress("DEPRECATION_ERROR")
4540
internal actual fun <T : Any> KClass<T>.compiledSerializerImpl(): KSerializer<T>? =
4641
this.constructSerializerForGivenTypeArgs()
4742

@@ -66,13 +61,11 @@ internal actual fun <T : Any, E : T?> ArrayList<E>.toNativeArrayImpl(eClass: KCl
6661
val result = arrayOfAnyNulls<E>(size)
6762
var index = 0
6863
for (element in this) result[index++] = element
69-
@Suppress("UNCHECKED_CAST", "USELESS_CAST")
64+
@Suppress("USELESS_CAST")
7065
return result as Array<E>
7166
}
7267

7368
@Suppress("UNCHECKED_CAST")
7469
private fun <T> arrayOfAnyNulls(size: Int): Array<T> = arrayOfNulls<Any>(size) as Array<T>
7570

76-
internal actual fun Any.isInstanceOf(kclass: KClass<*>): Boolean = kclass.isInstance(this)
77-
7871
internal actual fun isReferenceArray(rootClass: KClass<Any>): Boolean = rootClass == Array::class

docs/basic-serialization.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ When we run this code we get the exception.
7979

8080
```text
8181
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Project' is not found.
82-
Mark the class as @Serializable or provide the serializer explicitly.
82+
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
8383
```
8484

8585
<!--- TEST LINES_START -->

docs/polymorphism.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ We get an error, because the `OwnedProject` class is not serializable.
9292

9393
```text
9494
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'OwnedProject' is not found.
95-
Mark the class as @Serializable or provide the serializer explicitly.
95+
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
9696
```
9797

9898
<!--- TEST LINES_START -->
@@ -495,7 +495,7 @@ We get the exception.
495495

496496
```text
497497
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found.
498-
Mark the class as @Serializable or provide the serializer explicitly.
498+
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
499499
```
500500

501501
<!--- TEST LINES_START -->
@@ -543,7 +543,7 @@ However, the `Any` is a class and it is not serializable:
543543

544544
```text
545545
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found.
546-
Mark the class as @Serializable or provide the serializer explicitly.
546+
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
547547
```
548548

549549
<!--- TEST LINES_START -->

docs/serializers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -973,7 +973,7 @@ functions. Without it we'll get a "Serializer for class 'Date' is not found" exc
973973

974974
<!--- TEST LINES_START
975975
Exception in thread "main" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found.
976-
Mark the class as @Serializable or provide the serializer explicitly.
976+
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
977977
-->
978978

979979
<!--- INCLUDE

guide/test/BasicSerializationTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class BasicSerializationTest {
99
fun testExampleBasic01() {
1010
captureOutput("ExampleBasic01") { example.exampleBasic01.main() }.verifyOutputLinesStart(
1111
"Exception in thread \"main\" kotlinx.serialization.SerializationException: Serializer for class 'Project' is not found.",
12-
"Mark the class as @Serializable or provide the serializer explicitly."
12+
"Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
1313
)
1414
}
1515

guide/test/PolymorphismTest.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class PolymorphismTest {
1616
fun testExamplePoly02() {
1717
captureOutput("ExamplePoly02") { example.examplePoly02.main() }.verifyOutputLinesStart(
1818
"Exception in thread \"main\" kotlinx.serialization.SerializationException: Serializer for class 'OwnedProject' is not found.",
19-
"Mark the class as @Serializable or provide the serializer explicitly."
19+
"Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
2020
)
2121
}
2222

@@ -88,15 +88,15 @@ class PolymorphismTest {
8888
fun testExamplePoly12() {
8989
captureOutput("ExamplePoly12") { example.examplePoly12.main() }.verifyOutputLinesStart(
9090
"Exception in thread \"main\" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found.",
91-
"Mark the class as @Serializable or provide the serializer explicitly."
91+
"Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
9292
)
9393
}
9494

9595
@Test
9696
fun testExamplePoly13() {
9797
captureOutput("ExamplePoly13") { example.examplePoly13.main() }.verifyOutputLinesStart(
9898
"Exception in thread \"main\" kotlinx.serialization.SerializationException: Serializer for class 'Any' is not found.",
99-
"Mark the class as @Serializable or provide the serializer explicitly."
99+
"Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
100100
)
101101
}
102102

guide/test/SerializersTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class SerializersTest {
136136
fun testExampleSerializer19() {
137137
captureOutput("ExampleSerializer19") { example.exampleSerializer19.main() }.verifyOutputLinesStart(
138138
"Exception in thread \"main\" kotlinx.serialization.SerializationException: Serializer for class 'Date' is not found.",
139-
"Mark the class as @Serializable or provide the serializer explicitly."
139+
"Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied."
140140
)
141141
}
142142

0 commit comments

Comments
 (0)