Make Random implementations serializable (KT-25571)

Make Random.Default, XorWowRandom, and wrapper classes for JDK Random implement Serializable interface.

Co-authored-by: Ilya Gorbunov <ilya.gorbunov@jetbrains.com>
This commit is contained in:
Iaroslav Postovalov
2020-12-31 08:10:28 +07:00
committed by GitHub
parent 38967f208e
commit 00506a75d3
7 changed files with 116 additions and 16 deletions
@@ -5,8 +5,8 @@
package kotlin.random
import kotlin.UnsupportedOperationException
import kotlin.internal.*
import kotlin.internal.IMPLEMENTATIONS
import kotlin.internal.InlineOnly
/**
* Creates a [java.util.Random][java.util.Random] instance that uses the specified Kotlin [Random] generator as a randomness source.
@@ -49,15 +49,18 @@ internal abstract class AbstractPlatformRandom : Random() {
internal class FallbackThreadLocalRandom : AbstractPlatformRandom() {
private val implStorage = object : ThreadLocal<java.util.Random>() {
override fun initialValue(): java.util.Random {
return java.util.Random()
}
override fun initialValue(): java.util.Random = java.util.Random()
}
override val impl: java.util.Random
get() = implStorage.get()
}
private class PlatformRandom(override val impl: java.util.Random) : AbstractPlatformRandom()
private class PlatformRandom(override val impl: java.util.Random) : AbstractPlatformRandom(), Serializable {
private companion object {
private const val serialVersionUID: Long = 0L
}
}
private class KotlinRandom(val impl: Random) : java.util.Random() {
override fun next(bits: Int): Int = impl.nextBits(bits)
@@ -73,6 +76,7 @@ private class KotlinRandom(val impl: Random) : java.util.Random() {
}
private var seedInitialized: Boolean = false
override fun setSeed(seed: Long) {
if (!seedInitialized) {
// ignore seed value from constructor
@@ -81,4 +85,8 @@ private class KotlinRandom(val impl: Random) : java.util.Random() {
throw UnsupportedOperationException("Setting seed is not supported.")
}
}
private companion object {
private const val serialVersionUID: Long = 0L
}
}
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package random
import test.io.deserializeFromHex
import test.io.serializeAndDeserialize
import kotlin.random.Random
import kotlin.random.asJavaRandom
import kotlin.random.asKotlinRandom
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertSame
import kotlin.test.assertTrue
class RandomSerializationTest {
@Test
fun defaultIsSerializable() {
val instance = Random
discardSomeValues(instance)
assertSame(instance, serializeAndDeserialize(instance))
}
private fun discardSomeValues(instance: Random) {
instance.nextInt()
instance.nextDouble()
instance.nextLong()
instance.nextBytes(64)
}
private fun testRandomsHaveSameState(first: Random, second: Random) {
assertEquals(first.nextInt(), second.nextInt())
assertEquals(first.nextDouble(), second.nextDouble())
assertEquals(first.nextLong(), second.nextLong())
assertTrue(first.nextBytes(64).contentEquals(second.nextBytes(64)))
}
@Test
fun deserializeDefault() = assertSame(
expected = Random,
actual = deserializeFromHex("ac ed 00 05 73 72 00 22 6b 6f 74 6c 69 6e 2e 72 61 6e 64 6f 6d 2e 52 61 6e 64 6f 6d 24 44 65 66 61 75 6c 74 24 44 75 6d 6d 79 00 00 00 00 00 00 00 00 02 00 00 78 70"),
)
@Test
fun deserializeXorWow() {
val instance = Random(0)
val deserialized =
deserializeFromHex<Random>("ac ed 00 05 73 72 00 1a 6b 6f 74 6c 69 6e 2e 72 61 6e 64 6f 6d 2e 58 6f 72 57 6f 77 52 61 6e 64 6f 6d 00 00 00 00 00 00 00 00 02 00 06 49 00 06 61 64 64 65 6e 64 49 00 01 76 49 00 01 77 49 00 01 78 49 00 01 79 49 00 01 7a 78 70 01 61 f1 40 23 9d 3d b3 c9 07 82 1d 6a 67 48 b0 e3 f9 bd 0c b6 5b de 32")
testRandomsHaveSameState(instance, deserialized)
}
@Test
fun xorwowIsSerializable() {
val instance = Random(0)
discardSomeValues(instance)
val deserialized = serializeAndDeserialize(instance)
testRandomsHaveSameState(instance, deserialized)
}
@Test
fun wrapperOfKotlinRandomIsSerializable() {
val java = Random(0).asJavaRandom()
java.nextInt()
java.nextDouble()
java.nextLong()
java.nextBytes(ByteArray(64) { 0 })
val deserialized = serializeAndDeserialize(java)
testRandomsHaveSameState(java.asKotlinRandom(), deserialized.asKotlinRandom())
}
@Test
fun wrapperOfJavaRandomIsSerializable() {
val kotlin = java.util.Random(0).asKotlinRandom()
discardSomeValues(kotlin)
val deserialized = serializeAndDeserialize(kotlin)
testRandomsHaveSameState(kotlin, deserialized)
}
}