diff --git a/integration-testing/src/withGuavaTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt b/integration-testing/src/withGuavaTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt index fefcc00528..ab0b7a7ecb 100644 --- a/integration-testing/src/withGuavaTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt +++ b/integration-testing/src/withGuavaTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt @@ -7,6 +7,8 @@ package kotlinx.coroutines import com.google.common.reflect.* import kotlinx.coroutines.* import org.junit.Test +import java.io.Serializable +import java.lang.reflect.Modifier import kotlin.test.* class ListAllCoroutineThrowableSubclassesTest { @@ -31,13 +33,21 @@ class ListAllCoroutineThrowableSubclassesTest { "kotlinx.coroutines.channels.ClosedReceiveChannelException", "kotlinx.coroutines.flow.internal.ChildCancelledException", "kotlinx.coroutines.flow.internal.AbortFlowException", - ) + ) @Test fun testThrowableSubclassesAreSerializable() { val classes = ClassPath.from(this.javaClass.classLoader) .getTopLevelClassesRecursive("kotlinx.coroutines"); val throwables = classes.filter { Throwable::class.java.isAssignableFrom(it.load()) }.map { it.toString() } + for (throwable in throwables) { + for (field in throwable.javaClass.declaredFields) { + if (Modifier.isStatic(field.modifiers)) continue + val type = field.type + assertTrue(type.isPrimitive || Serializable::class.java.isAssignableFrom(type), + "Throwable $throwable has non-serializable field $field") + } + } assertEquals(knownThrowables.sorted(), throwables.sorted()) } } diff --git a/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt b/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt index 4259092e78..0d68b047f4 100644 --- a/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt +++ b/kotlinx-coroutines-core/jvm/src/CoroutineExceptionHandlerImpl.kt @@ -29,7 +29,7 @@ private val handlers: List = ServiceLoader.load( * The purpose of this exception is to add an otherwise inaccessible diagnostic information and to * be able to poke the failing coroutine context in the debugger. */ -private class DiagnosticCoroutineContextException(private val context: CoroutineContext) : RuntimeException() { +private class DiagnosticCoroutineContextException(@Transient private val context: CoroutineContext) : RuntimeException() { override fun getLocalizedMessage(): String { return context.toString() }