Skip to content

Commit e27a4e7

Browse files
authored
Merge pull request scala/scala#10129 from som-snytt/followup/12586-preserve-NPE
Preserve null policy in wrapped Java Map
2 parents dd191e7 + 0753d9c commit e27a4e7

File tree

2 files changed

+38
-7
lines changed

2 files changed

+38
-7
lines changed

library/src/scala/collection/concurrent/Map.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ trait Map[K, V] extends scala.collection.mutable.Map[K, V] {
9797
case None =>
9898
val v = op
9999
putIfAbsent(key, v) match {
100-
case Some(nv) => nv
100+
case Some(ov) => ov
101101
case None => v
102102
}
103103
}

library/src/scala/collection/convert/JavaCollectionWrappers.scala

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import java.{lang => jl, util => ju}
2121
import scala.jdk.CollectionConverters._
2222
import scala.util.Try
2323
import scala.util.chaining._
24+
import scala.util.control.ControlThrowable
2425

2526
/** Wrappers for exposing Scala collections as Java collections and vice-versa */
2627
@SerialVersionUID(3L)
@@ -332,7 +333,12 @@ private[collection] object JavaCollectionWrappers extends Serializable {
332333
else
333334
None
334335
}
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+
}
336342

337343
def addOne(kv: (K, V)): this.type = { underlying.put(kv._1, kv._2); this }
338344
def subtractOne(key: K): this.type = { underlying remove key; this }
@@ -355,8 +361,17 @@ private[collection] object JavaCollectionWrappers extends Serializable {
355361

356362
override def update(k: K, v: V): Unit = underlying.put(k, v)
357363

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+
}
360375
}
361376

362377
// support Some(null) if currently bound to null
@@ -441,7 +456,11 @@ private[collection] object JavaCollectionWrappers extends Serializable {
441456

442457
override def get(k: K) = Option(underlying get k)
443458

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+
}
445464

446465
override def isEmpty: Boolean = underlying.isEmpty
447466
override def knownSize: Int = if (underlying.isEmpty) 0 else super.knownSize
@@ -462,8 +481,17 @@ private[collection] object JavaCollectionWrappers extends Serializable {
462481
case _ => Try(last).toOption
463482
}
464483

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+
}
467495
}
468496
}
469497

@@ -572,4 +600,7 @@ private[collection] object JavaCollectionWrappers extends Serializable {
572600

573601
override def mapFactory = mutable.HashMap
574602
}
603+
604+
/** Thrown when certain Map operations attempt to put a null value. */
605+
private val PutNull = new ControlThrowable {}
575606
}

0 commit comments

Comments
 (0)