@@ -21,6 +21,7 @@ import java.{lang => jl, util => ju}
21
21
import scala .jdk .CollectionConverters ._
22
22
import scala .util .Try
23
23
import scala .util .chaining ._
24
+ import scala .util .control .ControlThrowable
24
25
25
26
/** Wrappers for exposing Scala collections as Java collections and vice-versa */
26
27
@ SerialVersionUID (3L )
@@ -332,7 +333,12 @@ private[collection] object JavaCollectionWrappers extends Serializable {
332
333
else
333
334
None
334
335
}
335
- override def getOrElseUpdate (key : K , op : => V ): V = underlying.computeIfAbsent(key, _ => op)
336
+
337
+ override def getOrElseUpdate (key : K , op : => V ): V =
338
+ underlying.computeIfAbsent(key, _ => op) match {
339
+ case null => update(key, null .asInstanceOf [V ]); null .asInstanceOf [V ]
340
+ case v => v
341
+ }
336
342
337
343
def addOne (kv : (K , V )): this .type = { underlying.put(kv._1, kv._2); this }
338
344
def subtractOne (key : K ): this .type = { underlying remove key; this }
@@ -355,8 +361,17 @@ private[collection] object JavaCollectionWrappers extends Serializable {
355
361
356
362
override def update (k : K , v : V ): Unit = underlying.put(k, v)
357
363
358
- override def updateWith (key : K )(remappingFunction : Option [V ] => Option [V ]): Option [V ] = Option {
359
- underlying.compute(key, (_, v) => remappingFunction(Option (v)).getOrElse(null .asInstanceOf [V ]))
364
+ override def updateWith (key : K )(remappingFunction : Option [V ] => Option [V ]): Option [V ] = {
365
+ def remap (k : K , v : V ): V =
366
+ remappingFunction(Option (v)) match {
367
+ case Some (null ) => throw PutNull
368
+ case Some (x) => x
369
+ case None => null .asInstanceOf [V ]
370
+ }
371
+ try Option (underlying.compute(key, remap))
372
+ catch {
373
+ case PutNull => update(key, null .asInstanceOf [V ]); Some (null .asInstanceOf [V ])
374
+ }
360
375
}
361
376
362
377
// support Some(null) if currently bound to null
@@ -441,7 +456,11 @@ private[collection] object JavaCollectionWrappers extends Serializable {
441
456
442
457
override def get (k : K ) = Option (underlying get k)
443
458
444
- override def getOrElseUpdate (key : K , op : => V ): V = underlying.computeIfAbsent(key, _ => op)
459
+ override def getOrElseUpdate (key : K , op : => V ): V =
460
+ underlying.computeIfAbsent(key, _ => op) match {
461
+ case null => super /* [concurrent.Map]*/ .getOrElseUpdate(key, op)
462
+ case v => v
463
+ }
445
464
446
465
override def isEmpty : Boolean = underlying.isEmpty
447
466
override def knownSize : Int = if (underlying.isEmpty) 0 else super .knownSize
@@ -462,8 +481,17 @@ private[collection] object JavaCollectionWrappers extends Serializable {
462
481
case _ => Try (last).toOption
463
482
}
464
483
465
- override def updateWith (key : K )(remappingFunction : Option [V ] => Option [V ]): Option [V ] = Option {
466
- underlying.compute(key, (_, v) => remappingFunction(Option (v)).getOrElse(null .asInstanceOf [V ]))
484
+ override def updateWith (key : K )(remappingFunction : Option [V ] => Option [V ]): Option [V ] = {
485
+ def remap (k : K , v : V ): V =
486
+ remappingFunction(Option (v)) match {
487
+ case Some (null ) => throw PutNull // see scala/scala#10129
488
+ case Some (x) => x
489
+ case None => null .asInstanceOf [V ]
490
+ }
491
+ try Option (underlying.compute(key, remap))
492
+ catch {
493
+ case PutNull => super /* [concurrent.Map]*/ .updateWith(key)(remappingFunction)
494
+ }
467
495
}
468
496
}
469
497
@@ -572,4 +600,7 @@ private[collection] object JavaCollectionWrappers extends Serializable {
572
600
573
601
override def mapFactory = mutable.HashMap
574
602
}
603
+
604
+ /** Thrown when certain Map operations attempt to put a null value. */
605
+ private val PutNull = new ControlThrowable {}
575
606
}
0 commit comments