How can I convert a Java Iterable to a Scala Iterable? - scala

Is there an easy way to convert a
java.lang.Iterable[_]
to a
Scala.Iterable[_]
?

In Scala 2.8 this became much much easier, and there are two ways to achieve it. One that's sort of explicit (although it uses implicits):
import scala.collection.JavaConverters._
val myJavaIterable = someExpr()
val myScalaIterable = myJavaIterable.asScala
EDIT: Since I wrote this, the Scala community has arrived at a broad consensus that JavaConverters is good, and JavaConversions is bad, because of the potential for spooky-action-at-a-distance. So don't use JavaConversions at all!
And one that's more like an implicit implicit: :)
import scala.collection.JavaConversions._
val myJavaIterable = someExpr()
for (magicValue <- myJavaIterable) yield doStuffWith(magicValue)

Yes use implicit conversions:
import java.lang.{Iterable => JavaItb}
import java.util.{Iterator => JavaItr}
implicit def jitb2sitb[T](jit: JavaItb[T]): Iterable[T] = new SJIterable(jit);
implicit def jitr2sitr[A](jit: JavaItr[A]): Iterator[A] = new SJIterator(jit)
Which can then be easily implemented:
class SJIterable[T](private val jitb: JavaItr[T]) extends Iterable[T] {
def elements(): Iterator[T] = jitb.iterator()
}
class SJIterator[T](private val jit: JavaItr[T]) extends Iterator[T] {
def hasNext: Boolean = jit hasNext
def next: T = jit next
}

Starting Scala 2.13, package scala.jdk.CollectionConverters replaces deprecated packages scala.collection.JavaConverters/JavaConversions:
import scala.jdk.CollectionConverters._
// val javaIterable: java.lang.Iterable[Int] = Iterable(1, 2, 3).asJava
javaIterable.asScala
// Iterable[Int] = List(1, 2, 3)

Related

FS2: How to get a java.io.InputStream from a fs2.Stream?

Say I have val fs2Stream: Stream[IO, Byte] and I need to, for example, call some Java library that requires a java.io.InputStream.
I suppose that I'm way too new to FS2, but I cannot seem to find the answer. I've tried to use fs2.io.toInputStream and fs2.io.readInputStream but I cannot figure out how to provide some of the required parameters. I've scoured the almighty Google for answers, but it seems that the API has changed since most people were last looking for an answer.
How can I go about doing something like the following?
def myFunc(data: fs2.Stream[IO, Byte]): InputStream[Byte] = someMagicalFunction(data)
You probably want something like this:
import cats.effect.{ContextShift, IO, Resource}
import java.io.InputStream
def myFunc(data: fs2.Stream[IO, Byte])
(implicit cs: ContextShift[IO]): Resource[IO, InputStream] =
data.through(fs2.io.toInputStream).compile.resource.lastOrError
Then you can use it like:
object JavaApi {
def foo(is: InputStream): IO[Unit] = ???
}
object Main extends IOApp {
def data: fs2.Stream[IO, Byte] = ???
override def run(args: List[String]): IO[ExitCode] =
myFunc(data).use(JavaApi.foo).as(ExitCode.Success)
}
Here is an Scastie with the code running.

scala implicit conversion doesn't work

I discover a strange phenomenon:
class A {
val dual: A = this
object T {
implicit def doubleDual(t: T): dual.dual.T = t.asInstanceOf[dual.dual.T]
implicit def justForTest(t: T): Int = 777
}
class T
}
val a = new A
val t = new a.T
// import a.T._
val x: Int = t //this works!
val t1: a.dual.dual.T = t //this doesn't work!
According to implicit search rule, the method doubleDual in object T should be applied. But it doesn't. I have to import a.T._ manually. Why?
According to implicit search rule, the method doubleDual in object T should be applied.
It looks to me like the search should find two implicits: a.T.doubleDual and a.dual.dual.T.doubleDual The question is why it doesn't give "implicit conversions are not applicable because they are ambiguous" error. Maybe because they have the same name?
No, that's wrong, a.dual.dual.T.doubleDual has a wrong type. But I still suspect the problem may be related to the T object appearing twice when searching for a.T and a.dual.dual.T. It's just that this would be a compiler bug, unless I missed something else.
The key is "the same name"!
class A {
val dual: A = this
object T {
implicit def doubleDual(t: T): dual.dual.T = t.asInstanceOf[dual.dual.T]
}
class T
}
val a = new A
val t = new a.T
import a.T.doubleDual //
import a.dual.dual.T.doubleDual //the same name!
val t1: a.dual.dual.T = t // won't compile
But after rename:
import a.T.doubleDual //
import a.dual.dual.T.{doubleDual => dd} // different name!
val t1: a.dual.dual.T = t // can compile

Building a compiler for Free monad (Cats library)

I'm trying to get my head around monads and Cats. Following some examples (e.g.cats) I wrote the code like below. But can't figure out how to make compiler to do what I need and to compile, actually.
import cats.Id
import cats.free.Free
import cats.~>
object Filtering extends App {
sealed trait Filter[A]
case class WhitespaceFilter(text: String) extends Filter[Seq[String]]
case class LowerCaseFilter(strings: Seq[String]) extends Filter[Seq[String]]
def whitespaceFilter(text: String): Free[Filter, Seq[String]] = Free.liftF(WhitespaceFilter(text))
def lowerCaseFilter(strings: Seq[String]): Free[Filter, Seq[String]] = Free.liftF(LowerCaseFilter(strings))
val process: (String => Free[Filter, Seq[String]]) = {
text: String =>
for {
p1 <- whitespaceFilter(text)
p2 <- lowerCaseFilter(p1)
} yield p2
}
def compiler: Filter ~> Id =
new (Filter ~> Id) {
def apply[A](fa: Filter[A]): Id[A] =
fa match {
// The code doesn't compile if uncommented...
case WhitespaceFilter(text) => ??? // text.trim.split("""[\s]+""")
case LowerCaseFilter(terms) => ??? // terms.map(_.toLowerCase)
}
}
val result: Seq[String] = process("Some Text").foldMap(compiler)
println(result) // should be Seq("some", "text")
}
Thanks!
I had a similar problem when playing around with the Cats example code you cited. I'm running IntelliJ IDEA and the IDE marks the commented lines with compiler errors but I can in fact run the code and get the output:
ArrayBuffer(some, text)
I think that IntelliJ's compiler is getting confused by the definition of Id:
type Id[A] = A
I'm not sure if IntelliJ uses it's own compiler or if it uses the Scala compiler. If the latter is true, there may be a way to get IntelliJ to use a more recent compiler that handles this type definition.
Good luck! :)

Generate case classes serializer and deserializer implicitly using play-json

I'm using play-json to map Json to case classes or enums. I'm looking for a smart way of creating Formats implicitly, since my project contains many types definitions.
At the moment I created a simple function to generate Formats for Enums:
def formatEnum[E <: Enumeration](enum: E) = Format(Reads.enumNameReads(enum), Writes.enumNameWrites)
But it takes a non-implicit argument so it cannot be used as implicit converter.
I tried to do the same for case classes:
implicit def caseFormat[A] = Json.format[A]
But I get the error "No unapply or unapplySeq function found", since Json.format is a macro which inspect the structure of the class.
Then I tried to create my macro in this way:
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
implicit def caseFormat[A](): Format[A] = macro impl[A]
def impl[A: c.WeakTypeTag](c: Context)(): c.Expr[Reads[A]] = {
import c.universe._
val TypeRef(pre, sym, args) = weakTypeTag[A].tpe
val t = args.head
val expr = q"Json.format[$t]"
c.Expr[Reads[A]](expr)
}
But the compiler does not find the implicit Format, though there is an implicit def that should generate the value.
Of course I can simply define many implicit val, but I think there is a smarter way to do it.
Assuming you have lots of case classes and you wish to json serialize it on the fly without having to write a play-json writer.
import play.api.libs.json._
import scala.reflect.runtime.{universe => ru}
implicit class writeutil[T: ru.TypeTag](i: T) {
implicit val writer = Json.writes[T]
def toJson() = Json.toJson(i)
}
def toInstance[T: ru.TypeTag](s: String): Option[T] = {
implicit val reader = Json.reads[T]
Json.fromJson[T](Json.parse(s)) match {
case JsSuccess(r: T, path: JsPath) => Option(r)
case e: JsError => None
}
}
An optimal implementation would be to re-use the reader/writer by caching and lookup. You can also read more about play-json.
You can use this as:
case class Entity(a: String, b: Int)
val e = Entity("Stack", 0)
e.toJson()

How to get ClassTag form TypeTag, or both at same time?

I have some code like this:
class ReflectiveJsonFormat[T:TypeTag] extends JsonFormat[T] {
def write(x: T) : JsValue = {
val t = typeOf[T]
val getters = t.declarations.filter { s => s.isMethod && s.asMethod.isGetter }
val mirror = runtimeMirror(this.getClass.getClassLoader)
val instanceMiror = mirror.reflect(x)
}
}
That last line fails with:
No ClassTag available for T
I thought TypeTag was more info than a ClassTag? Can I get the ClassTag from the TypeTag? If not, is there some syntax for saying that T has two context bounds -- both TypeTag and ClassTag? Or, how would you otherwise fix this code?
The library doesn't provide a built-in method that directly converts a TypeTag to a ClassTag, but you can write one:
import reflect.runtime.universe._
import reflect.ClassTag
def typeToClassTag[T: TypeTag]: ClassTag[T] = {
ClassTag[T]( typeTag[T].mirror.runtimeClass( typeTag[T].tpe ) )
}
Then in your method just add before the implicit ClassTag is needed:
implicit val c = typeToClassTag[T]
Well scala does support multiple context bounds if that is what you are after:
class ReflectiveJsonFormat[T:TypeTag:ClassTag]