diff options
author | Martin Odersky <odersky@gmail.com> | 2010-05-15 20:11:01 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2010-05-15 20:11:01 +0000 |
commit | 54523bc2fc3cd0100e082a3c42b9015398f71171 (patch) | |
tree | 93603556d10d5572424278abe900619a1cf5e3e9 | |
parent | bf82ecbcbeaa3a6975e360c2b616ce37938df80f (diff) | |
download | scala-54523bc2fc3cd0100e082a3c42b9015398f71171.tar.gz scala-54523bc2fc3cd0100e082a3c42b9015398f71171.tar.bz2 scala-54523bc2fc3cd0100e082a3c42b9015398f71171.zip |
Made javaConversions more general.
-rw-r--r-- | src/library/scala/collection/JavaConversions.scala | 236 |
1 files changed, 148 insertions, 88 deletions
diff --git a/src/library/scala/collection/JavaConversions.scala b/src/library/scala/collection/JavaConversions.scala index 05b192e25b..c1a39e0332 100644 --- a/src/library/scala/collection/JavaConversions.scala +++ b/src/library/scala/collection/JavaConversions.scala @@ -23,9 +23,8 @@ package scala.collection * <li><code>scala.collection.Iterator</code> <=> <code>java.util.{ Iterator, Enumeration }</code></li> * <li><code>scala.collection.mutable.Buffer</code> <=> <code>java.util.List</code></li> * <li><code>scala.collection.mutable.Set</code> <=> <code>java.util.Set</code></li> - * <li><code>scala.collection.mutable.Map</code> <=> <code>java.util.Map</code></li> + * <li><code>scala.collection.mutable.Map</code> <=> <code>java.util.{ Map, Dictionary }</code></li> * <li><code>scala.collection.mutable.ConcurrentMap</code> <=> <code>java.util.concurrent.ConcurrentMap</code></li> - * <li><code>java.util.Properties</code></li> => <code>scala.collection.mutable.Map[String, String]</code></li> * </ul> * <p> * In all cases, converting from a source type to a target type and back @@ -42,28 +41,19 @@ package scala.collection * In addition, the following one way conversions are provided: * </p> * <ul> - * <li><code>scala.collection.IndexedSeq => <code>java.util.List }</code></li> - * <li><code>scala.collection.mutable.IndexedSeq => <code>java.util.List</code></li> + * <li><code>scala.collection.Seq => <code>java.util.List }</code></li> + * <li><code>scala.collection.mutable.Seq => <code>java.util.List</code></li> * <li><code>scala.collection.Set</code> => <code>java.util.Set</code></li> * <li><code>scala.collection.Map</code> => <code>java.util.Map</code></li> * </ul> - * Note that no conversion is provided from <code>scala.collection.immutable.List</code> - * to <code>java.util.List</code>. Instead it is convertible to an immutable - * <code>java.util.Collection</code> which provides size and interaction - * capabilities, but not access by index as would be provided by - * <code>java.util.List</code>.<br/> - * This is intentional: in combination the implementation of - * <code>scala.collection.immutable.List</code> and the typical usage - * patterns of <code>java.util.List</code> would perform extremely poorly. - * </p> * * @author Miles Sabin + * @author Martin Odersky * @since 2.8 */ object JavaConversions { import java.{ lang => jl, util => ju } import java.util.{ concurrent => juc } - import scala.reflect.ClassManifest // Scala => Java @@ -168,9 +158,9 @@ object JavaConversions { * @param b The <code>Seq</code> to be converted. * @return A Java <code>List</code> view of the argument. */ - implicit def asList[A](b : mutable.IndexedSeq[A]): ju.List[A] = b match { - case jlw: JListWrapper[_] => jlw.underlying.asInstanceOf[ju.List[A]] - case _ => new MutableIndexedSeqWrapper(b) + implicit def asList[A](b : mutable.Seq[A]): ju.List[A] = b match { + case JListWrapper(wrapped) => wrapped + case _ => new MutableSeqWrapper(b) } /** @@ -187,9 +177,9 @@ object JavaConversions { * @return A Java <code>List</co * de> view of the argument. */ - implicit def asList[A](b : IndexedSeq[A]): ju.List[A] = b match { - case jlw: JListWrapper[_] => jlw.underlying.asInstanceOf[ju.List[A]] - case _ => new IndexedSeqWrapper(b) + implicit def asList[A](b : Seq[A]): ju.List[A] = b match { + case JListWrapper(wrapped) => wrapped + case _ => new SeqWrapper(b) } /** @@ -205,9 +195,9 @@ de> view of the argument. * @param s The <code>Set</code> to be converted. * @return A Java <code>Set</code> view of the argument. */ - implicit def asSet[A](s : mutable.Set[A])(implicit m : ClassManifest[A]): ju.Set[A] = s match { + implicit def asSet[A](s : mutable.Set[A]): ju.Set[A] = s match { case JSetWrapper(wrapped) => wrapped - case _ => new MutableSetWrapper(s)(m) + case _ => new MutableSetWrapper(s) } /** @@ -241,10 +231,42 @@ de> view of the argument. * @param m The <code>Map</code> to be converted. * @return A Java <code>Map</code> view of the argument. */ - implicit def asMap[A, B](m : mutable.Map[A, B])(implicit ma : ClassManifest[A]): ju.Map[A, B] = m match { + implicit def asMap[A, B](m : mutable.Map[A, B]): ju.Map[A, B] = m match { //case JConcurrentMapWrapper(wrapped) => wrapped case JMapWrapper(wrapped) => wrapped - case _ => new MutableMapWrapper(m)(ma) + case _ => new MutableMapWrapper(m) + } + + /** + * Implicitly converts a Scala mutable <code>Map</code> to a Java <code>Dictionary</code>. + * The returned Java <code>Dictionary</code> is backed by the provided Scala + * <code>Dictionary</code> and any side-effects of using it via the Java interface will + * be visible via the Scala interface and vice versa. + * <p> + * If the Scala <code>Dictionary</code> was previously obtained from an implicit or + * explicit call of <code>asMap(java.util.Dictionary)</code> then the original + * Java <code>Dictionary</code> will be returned. + * + * @param m The <code>Map</code> to be converted. + * @return A Java <code>Dictionary</code> view of the argument. + */ + implicit def asDictionary[A, B](m : mutable.Map[A, B]): ju.Dictionary[A, B] = m match { + //case JConcurrentMapWrapper(wrapped) => wrapped + case JDictionaryWrapper(wrapped) => wrapped + case _ => new DictionaryWrapper(m) + } + + /** + * Implicitly converts a Java <code>Properties</code> to a Scala mutable <code>Map[String, String]</code>. + * The returned Scala <code>Map[String, String]</code> is backed by the provided Java + * <code>Properties</code> and any side-effects of using it via the Scala interface will + * be visible via the Java interface and vice versa. + * + * @param m The <code>Properties</code> to be converted. + * @return A Scala mutable <code>Map[String, String]</code> view of the argument. + */ + implicit def asMap(p: ju.Properties): mutable.Map[String, String] = p match { + case _ => new JPropertiesWrapper(p) } /** @@ -260,7 +282,7 @@ de> view of the argument. * @param m The <code>Map</code> to be converted. * @return A Java <code>Map</code> view of the argument. */ - implicit def asMap[A, B](m : Map[A, B])(implicit ma : ClassManifest[A]): ju.Map[A, B] = m match { + implicit def asMap[A, B](m : Map[A, B]): ju.Map[A, B] = m match { //case JConcurrentMapWrapper(wrapped) => wrapped case JMapWrapper(wrapped) => wrapped case _ => new MapWrapper(m) @@ -276,10 +298,9 @@ de> view of the argument. * explicit call of <code>asConcurrentMap(java.util.concurrect.ConcurrentMap)</code> then the original * Java <code>ConcurrentMap</code> will be returned. */ - implicit def asConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]) - (implicit ma: ClassManifest[A], mb: ClassManifest[B]): juc.ConcurrentMap[A, B] = m match { + implicit def asConcurrentMap[A, B](m: mutable.ConcurrentMap[A, B]): juc.ConcurrentMap[A, B] = m match { case JConcurrentMapWrapper(wrapped) => wrapped - case _ => new ConcurrentMapWrapper(m)(ma, mb) + case _ => new ConcurrentMapWrapper(m) } // Java => Scala @@ -422,21 +443,22 @@ de> view of the argument. * @return A Scala mutable <code>ConcurrrentMap</code> view of the argument. */ implicit def asConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]): mutable.ConcurrentMap[A, B] = m match { - case ConcurrentMapWrapper(wrapped) => wrapped + case cmw: ConcurrentMapWrapper[a, b] => cmw.underlying case _ => new JConcurrentMapWrapper(m) } /** - * Implicitly converts a Java <code>Properties</code> to a Scala mutable <code>Map[String, String]</code>. + * Implicitly converts a Java <code>Dictionary</code> to a Scala mutable <code>Map[String, String]</code>. * The returned Scala <code>Map[String, String]</code> is backed by the provided Java - * <code>Properties</code> and any side-effects of using it via the Scala interface will + * <code>Dictionary</code> and any side-effects of using it via the Scala interface will * be visible via the Java interface and vice versa. * - * @param m The <code>Properties</code> to be converted. + * @param m The <code>Dictionary</code> to be converted. * @return A Scala mutable <code>Map[String, String]</code> view of the argument. */ - implicit def asMap(p: ju.Properties): mutable.Map[String, String] = p match { - case _ => new JPropertiesWrapper(p) + implicit def asMap[A, B](p: ju.Dictionary[A, B]): mutable.Map[A, B] = p match { + case DictionaryWrapper(wrapped) => wrapped + case _ => new JDictionaryWrapper(p) } // Private implementations ... @@ -477,12 +499,12 @@ de> view of the argument. def newBuilder[B] = new mutable.ArrayBuffer[B] } - case class IndexedSeqWrapper[A](underlying : IndexedSeq[A]) extends ju.AbstractList[A] { + case class SeqWrapper[A](underlying : Seq[A]) extends ju.AbstractList[A] { def size = underlying.length def get(i : Int) = underlying(i) } - case class MutableIndexedSeqWrapper[A](underlying : mutable.IndexedSeq[A]) extends ju.AbstractList[A] { + case class MutableSeqWrapper[A](underlying : mutable.Seq[A]) extends ju.AbstractList[A] { def size = underlying.length def get(i : Int) = underlying(i) override def set(i : Int, elem: A) = { val p = underlying(i) ; underlying(i) = elem ; p } @@ -532,15 +554,14 @@ de> view of the argument. } } - case class MutableSetWrapper[A](underlying : mutable.Set[A])(m : ClassManifest[A]) extends SetWrapper[A](underlying) { + case class MutableSetWrapper[A](underlying : mutable.Set[A]) extends SetWrapper[A](underlying) { override def add(elem: A) = { val sz = underlying.size ; underlying += elem ; sz < underlying.size } - override def remove(elem : AnyRef) = { - m.erasure.isInstance(elem) && { - val sz = underlying.size - underlying -= elem.asInstanceOf[A] - sz > underlying.size - } + override def remove(elem : AnyRef) = try { + underlying.remove(elem.asInstanceOf[A]) + } catch { + case ex: ClassCastException => false } + override def clear() = underlying.clear() } case class JSetWrapper[A](underlying : ju.Set[A]) extends mutable.Set[A] with mutable.SetLike[A, JSetWrapper[A]] { @@ -555,8 +576,7 @@ de> view of the argument. override def add(elem: A): Boolean = underlying.add(elem) override def remove(elem: A): Boolean = underlying.remove(elem) - - override def clear = underlying.clear + override def clear() = underlying.clear() override def empty = JSetWrapper(new ju.HashSet[A]) } @@ -564,6 +584,15 @@ de> view of the argument. class MapWrapper[A, B](underlying: Map[A, B]) extends ju.AbstractMap[A, B] { self => override def size = underlying.size + override def get(key: AnyRef): B = try { + underlying get key.asInstanceOf[A] match { + case None => null.asInstanceOf[B] + case Some(v) => v + } + } catch { + case ex: ClassCastException => null.asInstanceOf[B] + } + override def entrySet: ju.Set[ju.Map.Entry[A, B]] = new ju.AbstractSet[ju.Map.Entry[A, B]] { def size = self.size @@ -604,28 +633,24 @@ de> view of the argument. } } - abstract class MutableMapWrapperCommon[A, B](underlying: mutable.Map[A, B])(m: ClassManifest[A]) + case class MutableMapWrapper[A, B](underlying: mutable.Map[A, B]) extends MapWrapper[A, B](underlying) { override def put(k : A, v : B) = underlying.put(k, v) match { case Some(v1) => v1 case None => null.asInstanceOf[B] } - override def remove(k : AnyRef) = { - if (!m.erasure.isInstance(k)) - null.asInstanceOf[B] - else { - val k1 = k.asInstanceOf[A] - underlying.get(k1) match { - case Some(v) => underlying -= k1 ; v - case None => null.asInstanceOf[B] - } + override def remove(k : AnyRef): B = try { + underlying.remove(k.asInstanceOf[A]) match { + case None => null.asInstanceOf[B] + case Some(v) => v } + } catch { + case ex: ClassCastException => null.asInstanceOf[B] } - } - case class MutableMapWrapper[A, B](underlying : mutable.Map[A, B])(m : ClassManifest[A]) - extends MutableMapWrapperCommon[A, B](underlying)(m) + override def clear() = underlying.clear() + } trait JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]] extends mutable.Map[A, B] with mutable.MapLike[A, B, Repr] { @@ -664,7 +689,7 @@ de> view of the argument. def next = { val e = ui.next ; (e.getKey, e.getValue) } } - override def clear = underlying.clear + override def clear() = underlying.clear() override def empty: Repr = null.asInstanceOf[Repr] } @@ -674,36 +699,19 @@ de> view of the argument. override def empty = JMapWrapper(new ju.HashMap[A, B]) } - case class ConcurrentMapWrapper[A, B](underlying: mutable.ConcurrentMap[A, B]) - (m: ClassManifest[A], mv: ClassManifest[B]) - extends MutableMapWrapperCommon[A, B](underlying)(m) with juc.ConcurrentMap[A, B] { - self => - - override def remove(k : AnyRef) = { - if (!m.erasure.isInstance(k)) - null.asInstanceOf[B] - else { - val k1 = k.asInstanceOf[A] - underlying.remove(k1) match { - case Some(v) => v - case None => null.asInstanceOf[B] - } - } - } + class ConcurrentMapWrapper[A, B](override val underlying: mutable.ConcurrentMap[A, B]) + extends MutableMapWrapper[A, B](underlying) with juc.ConcurrentMap[A, B] { def putIfAbsent(k: A, v: B) = underlying.putIfAbsent(k, v) match { case Some(v) => v case None => null.asInstanceOf[B] } - def remove(k: AnyRef, v: AnyRef) = { - if (!m.erasure.isInstance(k) || !mv.erasure.isInstance(v)) + def remove(k: AnyRef, v: AnyRef) = try { + underlying.remove(k.asInstanceOf[A], v.asInstanceOf[B]) + } catch { + case ex: ClassCastException => false - else { - val k1 = k.asInstanceOf[A] - val v1 = v.asInstanceOf[B] - underlying.remove(k1, v1) - } } def replace(k: A, v: B): B = underlying.replace(k, v) match { @@ -712,7 +720,6 @@ de> view of the argument. } def replace(k: A, oldval: B, newval: B) = underlying.replace(k, oldval, newval) - } case class JConcurrentMapWrapper[A, B](val underlying: juc.ConcurrentMap[A, B]) @@ -738,7 +745,64 @@ de> view of the argument. } def replace(k: A, oldvalue: B, newvalue: B): Boolean = underlying.replace(k, oldvalue, newvalue) + } + + case class DictionaryWrapper[A, B](underlying: mutable.Map[A, B]) + extends ju.Dictionary[A, B] { + def size: Int = underlying.size + def isEmpty: Boolean = underlying.isEmpty + def keys: ju.Enumeration[A] = asEnumeration(underlying.keysIterator) + def elements: ju.Enumeration[B] = asEnumeration(underlying.valuesIterator) + def get(key: AnyRef) = try { + underlying.get(key.asInstanceOf[A]) match { + case None => null.asInstanceOf[B] + case Some(v) => v + } + } catch { + case ex: ClassCastException => null.asInstanceOf[B] + } + def put(key: A, value: B): B = underlying.put(key, value) match { + case Some(v) => v + case None => null.asInstanceOf[B] + } + override def remove(key: AnyRef) = try { + underlying.remove(key.asInstanceOf[A]) match { + case None => null.asInstanceOf[B] + case Some(v) => v + } + } catch { + case ex: ClassCastException => null.asInstanceOf[B] + } + } + + case class JDictionaryWrapper[A, B](underlying: ju.Dictionary[A, B]) + extends mutable.Map[A, B] { + + override def size: Int = underlying.size + + def get(k : A) = { + val v = underlying.get(k) + if (v != null) Some(v) else None + } + def +=(kv: (A, B)): this.type = { underlying.put(kv._1, kv._2); this } + def -=(key: A): this.type = { underlying.remove(key); this } + + override def put(k : A, v : B): Option[B] = { + val r = underlying.put(k, v) + if (r != null) Some(r) else None + } + + override def update(k : A, v : B) { underlying.put(k, v) } + + override def remove(k : A): Option[B] = { + val r = underlying.remove(k) + if (r != null) Some(r) else None + } + + def iterator = asIterator(underlying.keys) map (k => (k, underlying get k)) + + override def clear() = underlying.clear() } case class JPropertiesWrapper(underlying: ju.Properties) @@ -774,7 +838,7 @@ de> view of the argument. def next = { val e = ui.next ; (e.getKey.asInstanceOf[String], e.getValue.asInstanceOf[String]) } } - override def clear = underlying.clear + override def clear() = underlying.clear() override def empty = JPropertiesWrapper(new ju.Properties) @@ -784,9 +848,5 @@ de> view of the argument. def setProperty(key: String, value: String) = underlying.setProperty(key, value) } - } - - - |