Skip to content

Commit

Permalink
Workaround transient issue in JobCancellationException (#4291)
Browse files Browse the repository at this point in the history
Co-authored-by: Vsevolod Tolstopyatov <[email protected]>
  • Loading branch information
AlexRiedler and qwwdfsad authored Dec 4, 2024
1 parent 3c1f6d5 commit e670f62
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 2 deletions.
8 changes: 6 additions & 2 deletions kotlinx-coroutines-core/jvm/src/Exceptions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ internal actual class JobCancellationException public actual constructor(
override fun equals(other: Any?): Boolean =
other === this ||
other is JobCancellationException && other.message == message && other.job == job && other.cause == cause
override fun hashCode(): Int =
(message!!.hashCode() * 31 + job.hashCode()) * 31 + (cause?.hashCode() ?: 0)

override fun hashCode(): Int {
// since job is transient it is indeed nullable after deserialization
@Suppress("UNNECESSARY_SAFE_CALL")
return (message!!.hashCode() * 31 + (job?.hashCode() ?: 0)) * 31 + (cause?.hashCode() ?: 0)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,30 @@ class JobCancellationExceptionSerializerTest : TestBase() {
finish(4)
}
}

@Test
fun testHashCodeAfterDeserialization() = runTest {
try {
coroutineScope {
expect(1)
throw JobCancellationException(
message = "Job Cancelled",
job = Job(),
cause = null,
)
}
} catch (e: Throwable) {
finish(2)
val outputStream = ByteArrayOutputStream()
ObjectOutputStream(outputStream).use {
it.writeObject(e)
}
val deserializedException =
ObjectInputStream(outputStream.toByteArray().inputStream()).use {
it.readObject() as JobCancellationException
}
// verify hashCode does not fail even though Job is transient
assert(deserializedException.hashCode() != 0)
}
}
}

0 comments on commit e670f62

Please sign in to comment.