From 71777cc9ff27786d74bda55a00ab477a4e53efb5 Mon Sep 17 00:00:00 2001 From: Rex Kerr Date: Tue, 31 Mar 2015 01:14:31 -0700 Subject: SI-9197 Duration.Inf not a singleton when deserialized Made `Duration.Undefined`, `.Inf`, and `.MinusInf` all give back the singleton instance instead of creating a new copy by overriding readResolve. This override can be (and is) private, which at least on Sun's JDK8 doesn't mess with the auto-generated SerialVersionUIDs. Thus, the patch should make things strictly better: if you're on 2.11.7+ on JVMs which pick the same SerialVersionUIDs, you can recover singletons. Everywhere else you were already in trouble anyway. --- .../scala/concurrent/duration/Duration.scala | 5 ++++- .../concurrent/duration/SerializationTest.scala | 24 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 test/junit/scala/concurrent/duration/SerializationTest.scala diff --git a/src/library/scala/concurrent/duration/Duration.scala b/src/library/scala/concurrent/duration/Duration.scala index 2eded9f060..182c2d172a 100644 --- a/src/library/scala/concurrent/duration/Duration.scala +++ b/src/library/scala/concurrent/duration/Duration.scala @@ -182,6 +182,7 @@ object Duration { def compare(other: Duration) = if (other eq this) 0 else 1 def unary_- : Duration = this def toUnit(unit: TimeUnit): Double = Double.NaN + private def readResolve(): AnyRef = Undefined // Instructs deserialization to use this same instance } sealed abstract class Infinite extends Duration { @@ -230,7 +231,7 @@ object Duration { * but itself. This value closely corresponds to Double.PositiveInfinity, * matching its semantics in arithmetic operations. */ - val Inf: Infinite = new Infinite { + val Inf: Infinite = new Infinite { override def toString = "Duration.Inf" def compare(other: Duration) = other match { case x if x eq Undefined => -1 // Undefined != Undefined @@ -239,6 +240,7 @@ object Duration { } def unary_- : Duration = MinusInf def toUnit(unit: TimeUnit): Double = Double.PositiveInfinity + private def readResolve(): AnyRef = Inf // Instructs deserialization to use this same instance } /** @@ -251,6 +253,7 @@ object Duration { def compare(other: Duration) = if (other eq this) 0 else -1 def unary_- : Duration = Inf def toUnit(unit: TimeUnit): Double = Double.NegativeInfinity + private def readResolve(): AnyRef = MinusInf // Instructs deserialization to use this same instance } // Java Factories diff --git a/test/junit/scala/concurrent/duration/SerializationTest.scala b/test/junit/scala/concurrent/duration/SerializationTest.scala new file mode 100644 index 0000000000..af90a10984 --- /dev/null +++ b/test/junit/scala/concurrent/duration/SerializationTest.scala @@ -0,0 +1,24 @@ +package scala.concurrent.duration + +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 +import org.junit.Test + + +@RunWith(classOf[JUnit4]) +class SerializationTest { + @Test + def test_SI9197 { + def ser(a: AnyRef): Array[Byte] = { + val bais = new java.io.ByteArrayOutputStream + (new java.io.ObjectOutputStream(bais)).writeObject(a) + bais.toByteArray + } + def des(ab: Array[Byte]): AnyRef = + (new java.io.ObjectInputStream(new java.io.ByteArrayInputStream(ab))).readObject + + assert(Duration.Undefined eq des(ser(Duration.Undefined))) + assert(Duration.Inf eq des(ser(Duration.Inf))) + assert(Duration.MinusInf eq des(ser(Duration.MinusInf))) + } +} -- cgit v1.2.3