/* __ *\ ** ________ ___ / / ___ Scala API ** ** / __/ __// _ | / / / _ | (c) 2006-2010, LAMP/EPFL ** ** __\ \/ /__/ __ |/ /__/ __ | http://www.scala-lang.org/ ** ** /____/\___/_/ |_/____/_/ | | ** ** |/ ** \* */ // $Id$ package scala.collection /**

* A collection of implicit conversions supporting interoperability between * Scala and Java collections. *

*

* The following conversions are supported: *

* *

* In all cases, converting from a source type to a target type and back * again will return the original source object, eg. *

*
 *    import scala.collection.JavaConversions._
 *
 *    val sl = new scala.collection.mutable.ListBuffer[Int]
 *    val jl : java.util.List[Int] = sl
 *    val sl2 : scala.collection.mutable.Buffer[Int] = jl
 *    assert(sl eq sl2)g
*

* Note that no conversion is provided from scala.collection.immutable.List * to java.util.List. Instead it is convertible to an immutable * java.util.Collection which provides size and interation * capabilities, but not access by index as would be provided by * java.util.List.
* This is intentional: in combination the implementation of * scala.collection.immutable.List and the typical usage * patterns of java.util.List would perform extremely poorly. *

* * @author Miles Sabin * @since 2.8 */ object JavaConversions { import java.{ lang => jl, util => ju } import java.util.{ concurrent => juc } import scala.collection.{ generic, immutable, mutable, Traversable } import scala.reflect.ClassManifest // Scala => Java /** * Implicitly converts a Scala Iterator to a Java Iterator. * The returned Java Iterator is backed by the provided Scala * Iterator and any side-effects of using it via the Java interface will * be visible via the Scala interface and vice versa. *

* If the Scala Iterator was previously obtained from an implicit or * explicit call of asIterator(java.util.Iterator) then the original * Java Iterator will be returned. * * @param i The Iterator to be converted. * @return A Java Iterator view of the argument. */ implicit def asIterator[A](i : Iterator[A]) = i match { case JIteratorWrapper(wrapped) => wrapped case _ => IteratorWrapper(i) } /** * Implicitly converts a Scala Iterator to a Java Enumeration. * The returned Java Enumeration is backed by the provided Scala * Iterator and any side-effects of using it via the Java interface will * be visible via the Scala interface and vice versa. *

* If the Scala Iterator was previously obtained from an implicit or * explicit call of asIterator(java.util.Enumeration) then the * original Java Enumeration will be returned. * * @param i The Iterator to be converted. * @return A Java Enumeration view of the argument. */ implicit def asEnumeration[A](i : Iterator[A]) = i match { case JEnumerationWrapper(wrapped) => wrapped case _ => IteratorWrapper(i) } /** * Implicitly converts a Scala Iterable to a Java Iterable. * The returned Java Iterable is backed by the provided Scala * Iterable and any side-effects of using it via the Java interface will * be visible via the Scala interface and vice versa. *

* If the Scala Iterable was previously obtained from an implicit or * explicit call of asIterable(java.lang.Iterable) then the original * Java Iterable will be returned. * * @param i The Iterable to be converted. * @return A Java Iterable view of the argument. */ implicit def asIterable[A](i : Iterable[A]) = i match { case JIterableWrapper(wrapped) => wrapped case _ => IterableWrapper(i) } /** * Implicitly converts a Scala Iterable to an immutable Java * Collection. *

* If the Scala Iterable was previously obtained from an implicit or * explicit call of asSizedIterable(java.util.Collection) then the original * Java Collection will be returned. * * @param i The SizedIterable to be converted. * @return A Java Collection view of the argument. */ implicit def asCollection[A](i : Iterable[A]) = i match { case JCollectionWrapper(wrapped) => wrapped case _ => new IterableWrapper(i) } /** * Implicitly converts a Scala mutable Buffer to a Java List. * The returned Java List is backed by the provided Scala * Buffer and any side-effects of using it via the Java interface will * be visible via the Scala interface and vice versa. *

* If the Scala Buffer was previously obtained from an implicit or * explicit call of asBuffer(java.util.List) then the original * Java List will be returned. * * @param b The Buffer to be converted. * @return A Java List view of the argument. */ implicit def asList[A](b : mutable.Buffer[A]) : ju.List[A] = b match { case JListWrapper(wrapped) => wrapped case _ => new MutableBufferWrapper(b) } /** * Implicitly converts a Scala mutable Set to a Java Set. * The returned Java Set is backed by the provided Scala * Set and any side-effects of using it via the Java interface will * be visible via the Scala interface and vice versa. *

* If the Scala Set was previously obtained from an implicit or * explicit call of asSet(java.util.Set) then the original * Java Set will be returned. * * @param s The Set to be converted. * @return A Java Set view of the argument. */ implicit def asSet[A](s : mutable.Set[A])(implicit m : ClassManifest[A]) : ju.Set[A] = s match { case JSetWrapper(wrapped) => wrapped case _ => new MutableSetWrapper(s)(m) } /** * Implicitly converts a Scala mutable Map to a Java Map. * The returned Java Map is backed by the provided Scala * Map and any side-effects of using it via the Java interface will * be visible via the Scala interface and vice versa. *

* If the Scala Map was previously obtained from an implicit or * explicit call of asMap(java.util.Map) then the original * Java Map will be returned. * * @param m The Map to be converted. * @return A Java Map view of the argument. */ implicit def asMap[A, B](m : mutable.Map[A, B])(implicit ma : ClassManifest[A]) : ju.Map[A, B] = m match { case JMapWrapper(wrapped) => wrapped case _ => new MutableMapWrapper(m)(ma) } // Java => Scala /** * Implicitly converts a Java Iterator to a Scala Iterator. * The returned Scala Iterator is backed by the provided Java * Iterator and any side-effects of using it via the Scala interface will * be visible via the Java interface and vice versa. *

* If the Java Iterator was previously obtained from an implicit or * explicit call of asIterator(scala.collection.Iterator) then the original * Scala Iterator will be returned. * * @param i The Iterator to be converted. * @return A Scala Iterator view of the argument. */ implicit def asIterator[A](i : ju.Iterator[A]) = i match { case IteratorWrapper(wrapped) => wrapped case _ => JIteratorWrapper(i) } /** * Implicitly converts a Java Enumeration to a Scala Iterator. * The returned Scala Iterator is backed by the provided Java * Enumeration and any side-effects of using it via the Scala interface will * be visible via the Java interface and vice versa. *

* If the Java Enumeration was previously obtained from an implicit or * explicit call of asEnumeration(scala.collection.Iterator) then the * original Scala Iterator will be returned. * * @param i The Enumeration to be converted. * @return A Scala Iterator view of the argument. */ implicit def asIterator[A](i : ju.Enumeration[A]) = i match { case IteratorWrapper(wrapped) => wrapped case _ => JEnumerationWrapper(i) } /** * Implicitly converts a Java Iterable to a Scala Iterable. * The returned Scala Iterable is backed by the provided Java * Iterable and any side-effects of using it via the Scala interface will * be visible via the Java interface and vice versa. *

* If the Java Iterable was previously obtained from an implicit or * explicit call of asIterable(scala.collection.Iterable) then the original * Scala Iterable will be returned. * * @param i The Iterable to be converted. * @return A Scala Iterable view of the argument. */ implicit def asIterable[A](i : jl.Iterable[A]) = i match { case IterableWrapper(wrapped) => wrapped case _ => JIterableWrapper(i) } /** * Implicitly converts a Java Collection to an Scala Iterable. *

* If the Java Collection was previously obtained from an implicit or * explicit call of asCollection(scala.collection.SizedIterable) then * the original Scala SizedIterable will be returned. * * @param i The Collection to be converted. * @return A Scala SizedIterable view of the argument. */ implicit def asIterable[A](i : ju.Collection[A]) = i match { case IterableWrapper(wrapped) => wrapped case _ => JCollectionWrapper(i) } /** * Implicitly converts a Java List to a Scala mutable Buffer. * The returned Scala Buffer is backed by the provided Java * List and any side-effects of using it via the Scala interface will * be visible via the Java interface and vice versa. *

* If the Java List was previously obtained from an implicit or * explicit call of asList(scala.collection.mutable.Buffer) then the original * Scala Buffer will be returned. * * @param l The List to be converted. * @return A Scala mutable Buffer view of the argument. */ implicit def asBuffer[A](l : ju.List[A]) = l match { case MutableBufferWrapper(wrapped) => wrapped case _ =>new JListWrapper(l) } /** * Implicitly converts a Java Set to a Scala mutable Set. * The returned Scala Set is backed by the provided Java * Set and any side-effects of using it via the Scala interface will * be visible via the Java interface and vice versa. *

* If the Java Set was previously obtained from an implicit or * explicit call of asSet(scala.collection.mutable.Set) then the original * Scala Set will be returned. * * @param s The Set to be converted. * @return A Scala mutable Set view of the argument. */ implicit def asSet[A](s : ju.Set[A]) = s match { case MutableSetWrapper(wrapped) => wrapped case _ =>new JSetWrapper(s) } /** * Implicitly converts a Java Map to a Scala mutable Map. * The returned Scala Map is backed by the provided Java * Map and any side-effects of using it via the Scala interface will * be visible via the Java interface and vice versa. *

* If the Java Map was previously obtained from an implicit or * explicit call of asMap(scala.collection.mutable.Map) then the original * Scala Map will be returned. * * @param m The Map to be converted. * @return A Scala mutable Map view of the argument. */ implicit def asMap[A, B](m : ju.Map[A, B]) = m match { case MutableMapWrapper(wrapped) => wrapped case _ => new JMapWrapper(m) } implicit def asConcurrentMap[A, B](m: juc.ConcurrentMap[A, B]) = m match { case _ => new JConcurrentMapWrapper(m) } implicit def asMap(p: ju.Properties): mutable.Map[String, String] = p match { case _ => new JPropertiesWrapper(p) } // Private implementations ... case class IteratorWrapper[A](underlying : Iterator[A]) extends ju.Iterator[A] with ju.Enumeration[A] { def hasNext = underlying.hasNext def next = underlying.next def hasMoreElements = underlying.hasNext def nextElement = underlying.next def remove = throw new UnsupportedOperationException } case class JIteratorWrapper[A](underlying : ju.Iterator[A]) extends Iterator[A] { def hasNext = underlying.hasNext def next = underlying.next } case class JEnumerationWrapper[A](underlying : ju.Enumeration[A]) extends Iterator[A] { def hasNext = underlying.hasMoreElements def next = underlying.nextElement } case class IterableWrapper[A](underlying : Iterable[A]) extends ju.AbstractCollection[A] { def iterator = underlying.iterator def size = underlying.size override def isEmpty = underlying.isEmpty } case class JIterableWrapper[A](underlying : jl.Iterable[A]) extends Iterable[A] { def iterator = underlying.iterator def newBuilder[B] = new mutable.ArrayBuffer[B] } case class JCollectionWrapper[A](underlying : ju.Collection[A]) extends Iterable[A] { def iterator = underlying.iterator override def size = underlying.size override def isEmpty = underlying.isEmpty def newBuilder[B] = new mutable.ArrayBuffer[B] } case class MutableBufferWrapper[A](underlying : mutable.Buffer[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 } override def add(elem : A) = { underlying.append(elem) ; true } override def remove(i : Int) = underlying.remove(i) } case class JListWrapper[A](val underlying : ju.List[A]) extends mutable.Buffer[A] { def length = underlying.size override def isEmpty = underlying.isEmpty override def iterator : Iterator[A] = underlying.iterator def apply(i : Int) = underlying.get(i) def update(i : Int, elem : A) = underlying.set(i, elem) def +=:(elem : A) = { underlying.subList(0, 0).add(elem) ; this } def +=(elem : A): this.type = { underlying.add(elem); this } def insertAll(i : Int, elems : Traversable[A]) = { val ins = underlying.subList(0, i) ; elems.foreach(ins.add(_)) } def remove(i : Int) = underlying.remove(i) def clear = underlying.clear def result = this } case class MutableSetWrapper[A](underlying : mutable.Set[A])(m : ClassManifest[A]) extends ju.AbstractSet[A] { self => def size = underlying.size 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 } } def iterator = new ju.Iterator[A] { val ui = underlying.iterator var prev : Option[A] = None def hasNext = ui.hasNext def next = { val e = ui.next ; prev = Some(e) ; e } def remove = prev match { case Some(e) => self.remove(e.asInstanceOf[AnyRef]) ; prev = None case _ => throw new IllegalStateException("next must be called at least once before remove") } } } case class JSetWrapper[A](underlying : ju.Set[A]) extends mutable.Set[A] with mutable.SetLike[A, JSetWrapper[A]] { override def size = underlying.size def iterator = underlying.iterator def contains(elem: A): Boolean = underlying.contains(elem) def +=(elem: A): this.type = { underlying.add(elem); this } def -=(elem: A): this.type = { underlying.remove(elem); this } 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 empty = JSetWrapper(new ju.HashSet[A]) } case class MutableMapWrapper[A, B](underlying : mutable.Map[A, B])(m : ClassManifest[A]) extends ju.AbstractMap[A, B] { self => override def size = underlying.size 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 entrySet : ju.Set[ju.Map.Entry[A, B]] = new ju.AbstractSet[ju.Map.Entry[A, B]] { def size = self.size def iterator = new ju.Iterator[ju.Map.Entry[A, B]] { val ui = underlying.iterator var prev : Option[A] = None def hasNext = ui.hasNext def next = { val (k, v) = ui.next prev = Some(k) new ju.Map.Entry[A, B] { def getKey = k def getValue = v def setValue(v1 : B) = self.put(k, v1) override def equals(other : Any) = other match { case e : ju.Map.Entry[_, _] => k == e.getKey && v == e.getValue case _ => false } } } def remove = prev match { case Some(k) => val v = self.remove(k.asInstanceOf[AnyRef]) ; prev = None ; v case _ => throw new IllegalStateException("next must be called at least once before remove") } } } } abstract class JMapWrapperLike[A, B, +Repr <: mutable.MapLike[A, B, Repr] with mutable.Map[A, B]] (underlying: ju.Map[A, B]) extends mutable.Map[A, B] with mutable.MapLike[A, B, Repr] { override def size = underlying.size def get(k : A) = { val v = underlying.get(k) if (v != null) Some(v) else if(underlying.containsKey(k)) Some(null.asInstanceOf[B]) 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 = new Iterator[(A, B)] { val ui = underlying.entrySet.iterator def hasNext = ui.hasNext def next = { val e = ui.next ; (e.getKey, e.getValue) } } override def clear = underlying.clear override def empty: Repr = null.asInstanceOf[Repr] } case class JMapWrapper[A, B](underlying : ju.Map[A, B]) extends JMapWrapperLike[A, B, JMapWrapper[A, B]](underlying) { override def empty = JMapWrapper(new ju.HashMap[A, B]) } case class JConcurrentMapWrapper[A, B](underlying: juc.ConcurrentMap[A, B]) extends JMapWrapperLike[A, B, JConcurrentMapWrapper[A, B]](underlying) { override def get(k: A) = { val v = underlying.get(k) if (v != null) Some(v) else None } override def empty = new JConcurrentMapWrapper(new juc.ConcurrentHashMap[A, B]) def putIfAbsent(k: A, v: B): Option[B] = { val r = underlying.putIfAbsent(k, v) if (r != null) Some(r) else None } def remove(k: A, v: B): Boolean = underlying.remove(k, v) def replace(k: A, v: B): Option[B] = { val prev = underlying.replace(k, v) if (prev != null) Some(prev) else None } def replace(k: A, oldvalue: B, newvalue: B): Boolean = underlying.replace(k, oldvalue, newvalue) } case class JPropertiesWrapper(underlying: ju.Properties) extends mutable.Map[String, String] with mutable.MapLike[String, String, JPropertiesWrapper] { override def size = underlying.size def get(k : String) = { val v = underlying.get(k) if (v != null) Some(v.asInstanceOf[String]) else None } def +=(kv: (String, String)): this.type = { underlying.put(kv._1, kv._2); this } def -=(key: String): this.type = { underlying.remove(key); this } override def put(k : String, v : String): Option[String] = { val r = underlying.put(k, v) if (r != null) Some(r.asInstanceOf[String]) else None } override def update(k : String, v : String) { underlying.put(k, v) } override def remove(k : String): Option[String] = { val r = underlying.remove(k) if (r != null) Some(r.asInstanceOf[String]) else None } def iterator = new Iterator[(String, String)] { val ui = underlying.entrySet.iterator def hasNext = ui.hasNext def next = { val e = ui.next ; (e.getKey.asInstanceOf[String], e.getValue.asInstanceOf[String]) } } override def clear = underlying.clear override def empty = JPropertiesWrapper(new ju.Properties) def getProperty(key: String) = underlying.getProperty(key) def getProperty(key: String, defaultValue: String) = underlying.getProperty(key, defaultValue) def setProperty(key: String, value: String) = underlying.setProperty(key, value) } }