diff --git a/src/library/scala/collection/convert/JavaCollectionWrappers.scala b/src/library/scala/collection/convert/JavaCollectionWrappers.scala index 011980b70aca..4ee7a56383e0 100644 --- a/src/library/scala/collection/convert/JavaCollectionWrappers.scala +++ b/src/library/scala/collection/convert/JavaCollectionWrappers.scala @@ -332,11 +332,19 @@ private[collection] object JavaCollectionWrappers extends Serializable { def addOne(kv: (K, V)): this.type = { underlying.put(kv._1, kv._2); this } def subtractOne(key: K): this.type = { underlying remove key; this } - override def put(k: K, v: V): Option[V] = Option(underlying.put(k, v)) + override def put(k: K, v: V): Option[V] = { + val present = underlying.containsKey(k) + val result = underlying.put(k, v) + if (present) Some(result) else None + } override def update(k: K, v: V): Unit = { underlying.put(k, v) } - override def remove(k: K): Option[V] = Option(underlying remove k) + override def remove(k: K): Option[V] = { + val present = underlying.containsKey(k) + val result = underlying.remove(k) + if (present) Some(result) else None + } def iterator: Iterator[(K, V)] = new AbstractIterator[(K, V)] { val ui = underlying.entrySet.iterator diff --git a/test/junit/scala/jdk/CollectionConvertersTest.scala b/test/junit/scala/jdk/CollectionConvertersTest.scala new file mode 100644 index 000000000000..d30ee7264860 --- /dev/null +++ b/test/junit/scala/jdk/CollectionConvertersTest.scala @@ -0,0 +1,55 @@ +/* + * Scala (https://www.scala-lang.org) + * + * Copyright EPFL and Lightbend, Inc. + * + * Licensed under Apache License 2.0 + * (http://www.apache.org/licenses/LICENSE-2.0). + * + * See the NOTICE file distributed with this work for + * additional information regarding copyright ownership. + */ + +package scala.jdk + +import java.util.{ + Dictionary, + HashMap => JMap, + Hashtable => JTable, + Properties => JProperties, +} + +import org.junit.Assert.assertEquals +import org.junit.Test + +import scala.tools.testkit.AssertUtil.assertThrows + +import CollectionConverters._ + +class CollectionConvertersTest { + @Test def `t11894 Map wrapper respects put contract`(): Unit = { + val sut = new JMap[String, String].asScala + assertEquals(None, sut.put("one", null)) + assertEquals(Some(null), sut.put("one", "eins")) + assertEquals(Some("eins"), sut.put("one", "uno")) + assertEquals(Some("uno"), sut.remove("one")) + assertEquals(None, sut.remove("one")) + assertEquals(None, sut.put("one", null)) + assertEquals(Some(null), sut.remove("one")) + assertEquals(None, sut.remove("one")) + } + @Test def `t11894 Dictionary wrapper disallows nulls`(): Unit = { + val tbl = new JTable[String, String] + val sut = tbl.asInstanceOf[Dictionary[String, String]].asScala + assertThrows[NullPointerException](sut.put("any", null)) + } + @Test def `t11894 Properties wrapper enforces Strings`(): Unit = { + val ps = new JProperties() + val sut = ps.asScala + assertThrows[NullPointerException](sut.put("any", null)) + assertEquals(None, sut.put("one", "eins")) + assertEquals("eins", sut("one")) + ps.put("one", new Object()) + assertThrows[ClassCastException](sut.put("one", "uno")) + } +}