Skip to content

Commit

Permalink
Add javaapi collection forwarders for 2.12 and 2.11
Browse files Browse the repository at this point in the history
Adds 2.13 collection compatible forwarders for scala 2.11 and scala 2.12, see #346.

2.11 has converters in traits WrapAsJava and WrapAsScala, while 2.12 has them in  AsJavaConverters and AsScalaConverters.
The method names are the same, but unfortunately both CollectionConverters objects have to be separately defined for both sources, because of this import.

Tests are added in a Java file, to verify that the methods can be called as java api.
  • Loading branch information
DieBauer committed Aug 10, 2022
1 parent a6d5f2f commit 5c76f7b
Show file tree
Hide file tree
Showing 4 changed files with 282 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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.javaapi

import java.{lang => jl, util => ju}, java.util.{concurrent => juc}
import scala.collection.convert.{WrapAsJava, WrapAsScala}
import scala.collection._

/** This object contains methods that convert between Scala and Java collections.
*
* The explicit conversion methods defined here are intended to be used in Java code. For Scala
* code, it is recommended to use the extension methods defined in
* [[scala.jdk.CollectionConverters]].
*/
object CollectionConverters extends WrapAsJava with WrapAsScala {
def asJava[A](i: Iterator[A]): ju.Iterator[A] = asJavaIterator(i)

def asJava[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i)

def asJava[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b)

def asJava[A](s: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(s)

def asJava[A](s: Seq[A]): ju.List[A] = seqAsJavaList(s)

def asJava[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s)

def asJava[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s)

def asJava[K, V](m: mutable.Map[K, V]): ju.Map[K, V] = mutableMapAsJavaMap(m)

def asJava[K, V](m: Map[K, V]): ju.Map[K, V] = mapAsJavaMap(m)

def asJava[K, V](m: concurrent.Map[K, V]): juc.ConcurrentMap[K, V] = mapAsJavaConcurrentMap(m)

def asScala[A](i: ju.Iterator[A]): Iterator[A] = asScalaIterator(i)

def asScala[A](e: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(e)

def asScala[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i)

def asScala[A](c: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(c)

def asScala[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l)

def asScala[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s)

def asScala[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m)

def asScala[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m)

def asScala[A, B](d: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(d)

def asScala(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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.javaapi

import java.{lang => jl, util => ju}, java.util.{concurrent => juc}
import scala.collection.convert.{AsJavaConverters, AsScalaConverters}
import scala.collection._

/** This object contains methods that convert between Scala and Java collections.
*
* The explicit conversion methods defined here are intended to be used in Java code. For Scala
* code, it is recommended to use the extension methods defined in
* [[scala.jdk.CollectionConverters]].
*/
object CollectionConverters extends AsJavaConverters with AsScalaConverters {
def asJava[A](i: Iterator[A]): ju.Iterator[A] = asJavaIterator(i)

def asJava[A](i: Iterable[A]): jl.Iterable[A] = asJavaIterable(i)

def asJava[A](b: mutable.Buffer[A]): ju.List[A] = bufferAsJavaList(b)

def asJava[A](s: mutable.Seq[A]): ju.List[A] = mutableSeqAsJavaList(s)

def asJava[A](s: Seq[A]): ju.List[A] = seqAsJavaList(s)

def asJava[A](s: mutable.Set[A]): ju.Set[A] = mutableSetAsJavaSet(s)

def asJava[A](s: Set[A]): ju.Set[A] = setAsJavaSet(s)

def asJava[K, V](m: mutable.Map[K, V]): ju.Map[K, V] = mutableMapAsJavaMap(m)

def asJava[K, V](m: Map[K, V]): ju.Map[K, V] = mapAsJavaMap(m)

def asJava[K, V](m: concurrent.Map[K, V]): juc.ConcurrentMap[K, V] = mapAsJavaConcurrentMap(m)

def asScala[A](i: ju.Iterator[A]): Iterator[A] = asScalaIterator(i)

def asScala[A](e: ju.Enumeration[A]): Iterator[A] = enumerationAsScalaIterator(e)

def asScala[A](i: jl.Iterable[A]): Iterable[A] = iterableAsScalaIterable(i)

def asScala[A](c: ju.Collection[A]): Iterable[A] = collectionAsScalaIterable(c)

def asScala[A](l: ju.List[A]): mutable.Buffer[A] = asScalaBuffer(l)

def asScala[A](s: ju.Set[A]): mutable.Set[A] = asScalaSet(s)

def asScala[A, B](m: ju.Map[A, B]): mutable.Map[A, B] = mapAsScalaMap(m)

def asScala[A, B](m: juc.ConcurrentMap[A, B]): concurrent.Map[A, B] = mapAsScalaConcurrentMap(m)

def asScala[A, B](d: ju.Dictionary[A, B]): mutable.Map[A, B] = dictionaryAsScalaMap(d)

def asScala(p: ju.Properties): mutable.Map[String, String] = propertiesAsScalaMap(p)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package test.scala.jdk.javaapi;

import org.junit.Assert;
import org.junit.Test;
import scala.Array;
import scala.Tuple2;
import scala.collection.Iterable;
import scala.collection.Iterator;
import scala.collection.concurrent.TrieMap;
import scala.collection.mutable.*;
import scala.collection.mutable.Map;
import scala.collection.mutable.Set;
import scala.jdk.javaapi.CollectionConverters;

import java.util.*;
import java.util.concurrent.ConcurrentMap;

public class CollectionConvertersTest {

/**
* The following conversions are supported via asScala and asJava:
*
* scala.collection.Iterable <=> java.lang.Iterable
* scala.collection.Iterator <=> java.util.Iterator
* scala.collection.mutable.Buffer <=> java.util.List
* scala.collection.mutable.Set <=> java.util.Set
* scala.collection.mutable.Map <=> java.util.Map
* scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
*/
@Test
public void shouldConvertAsScala() {
// scala.collection.Iterable <=> java.lang.Iterable
java.lang.Iterable iterable = CollectionConverters.asJava(TestObjects.iterable());
Assert.assertEquals("A", iterable.iterator().next());
Iterable scalaIterable = CollectionConverters.asScala(iterable);
Assert.assertEquals(TestObjects.iterable().head(), scalaIterable.head());

// scala.collection.Iterator <=> java.util.Iterator
java.util.Iterator iterator = CollectionConverters.asJava(TestObjects.iterator());
Assert.assertEquals("A", iterator.next());
Iterator scalaIterator = CollectionConverters.asScala(iterator);
Assert.assertTrue(scalaIterator.contains("B"));

// scala.collection.mutable.Buffer <=> java.util.List
List<String> list = CollectionConverters.asJava(TestObjects.buffer());
Assert.assertEquals("A", list.get(0));
Buffer<String> scalaBuffer = CollectionConverters.asScala(list);
Assert.assertEquals("A", scalaBuffer.head());

// scala.collection.mutable.Set <=> java.util.Set
java.util.Set<String> set = CollectionConverters.asJava(TestObjects.mutableSet());
Assert.assertTrue(set.contains("A"));
Set<String> scalaSet = CollectionConverters.asScala(set);
Assert.assertTrue(scalaSet.contains("A"));

// scala.collection.mutable.Map <=> java.util.Map
java.util.Map<String, String> map = CollectionConverters.asJava(TestObjects.mutableMap());
Assert.assertEquals("B", map.get("A"));
Map<String, String> scalaMap = CollectionConverters.asScala(map);
Assert.assertEquals("B", scalaMap.get("A").get());

// scala.collection.concurrent.Map <=> java.util.concurrent.ConcurrentMap
ConcurrentMap<String, String> concurrentMap = CollectionConverters.asJava(TestObjects.concurrentMap());
Assert.assertEquals("B", concurrentMap.get("A"));
scala.collection.concurrent.Map<String, String> scalaConcurrentMap = CollectionConverters.asScala(concurrentMap);
Assert.assertEquals("B", scalaConcurrentMap.get("A").get());
}

/**
* The following conversions are supported via asScala and through specially-named methods to convert to Java collections, as shown:
*
* scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
* scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
* scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
*/
public void convertAsCollection() {
// scala.collection.Iterable <=> java.util.Collection (via asJavaCollection)
Collection<String> collection = CollectionConverters.asJavaCollection(TestObjects.iterable());
Assert.assertTrue(collection.contains("A"));
Iterable<String> iterable = CollectionConverters.asScala(collection);
Assert.assertEquals("A", iterable.head());

// scala.collection.Iterator <=> java.util.Enumeration (via asJavaEnumeration)
Enumeration<String> enumeration = CollectionConverters.asJavaEnumeration(TestObjects.iterator());
Assert.assertEquals("A", enumeration.nextElement());
Iterator<String> iterator = CollectionConverters.asScala(enumeration);
Assert.assertEquals("A", iterator.next());

// scala.collection.mutable.Map <=> java.util.Dictionary (via asJavaDictionary)
Dictionary<String, String> dictionary = CollectionConverters.asJavaDictionary(TestObjects.mutableMap());
Assert.assertEquals("B", dictionary.get("A"));
Map<String, String> map = CollectionConverters.asScala(dictionary);
Assert.assertEquals("B", map.get("A").get());
}

/** In addition, the following one-way conversions are provided via asJava:
*
* scala.collection.Seq => java.util.List
* scala.collection.mutable.Seq => java.util.List
* scala.collection.Set => java.util.Set
* scala.collection.Map => java.util.Map
*/
public void convertsAsJava() {
// scala.collection.Seq => java.util.List
Assert.assertEquals("A", CollectionConverters.asJava(TestObjects.seq()).get(0));

// scala.collection.mutable.Seq => java.util.List
Assert.assertEquals("A", CollectionConverters.asJava(TestObjects.mutableSeq()).get(0));

// scala.collection.Set => java.util.Set
Assert.assertTrue(CollectionConverters.asJava(TestObjects.set()).contains("A"));

// scala.collection.Map => java.util.Map
Assert.assertEquals("B", CollectionConverters.asJava(TestObjects.map()).get("A"));
}

/**
* The following one way conversion is provided via asScala:
*
* java.util.Properties => scala.collection.mutable.Map
*/
public void convertsFromProperties() {
Properties properties = new Properties();
properties.put("key", "value");
Map<String, String> stringStringMap = CollectionConverters.asScala(properties);
Assert.assertEquals("value", stringStringMap.get("key").get());
}
}
24 changes: 24 additions & 0 deletions compat/src/test/scala-jvm/test/scala/jdk/javaapi/TestObjects.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package test.scala.jdk.javaapi

import scala.collection.concurrent.TrieMap
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.Buffer

/**
* Scala collection objects defined for easy access in a Java class
*/
object TestObjects {

val seq: scala.collection.Seq[String] = ArrayBuffer("A", "B")
val mutableSeq: scala.collection.mutable.Seq[String] = ArrayBuffer("A", "B")
val set: scala.collection.Set[String] = Set("A", "B")
val map: scala.collection.Map[String, String] = Map("A" -> "B")

val iterable: scala.collection.Iterable[String] = Iterable("A", "B")
val iterator: scala.collection.Iterator[String] = Iterator("A", "B")
val buffer: scala.collection.mutable.Buffer[String] = mutable.Buffer("A", "B")
val mutableSet: scala.collection.mutable.Set[String] = mutable.Set("A", "B")
val mutableMap: scala.collection.mutable.Map[String, String] = mutable.Map("A" -> "B")
val concurrentMap: scala.collection.concurrent.Map[String, String] = TrieMap("A" -> "B")
}

0 comments on commit 5c76f7b

Please sign in to comment.