Skip to content

Commit 73f0480

Browse files
committed
Make unified collection serialization opt-in instead of opt-out
Fixes scala/bug#11192
1 parent 5c6a0db commit 73f0480

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+219
-145
lines changed

src/library/scala/Enumeration.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -316,8 +316,6 @@ abstract class Enumeration (initial: Int) extends Serializable {
316316
super[SortedSet].zip[B](that)
317317
override def collect[B](pf: PartialFunction[Value, B])(implicit @implicitNotFound(ValueSet.ordMsg) ev: Ordering[B]): SortedIterableCC[B] =
318318
super[SortedSet].collect[B](pf)
319-
320-
override protected[this] def writeReplace(): AnyRef = this
321319
}
322320

323321
/** A factory object for value sets */

src/library/scala/collection/Iterable.scala

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import scala.language.{higherKinds, implicitConversions}
1717
import scala.annotation.unchecked.uncheckedVariance
1818
import scala.collection.mutable.Builder
1919
import scala.collection.View.{LeftPartitionMapped, RightPartitionMapped}
20-
import scala.collection.generic.DefaultSerializationProxy
2120

2221
/** Base trait for generic collections.
2322
*
@@ -26,7 +25,7 @@ import scala.collection.generic.DefaultSerializationProxy
2625
* @define Coll `Iterable`
2726
* @define coll iterable collection
2827
*/
29-
trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterable[A]] with Serializable {
28+
trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterable[A]] {
3029

3130
// The collection itself
3231
final def toIterable: this.type = this
@@ -50,12 +49,6 @@ trait Iterable[+A] extends IterableOnce[A] with IterableOps[A, Iterable, Iterabl
5049
@deprecated("Iterable.seq always returns the iterable itself", "2.13.0")
5150
def seq: this.type = this
5251

53-
/** Create a proxy for Java serialization. The default implementation will serialize all elements and
54-
* deserialize by using a builder for `CC` via `iterableFactory`. Override in subclasses if more data needs
55-
* to be preserved or a more efficient implementation is available. Override to return `this` in order to
56-
* use self-serialization instead of a proxy. */
57-
protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(iterableFactory.iterableFactory, this)
58-
5952
/** Defines the prefix of this object's `toString` representation.
6053
*
6154
* It is recommended to return the name of the concrete collection type, but
@@ -866,10 +859,11 @@ object IterableOps {
866859
*
867860
* @define coll collection
868861
*/
862+
@SerialVersionUID(3L)
869863
class WithFilter[+A, +CC[_]](
870864
self: IterableOps[A, CC, _],
871865
p: A => Boolean
872-
) extends collection.WithFilter[A, CC] {
866+
) extends collection.WithFilter[A, CC] with Serializable {
873867

874868
protected def filtered: Iterable[A] =
875869
new View.Filter(self, p, isFlipped = false)

src/library/scala/collection/Map.scala

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ package scala
1414
package collection
1515

1616
import scala.annotation.unchecked.uncheckedVariance
17-
import scala.collection.generic.DefaultSerializationProxy
17+
import scala.collection.generic.DefaultSerializable
1818
import scala.collection.mutable.StringBuilder
1919
import scala.language.higherKinds
2020
import scala.util.hashing.MurmurHash3
@@ -59,8 +59,6 @@ trait Map[K, +V]
5959

6060
override def hashCode(): Int = MurmurHash3.mapHash(toIterable)
6161

62-
override protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(mapFactory.mapFactory[K, V], this)
63-
6462
// These two methods are not in MapOps so that MapView is not forced to implement them
6563
@deprecated("Use - or remove on an immutable Map", "2.13.0")
6664
def - (key: K): Map[K, V]
@@ -152,7 +150,7 @@ trait MapOps[K, +V, +CC[_, _] <: IterableOps[_, AnyConstr, _], +C]
152150

153151
/** The implementation class of the set returned by `keySet`.
154152
*/
155-
protected class KeySet extends AbstractSet[K] with GenKeySet {
153+
protected class KeySet extends AbstractSet[K] with GenKeySet with DefaultSerializable {
156154
def diff(that: Set[K]): Set[K] = fromSpecific(view.filterNot(that))
157155
}
158156

@@ -332,10 +330,11 @@ object MapOps {
332330
*
333331
* @define coll map collection
334332
*/
333+
@SerialVersionUID(3L)
335334
class WithFilter[K, +V, +IterableCC[_], +CC[_, _] <: IterableOps[_, AnyConstr, _]](
336335
self: MapOps[K, V, CC, _] with IterableOps[(K, V), IterableCC, _],
337336
p: ((K, V)) => Boolean
338-
) extends IterableOps.WithFilter[(K, V), IterableCC](self, p) {
337+
) extends IterableOps.WithFilter[(K, V), IterableCC](self, p) with Serializable {
339338

340339
def map[K2, V2](f: ((K, V)) => (K2, V2)): CC[K2, V2] =
341340
self.mapFactory.from(new View.Map(filtered, f))

src/library/scala/collection/SortedMap.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import scala.annotation.implicitNotFound
1717
import scala.collection.immutable.TreeMap
1818
import scala.language.higherKinds
1919
import scala.annotation.unchecked.uncheckedVariance
20-
import scala.collection.generic.DefaultSerializationProxy
2120

2221
/** Base type of sorted sets */
2322
trait SortedMap[K, +V]
@@ -41,8 +40,6 @@ trait SortedMap[K, +V]
4140

4241
override def empty: SortedMapCC[K, V] @uncheckedVariance = sortedMapFactory.empty
4342

44-
override protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(sortedMapFactory.sortedMapFactory[K, V], this)
45-
4643
override protected[this] def stringPrefix: String = "SortedMap"
4744
}
4845

src/library/scala/collection/SortedSet.scala

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ package scala.collection
1414

1515
import scala.annotation.implicitNotFound
1616
import scala.annotation.unchecked.uncheckedVariance
17-
import scala.collection.generic.DefaultSerializationProxy
1817
import scala.language.higherKinds
1918

2019
/** Base type of sorted sets */
@@ -36,8 +35,6 @@ trait SortedSet[A] extends Set[A] with SortedSetOps[A, SortedSet, SortedSet[A]]
3635

3736
override def empty: SortedIterableCC[A] = sortedIterableFactory.empty
3837

39-
override protected[this] def writeReplace(): AnyRef = new DefaultSerializationProxy(sortedIterableFactory.evidenceIterableFactory[A], this)
40-
4138
override protected[this] def stringPrefix: String = "SortedSet"
4239
}
4340

src/library/scala/collection/View.scala

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import scala.collection.immutable.LazyList
2424
* @define coll view
2525
* @define Coll `View`
2626
*/
27-
trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] {
27+
trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] with Serializable {
2828

2929
override def view: View[A] = this
3030

@@ -36,8 +36,6 @@ trait View[+A] extends Iterable[A] with IterableOps[A, View, View[A]] {
3636

3737
@deprecated("Views no longer know about their underlying collection type; .force always returns an IndexedSeq", "2.13.0")
3838
@`inline` def force: IndexedSeq[A] = toIndexedSeq
39-
40-
override protected[this] def writeReplace(): AnyRef = this
4139
}
4240

4341
/** This object reifies operations on views as case classes

src/library/scala/collection/WithFilter.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import scala.language.higherKinds
2222
*
2323
* @define coll collection
2424
*/
25-
abstract class WithFilter[+A, +CC[_]] {
25+
@SerialVersionUID(3L)
26+
abstract class WithFilter[+A, +CC[_]] extends Serializable {
2627

2728
/** Builds a new collection by applying a function to all elements of the
2829
* `filtered` outer $coll.

src/library/scala/collection/concurrent/TrieMap.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import java.io.{ObjectInputStream, ObjectOutputStream}
1818
import java.util.concurrent.atomic._
1919

2020
import scala.annotation.tailrec
21+
import scala.collection.generic.DefaultSerializable
2122
import scala.collection.immutable.{List, Nil}
2223
import scala.collection.mutable.GrowableBuilder
2324
import scala.util.hashing.Hashing
@@ -683,7 +684,8 @@ private[concurrent] case class RDCSS_Descriptor[K, V](old: INode[K, V], expected
683684
final class TrieMap[K, V] private (r: AnyRef, rtupd: AtomicReferenceFieldUpdater[TrieMap[K, V], AnyRef], hashf: Hashing[K], ef: Equiv[K])
684685
extends scala.collection.mutable.AbstractMap[K, V]
685686
with scala.collection.concurrent.Map[K, V]
686-
with scala.collection.mutable.MapOps[K, V, TrieMap, TrieMap[K, V]] {
687+
with scala.collection.mutable.MapOps[K, V, TrieMap, TrieMap[K, V]]
688+
with DefaultSerializable {
687689

688690
private[this] var hashingobj = if (hashf.isInstanceOf[Hashing.Default[_]]) new TrieMap.MangledHashing[K] else hashf
689691
private[this] var equalityobj = ef

src/library/scala/collection/convert/Wrappers.scala

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ private[collection] trait Wrappers {
3232
}
3333

3434
@SerialVersionUID(3L)
35-
case class IteratorWrapper[A](underlying: Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] {
35+
case class IteratorWrapper[A](underlying: Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] with Serializable {
3636
def hasNext = underlying.hasNext
3737
def next() = underlying.next()
3838
def hasMoreElements = underlying.hasNext
@@ -45,29 +45,29 @@ private[collection] trait Wrappers {
4545
}
4646

4747
@SerialVersionUID(3L)
48-
case class JIteratorWrapper[A](underlying: ju.Iterator[A]) extends AbstractIterator[A] with Iterator[A] {
48+
case class JIteratorWrapper[A](underlying: ju.Iterator[A]) extends AbstractIterator[A] with Iterator[A] with Serializable {
4949
def hasNext = underlying.hasNext
5050
def next() = underlying.next
5151
}
5252

5353
@SerialVersionUID(3L)
54-
case class JEnumerationWrapper[A](underlying: ju.Enumeration[A]) extends AbstractIterator[A] with Iterator[A] {
54+
case class JEnumerationWrapper[A](underlying: ju.Enumeration[A]) extends AbstractIterator[A] with Iterator[A] with Serializable {
5555
def hasNext = underlying.hasMoreElements
5656
def next() = underlying.nextElement
5757
}
5858

5959
@SerialVersionUID(3L)
60-
case class IterableWrapper[A](underlying: Iterable[A]) extends ju.AbstractCollection[A] with IterableWrapperTrait[A] { }
60+
case class IterableWrapper[A](underlying: Iterable[A]) extends ju.AbstractCollection[A] with IterableWrapperTrait[A] with Serializable { }
6161

6262
@SerialVersionUID(3L)
63-
case class JIterableWrapper[A](underlying: jl.Iterable[A]) extends AbstractIterable[A] {
63+
case class JIterableWrapper[A](underlying: jl.Iterable[A]) extends AbstractIterable[A] with Serializable{
6464
def iterator = underlying.iterator.asScala
6565
override def iterableFactory = mutable.ArrayBuffer
6666
override def isEmpty: Boolean = !underlying.iterator().hasNext
6767
}
6868

6969
@SerialVersionUID(3L)
70-
case class JCollectionWrapper[A](underlying: ju.Collection[A]) extends AbstractIterable[A] {
70+
case class JCollectionWrapper[A](underlying: ju.Collection[A]) extends AbstractIterable[A] with Serializable {
7171
def iterator = underlying.iterator.asScala
7272
override def size = underlying.size
7373
override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
@@ -76,12 +76,12 @@ private[collection] trait Wrappers {
7676
}
7777

7878
@SerialVersionUID(3L)
79-
case class SeqWrapper[A](underlying: Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
79+
case class SeqWrapper[A](underlying: Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] with Serializable {
8080
def get(i: Int) = underlying(i)
8181
}
8282

8383
@SerialVersionUID(3L)
84-
case class MutableSeqWrapper[A](underlying: mutable.Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
84+
case class MutableSeqWrapper[A](underlying: mutable.Seq[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] with Serializable {
8585
def get(i: Int) = underlying(i)
8686
override def set(i: Int, elem: A) = {
8787
val p = underlying(i)
@@ -91,15 +91,15 @@ private[collection] trait Wrappers {
9191
}
9292

9393
@SerialVersionUID(3L)
94-
case class MutableBufferWrapper[A](underlying: mutable.Buffer[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] {
94+
case class MutableBufferWrapper[A](underlying: mutable.Buffer[A]) extends ju.AbstractList[A] with IterableWrapperTrait[A] with Serializable {
9595
def get(i: Int) = underlying(i)
9696
override def set(i: Int, elem: A) = { val p = underlying(i); underlying(i) = elem; p }
9797
override def add(elem: A) = { underlying += elem; true }
9898
override def remove(i: Int) = underlying remove i
9999
}
100100

101101
@SerialVersionUID(3L)
102-
case class JListWrapper[A](underlying: ju.List[A]) extends mutable.AbstractBuffer[A] with SeqOps[A, mutable.Buffer, mutable.Buffer[A]] {
102+
case class JListWrapper[A](underlying: ju.List[A]) extends mutable.AbstractBuffer[A] with SeqOps[A, mutable.Buffer, mutable.Buffer[A]] with Serializable {
103103
def length = underlying.size
104104
override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
105105
override def isEmpty = underlying.isEmpty
@@ -179,7 +179,7 @@ private[collection] trait Wrappers {
179179
}
180180

181181
@SerialVersionUID(3L)
182-
case class MutableSetWrapper[A](underlying: mutable.Set[A]) extends SetWrapper[A](underlying) {
182+
case class MutableSetWrapper[A](underlying: mutable.Set[A]) extends SetWrapper[A](underlying) with Serializable {
183183
override def add(elem: A) = {
184184
val sz = underlying.size
185185
underlying += elem
@@ -192,7 +192,7 @@ private[collection] trait Wrappers {
192192
}
193193

194194
@SerialVersionUID(3L)
195-
case class JSetWrapper[A](underlying: ju.Set[A]) extends mutable.AbstractSet[A] with mutable.SetOps[A, mutable.Set, mutable.Set[A]] {
195+
case class JSetWrapper[A](underlying: ju.Set[A]) extends mutable.AbstractSet[A] with mutable.SetOps[A, mutable.Set, mutable.Set[A]] with Serializable {
196196

197197
override def size = underlying.size
198198
override def isEmpty: Boolean = underlying.isEmpty
@@ -311,7 +311,7 @@ private[collection] trait Wrappers {
311311
@SerialVersionUID(3L)
312312
abstract class AbstractJMapWrapper[K, V]
313313
extends mutable.AbstractMap[K, V]
314-
with JMapWrapperLike[K, V, mutable.Map, mutable.Map[K, V]]
314+
with JMapWrapperLike[K, V, mutable.Map, mutable.Map[K, V]] with Serializable
315315

316316
trait JMapWrapperLike[K, V, +CC[X, Y] <: mutable.MapOps[X, Y, CC, _], +C <: mutable.MapOps[K, V, CC, C]]
317317
extends mutable.MapOps[K, V, CC, C] {
@@ -358,7 +358,7 @@ private[collection] trait Wrappers {
358358
*/
359359
@SerialVersionUID(3L)
360360
class JMapWrapper[K, V](val underlying : ju.Map[K, V])
361-
extends AbstractJMapWrapper[K, V] {
361+
extends AbstractJMapWrapper[K, V] with Serializable {
362362

363363
override def isEmpty: Boolean = underlying.isEmpty
364364
override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
@@ -414,7 +414,7 @@ private[collection] trait Wrappers {
414414
}
415415

416416
@SerialVersionUID(3L)
417-
case class DictionaryWrapper[K, V](underlying: mutable.Map[K, V]) extends ju.Dictionary[K, V] {
417+
case class DictionaryWrapper[K, V](underlying: mutable.Map[K, V]) extends ju.Dictionary[K, V] with Serializable {
418418
def size: Int = underlying.size
419419
def isEmpty: Boolean = underlying.isEmpty
420420
def keys: ju.Enumeration[K] = asJavaEnumeration(underlying.keysIterator)
@@ -442,7 +442,7 @@ private[collection] trait Wrappers {
442442
}
443443

444444
@SerialVersionUID(3L)
445-
case class JDictionaryWrapper[K, V](underlying: ju.Dictionary[K, V]) extends mutable.AbstractMap[K, V] {
445+
case class JDictionaryWrapper[K, V](underlying: ju.Dictionary[K, V]) extends mutable.AbstractMap[K, V] with Serializable {
446446
override def size: Int = underlying.size
447447
override def isEmpty: Boolean = underlying.isEmpty
448448
override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
@@ -466,7 +466,7 @@ private[collection] trait Wrappers {
466466

467467
@SerialVersionUID(3L)
468468
case class JPropertiesWrapper(underlying: ju.Properties) extends mutable.AbstractMap[String, String]
469-
with mutable.MapOps[String, String, mutable.Map, mutable.Map[String, String]] {
469+
with mutable.MapOps[String, String, mutable.Map, mutable.Map[String, String]] with Serializable {
470470

471471
override def size = underlying.size
472472
override def isEmpty: Boolean = underlying.isEmpty

src/library/scala/collection/generic/DefaultSerializationProxy.scala

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,21 @@ final class DefaultSerializationProxy[A](factory: Factory[A, Any], @transient pr
6767

6868
@SerialVersionUID(3L)
6969
private[collection] case object SerializeEnd
70+
71+
/** Mix-in trait to enable DefaultSerializationProxy for the standard collection types. Depending on the type
72+
* it is mixed into, it will dynamically choose `iterableFactory`, `mapFactory`, `sortedIterableFactory` or
73+
* `sortedMapFactory` for deserialization into the respective `CC` type. Override `writeReplace` or implement
74+
* it directly without using this trait if you need a non-standard factory or if you want to use a different
75+
* serialization scheme.
76+
*/
77+
trait DefaultSerializable extends Serializable { this: scala.collection.Iterable[_] =>
78+
protected[this] def writeReplace(): AnyRef = {
79+
val f: Factory[Any, Any] = this match {
80+
case it: scala.collection.SortedMap[_, _] => it.sortedMapFactory.sortedMapFactory[Any, Any](it.ordering.asInstanceOf[Ordering[Any]]).asInstanceOf[Factory[Any, Any]]
81+
case it: scala.collection.Map[_, _] => it.mapFactory.mapFactory[Any, Any].asInstanceOf[Factory[Any, Any]]
82+
case it: scala.collection.SortedSet[_] => it.sortedIterableFactory.evidenceIterableFactory[Any](it.ordering.asInstanceOf[Ordering[Any]])
83+
case it => it.iterableFactory.iterableFactory
84+
}
85+
new DefaultSerializationProxy(f, this)
86+
}
87+
}

src/library/scala/collection/immutable/ArraySeq.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ sealed abstract class ArraySeq[+A]
3737
extends AbstractSeq[A]
3838
with IndexedSeq[A]
3939
with IndexedSeqOps[A, ArraySeq, ArraySeq[A]]
40-
with StrictOptimizedSeqOps[A, ArraySeq, ArraySeq[A]] {
40+
with StrictOptimizedSeqOps[A, ArraySeq, ArraySeq[A]]
41+
with Serializable {
4142

4243
/** The tag of the element type. This does not have to be equal to the element type of this ArraySeq. A primitive
4344
* ArraySeq can be backed by an array of boxed values and a reference ArraySeq can be backed by an array of a supertype
@@ -157,8 +158,6 @@ sealed abstract class ArraySeq[+A]
157158
copied
158159
}
159160

160-
override protected[this] def writeReplace(): AnyRef = this
161-
162161
override protected final def applyPreferredMaxLength: Int = Int.MaxValue
163162

164163
override def sorted[B >: A](implicit ord: Ordering[B]): ArraySeq[A] =

src/library/scala/collection/immutable/BitSet.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ sealed abstract class BitSet
3232
with SortedSetOps[Int, SortedSet, BitSet]
3333
with StrictOptimizedSortedSetOps[Int, SortedSet, BitSet]
3434
with collection.BitSet
35-
with collection.BitSetOps[BitSet] {
35+
with collection.BitSetOps[BitSet]
36+
with Serializable {
3637

3738
override def unsorted: Set[Int] = this
3839

@@ -77,7 +78,7 @@ sealed abstract class BitSet
7778
override def zip[B](that: scala.IterableOnce[B])(implicit @implicitNotFound(collection.BitSet.zipOrdMsg) ev: Ordering[(Int, B)]): SortedSet[(Int, B)] =
7879
super.zip(that)
7980

80-
override protected[this] def writeReplace(): AnyRef = new BitSet.SerializationProxy(this)
81+
protected[this] def writeReplace(): AnyRef = new BitSet.SerializationProxy(this)
8182
}
8283

8384
/**

src/library/scala/collection/immutable/HashMap.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import java.lang.System.arraycopy
1818

1919
import scala.annotation.unchecked.{uncheckedVariance => uV}
2020
import scala.collection.Hashing.improve
21+
import scala.collection.generic.DefaultSerializable
2122
import scala.collection.mutable.{Builder, ReusableBuilder}
2223
import scala.collection.{Iterator, MapFactory, StrictOptimizedIterableOps, mutable}
2324
import scala.util.hashing.MurmurHash3
@@ -37,7 +38,8 @@ import scala.runtime.Statics.releaseFence
3738

3839
final class HashMap[K, +V] private[immutable] (private[immutable] val rootNode: MapNode[K, V])
3940
extends AbstractMap[K, V]
40-
with StrictOptimizedMapOps[K, V, HashMap, HashMap[K, V]] {
41+
with StrictOptimizedMapOps[K, V, HashMap, HashMap[K, V]]
42+
with DefaultSerializable {
4143

4244
def this() = this(MapNode.empty)
4345

0 commit comments

Comments
 (0)