From ecd131a7a14cc2d5452cfd24ce80e9c470880261 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Tue, 16 Jun 2015 18:35:33 +0300 Subject: [PATCH] Lazy made serializable. --- libraries/stdlib/src/kotlin/util/Lazy.kt | 26 ++++++++--- .../test/collections/CollectionJVMTest.kt | 20 +++++---- libraries/stdlib/test/utils/LazyJVMTest.kt | 36 +++++++++++++++ libraries/stdlib/test/utils/LazyTest.kt | 45 +++++++++++++++++++ 4 files changed, 112 insertions(+), 15 deletions(-) create mode 100644 libraries/stdlib/test/utils/LazyJVMTest.kt create mode 100644 libraries/stdlib/test/utils/LazyTest.kt diff --git a/libraries/stdlib/src/kotlin/util/Lazy.kt b/libraries/stdlib/src/kotlin/util/Lazy.kt index 3ed0b371e1f..7cf7e34815e 100644 --- a/libraries/stdlib/src/kotlin/util/Lazy.kt +++ b/libraries/stdlib/src/kotlin/util/Lazy.kt @@ -1,5 +1,7 @@ package kotlin +import java.io.Serializable + /** * Represents a value with lazy initialization. @@ -40,11 +42,11 @@ public enum class LazyThreadSafetyMode { private object UNINITIALIZED_VALUE -private class LazyImpl(initializer: () -> T) : Lazy { +private class LazyImpl(initializer: () -> T) : Lazy, Serializable { private var initializer: (() -> T)? = initializer private volatile var _value: Any? = UNINITIALIZED_VALUE - public override val value: T + override val value: T get() { val _v1 = _value if (_v1 !== UNINITIALIZED_VALUE) { @@ -65,16 +67,16 @@ private class LazyImpl(initializer: () -> T) : Lazy { } } - override val valueCreated: Boolean = _value !== UNINITIALIZED_VALUE + override val valueCreated: Boolean get() = _value !== UNINITIALIZED_VALUE override fun toString(): String = if (valueCreated) value.toString() else "Lazy value not initialized yet." + + private fun writeReplace(): Any = InitializedLazyImpl(value) } -private class UnsafeLazyImpl(initializer: () -> T) : Lazy { +private class UnsafeLazyImpl(initializer: () -> T) : Lazy, Serializable { private var initializer: (() -> T)? = initializer - - private var _value: Any? = UNINITIALIZED_VALUE override val value: T @@ -86,7 +88,17 @@ private class UnsafeLazyImpl(initializer: () -> T) : Lazy { return _value as T } - override val valueCreated: Boolean = _value !== UNINITIALIZED_VALUE + override val valueCreated: Boolean get() = _value !== UNINITIALIZED_VALUE override fun toString(): String = if (valueCreated) value.toString() else "Lazy value not initialized yet." + + private fun writeReplace(): Any = InitializedLazyImpl(value) +} + +private class InitializedLazyImpl(override val value: T) : Lazy, Serializable { + + override val valueCreated: Boolean get() = true + + override fun toString(): String = value.toString() + } diff --git a/libraries/stdlib/test/collections/CollectionJVMTest.kt b/libraries/stdlib/test/collections/CollectionJVMTest.kt index 5d8b7d0f546..2d7d658290d 100644 --- a/libraries/stdlib/test/collections/CollectionJVMTest.kt +++ b/libraries/stdlib/test/collections/CollectionJVMTest.kt @@ -154,19 +154,23 @@ class CollectionJVMTest { test fun emptyMapIsSerializable() = testSingletonSerialization(emptyMap()) private fun testSingletonSerialization(value: Any) { - val outputStream = ByteArrayOutputStream() - val objectOuputStream = ObjectOutputStream(outputStream) + val result = serializeAndDeserialize(value) - objectOuputStream.writeObject(value) - objectOuputStream.close() + assertEquals(value, result) + assertTrue(value === result) + } + + private fun serializeAndDeserialize(value: T): T { + val outputStream = ByteArrayOutputStream() + val objectOutputStream = ObjectOutputStream(outputStream) + + objectOutputStream.writeObject(value) + objectOutputStream.close() outputStream.close() val inputStream = ByteArrayInputStream(outputStream.toByteArray()) val inputObjectStream = ObjectInputStream(inputStream) - val result = inputObjectStream.readObject() - - assertEquals(value, result) - assertTrue(value === result) + return inputObjectStream.readObject() as T } } diff --git a/libraries/stdlib/test/utils/LazyJVMTest.kt b/libraries/stdlib/test/utils/LazyJVMTest.kt new file mode 100644 index 00000000000..b5bde85cda0 --- /dev/null +++ b/libraries/stdlib/test/utils/LazyJVMTest.kt @@ -0,0 +1,36 @@ +package test.utils + + +import kotlin.* +import kotlin.test.* +import java.io.* +import org.junit.Test as test + +class LazyJVMTest { + + test fun lazyInitializationForcedOnSerialization() { + for(mode in listOf(LazyThreadSafetyMode.SYNCHRONIZED, LazyThreadSafetyMode.NONE)) { + val lazy = lazy(mode) { "initialized" } + assertFalse(lazy.valueCreated) + val lazy2 = serializeAndDeserialize(lazy) + assertTrue(lazy.valueCreated) + assertTrue(lazy2.valueCreated) + assertEquals(lazy.value, lazy2.value) + } + } + + + private fun serializeAndDeserialize(value: T): T { + val outputStream = ByteArrayOutputStream() + val objectOutputStream = ObjectOutputStream(outputStream) + + objectOutputStream.writeObject(value) + objectOutputStream.close() + outputStream.close() + + val inputStream = ByteArrayInputStream(outputStream.toByteArray()) + val inputObjectStream = ObjectInputStream(inputStream) + return inputObjectStream.readObject() as T + } + +} \ No newline at end of file diff --git a/libraries/stdlib/test/utils/LazyTest.kt b/libraries/stdlib/test/utils/LazyTest.kt new file mode 100644 index 00000000000..8e17496ad9b --- /dev/null +++ b/libraries/stdlib/test/utils/LazyTest.kt @@ -0,0 +1,45 @@ +package test.utils + +import kotlin.* +import kotlin.test.* +import org.junit.Test as test + +class LazyTest { + + test fun initializationCalledOnce() { + var callCount = 0 + val lazyInt = lazy { ++callCount } + + assertEquals(0, callCount) + assertEquals(1, lazyInt.value) + assertEquals(1, callCount) + + lazyInt.value + assertEquals(1, callCount) + } + + test fun valueCreated() { + var callCount = 0 + val lazyInt = lazy { ++callCount } + + assertFalse(lazyInt.valueCreated) + assertEquals(0, callCount) + + lazyInt.value + + assertTrue(lazyInt.valueCreated) + } + + + test fun lazyToString() { + var callCount = 0 + val lazyInt = lazy { ++callCount } + + assertNotEquals("1", lazyInt.toString()) + assertEquals(0, callCount) + + assertEquals(1, lazyInt.value) + assertEquals("1", lazyInt.toString()) + assertEquals(1, callCount) + } +} \ No newline at end of file