summaryrefslogtreecommitdiff
path: root/src/library/scala/collection/immutable/List.scala
diff options
context:
space:
mode:
authorScott Carey <scottcarey+git@gmail.com>2013-12-06 18:07:41 -0800
committerScott Carey <scottcarey+git@gmail.com>2013-12-12 13:22:11 -0800
commita5fc6e69e0c26ca8537e01d17109e1037600af76 (patch)
treee826bf5f712029b5550ec32d059a6421fa7b6245 /src/library/scala/collection/immutable/List.scala
parent73cddba169a3b1fc1519a6128275dddceec3299a (diff)
downloadscala-a5fc6e69e0c26ca8537e01d17109e1037600af76.tar.gz
scala-a5fc6e69e0c26ca8537e01d17109e1037600af76.tar.bz2
scala-a5fc6e69e0c26ca8537e01d17109e1037600af76.zip
SI-8042 Use Serialization Proxy Pattern in List
Modify List to use the Serialization Proxy Pattern instead of directly mutating its state during deserialization. Use the proxy at the List level for both Nil and :: for simplicity. Change one member variable (hd) to val from var as a result. The other member variable (tl) cannot yet be changed to val because it is mutated by ListBuffer in the library and Types in reflection.
Diffstat (limited to 'src/library/scala/collection/immutable/List.scala')
-rw-r--r--src/library/scala/collection/immutable/List.scala58
1 files changed, 34 insertions, 24 deletions
diff --git a/src/library/scala/collection/immutable/List.scala b/src/library/scala/collection/immutable/List.scala
index 57618d64a5..90aabc5a9a 100644
--- a/src/library/scala/collection/immutable/List.scala
+++ b/src/library/scala/collection/immutable/List.scala
@@ -322,6 +322,39 @@ sealed abstract class List[+A] extends AbstractSeq[A]
override def toStream : Stream[A] =
if (isEmpty) Stream.Empty
else new Stream.Cons(head, tail.toStream)
+
+ // Create a proxy for Java serialization that allows us to avoid mutation
+ // during de-serialization. This is the Serialization Proxy Pattern.
+ protected final def writeReplace(): AnyRef = new SerializationProxy(this)
+}
+
+@SerialVersionUID(1L)
+private class SerializationProxy[B](@transient private var orig: List[B]) extends Serializable {
+
+ private def writeObject(out: ObjectOutputStream) {
+ var xs: List[B] = orig
+ while (!xs.isEmpty) {
+ out.writeObject(xs.head)
+ xs = xs.tail
+ }
+ out.writeObject(ListSerializeEnd)
+ }
+
+ // Java serialization calls this before readResolve during de-serialization.
+ // Read the whole list and store it in `orig`.
+ private def readObject(in: ObjectInputStream) {
+ val builder = List.newBuilder[B]
+ while (true) in.readObject match {
+ case ListSerializeEnd =>
+ orig = builder.result()
+ return
+ case a =>
+ builder += a.asInstanceOf[B]
+ }
+ }
+
+ // Provide the result stored in `orig` for Java serialization
+ private def readResolve(): AnyRef = orig
}
/** The empty list.
@@ -352,33 +385,10 @@ case object Nil extends List[Nothing] {
* @version 1.0, 15/07/2003
* @since 2.8
*/
-@SerialVersionUID(0L - 8476791151983527571L)
-final case class ::[B](private var hd: B, private[scala] var tl: List[B]) extends List[B] {
+final case class ::[B](private val hd: B, private[scala] var tl: List[B]) extends List[B] {
override def head : B = hd
override def tail : List[B] = tl
override def isEmpty: Boolean = false
-
- private def readObject(in: ObjectInputStream) {
- val firstObject = in.readObject()
- hd = firstObject.asInstanceOf[B]
- assert(hd != ListSerializeEnd)
- var current: ::[B] = this
- while (true) in.readObject match {
- case ListSerializeEnd =>
- current.tl = Nil
- return
- case a =>
- val list : ::[B] = new ::(a.asInstanceOf[B], Nil)
- current.tl = list
- current = list
- }
- }
-
- private def writeObject(out: ObjectOutputStream) {
- var xs: List[B] = this
- while (!xs.isEmpty) { out.writeObject(xs.head); xs = xs.tail }
- out.writeObject(ListSerializeEnd)
- }
}
/** $factoryInfo