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.
Related
I am trying to use fs2.io.writeOutputStream for the output to a Java AWS lambda fn. I don't know how to provide the implicit parameter it's looking for:
"no implicits found for parameter cs: ContextShift[IO]"
I found some documentation for creating my own implicit ContextShift object but that seems like overkill for what I'm trying to do.
final def handleRequest(in: InputStream, out: OutputStream, context: Context): Unit = (for {
bytes <- in.compile.toList
str = getString(bytes)
args <- decode(str).raiseIO
_ <- produce(args).to(writeOutputStream(IO(out), global)).compile.drain
} yield Unit).unsafeRunAsyncAndForget() // throws exception in the case of Failure
// ------------------------------------------------
// produce(args: MyCaseClass): fs2.Stream[IO, Byte]
"By default, Cats Effect can provide instance of ContextShift[IO] that manages thread-pools, but only if there’s an ExecutionContext in scope or if IOApp is used."
-- Cats-effect documentation.
From an ExecutionContext.
import cats.effect.{IO, ContextShift}
import scala.concurrent.ExecutionContext.Implicits.global
val contextShift = IO.contextShift(global)
Using IOApp.
import cats.effect.{IO, IOApp, ContextShift}
object Main extends IOApp {
override def run(args: List[String]): IO[ExitCode] = {
val cs = implicitly[ContextShift[IO]]
}
}
What is the preferred way to call functions which constructs instances implementing certain type classes e.g. deserialize in the following example:
// Simulacrum annotation
#typeclass trait Encodable[A] {
def deserialize(bytes: Seq[Byte]): Try[A] // Constructor
def serialize(proof: A): Seq[Byte]
}
// implementation Encodable for Int
implicit val IntEncodable: Encodable[Int] = new Encodable[Int] {
def deserialize(bytes: Seq[Byte]): Try[Int] = Success(bytes.head)
def serialize(value: Int): Seq[Byte] = List(value.toByte)
}
// import Simulacrum generated ops
import Encodable.ops._
// is it best practise to define a function like this for all constructor-like functions in the typeclass?
def deserialize[A:Encodable](bytes: Vector[Byte])(implicit instance: Encodable[A]): Try[A] = instance.deserialize(bytes)
// or def deserialize[A:Encodable](bytes: Vector[Byte]): Try[A] = Encodable[A].deserialize(bytes)
// call constructor
val value: Int = deserialize(Vector(1)).get
// call method
println(value.serialize)
To me, this is overkill. My preferred way, and what I have seen in other code bases, is just:
val value: Int = Encodable[Int].deserialize(Vector(1)).get
I don't think much is gained by that additional deserialize method. I have also seen:
val value: Int = implicitly[Encodable[Int]].deserialize(Vector(1)).get
Which might be more familiar to those who haven't seen simulacrum before, but I don't think it's that necessary.
I'm creating custom json readers for case classes but it can't find implicit JsonReader type class for List[T] which is used in other case class.
When I checked DefaultJsonProtocol, it has implicit format for collections already;
implicit def listFormat[T :JsonFormat] = new RootJsonFormat[List[T]] {
def write(list: List[T]) = JsArray(list.map(_.toJson).toVector)
def read(value: JsValue): List[T] = value match {
case JsArray(elements) => elements.map(_.convertTo[T])(collection.breakOut)
case x => deserializationError("Expected List as JsArray, but got " + x)
}
}
Here is the simplified code;
case class Test(i: Int, d: Double)
case class ListOfTest(t: List[Test])
trait TestResultFormat extends DefaultJsonProtocol {
import CustomFormat._
implicit object TestJsonFormat extends RootJsonReader[Test] {
override def read(json: JsValue): Test = {
val jsObject = json.asJsObject
val jsFields = jsObject.fields
val i = jsFields.get("i").map(_.convertTo[Int]).getOrElse(0)
val d = jsFields.get("d").map(_.convertTo[Double]).getOrElse(0d)
Test(i, d)
}
}
implicit object ListOfTestJsonFormat extends RootJsonReader[ListOfTest] {
override def read(json: JsValue): ListOfTest = {
val jsObject = json.asJsObject
val jsFields = jsObject.fields
val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
ListOfTest(tests)
}
}
}
Here is the errors;
Error:(230, 53) not enough arguments for method convertTo: (implicit evidence$1: spray.json.JsonReader[List[com.xx.Test]])List[com.xx.Test].
Unspecified value parameter evidence$1.
val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
^
Error:(230, 53) Cannot find JsonReader or JsonFormat type class for List[com.xx.Test]
val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
^
I think the problem is related to the fact that the JsonReader for List[T] in DefaultJsonProtocol is a RootJsonFormat (not a RootJsonReader), which basically means you can read it and also write it. So, when you try to read a List[Item], it's expected that you are also able to write Items. So, you could use RootJsonFormat instead and throw an exception in case you try to write it (since you don't support it). For example:
import spray.json._
implicit object TestJsonFormat extends RootJsonFormat[Test] {
override def read(json: JsValue): Test = {
val jsObject = json.asJsObject
val jsFields = jsObject.fields
val i = jsFields.get("i").map(_.convertTo[Int]).getOrElse(0)
val d = jsFields.get("d").map(_.convertTo[Double]).getOrElse(0d)
Test(i, d)
}
override def write(obj: Test): JsValue = serializationError("not supported")
}
If you are aware of a clean solution involving only the readers, please do let me know because I ran into this problem myself and couldn't find anything else.
I have learned that limitation comes from spray-json:
spray-json 's type class infrastructure is build around the (Root)JsonFormat type, not the (Root)JsonReader. So you'll indeed have to provide a "Format" even if you are just reading.
Check here.
To overcome issue; I created another trait extends RootJsonFormat instead of reader and overrides write method with basically not implemented method.
trait EmptyWriterFormat[T] extends RootJsonFormat[T] {
override def write(o: T): JsValue = ???
}
I'm trying to understand the following blog post, which discusses how to use macros to create a generic macro-based approach to convert case class objects to and from a map: http://blog.echo.sh/post/65955606729/exploring-scala-macros-map-to-case-class-conversion
Even though I read the entire post and another article on scala macros, I still do not fully understand how they work. Unfortunately, I'm receiving a couple of compile errors from the example code given in the blog post and am not sure why the errors are occurring nor how to resolve them. I'm reproducing the code below, preceded by the compile errors, for completeness (I annotated the code snippet with comments regarding the compile errors). Does anyone know why these compiler issues are occurring and how to resolve them?
-type mismatch; found : field.NameType required:
c.universe.TermName
-Can't unquote List[Nothing] with .., bottom type values often indicate programmer mistake
Here's the code:
import scala.reflect.macros.Context
import scala.language.experimental.macros
trait Mappable[T] {
def toMap(t: T): Map[String, Any]
def fromMap(map: Map[String, Any]): T
}
object Mappable {
implicit def materializeMappable[T]: Mappable[T] = macro materializeMappableImpl[T]
def materializeMappableImpl[T: c.WeakTypeTag](c: Context): c.Expr[Mappable[T]] = {
import c.universe._
val tpe = weakTypeOf[T]
val companion = tpe.typeSymbol.companionSymbol
val fields = tpe.declarations.collectFirst {
case m: MethodSymbol if m.isPrimaryConstructor ⇒ m
}.get.paramss.head
val (toMapParams, fromMapParams) = fields.map { field ⇒
val name = field.name
val decoded = name.decoded
val returnType = tpe.declaration(name).typeSignature
(q"$decoded → t.$name", q"map($decoded).asInstanceOf[$returnType]") // error 1
}.unzip
c.Expr[Mappable[T]] {
q"""
new Mappable[$tpe] {
def toMap(t: $tpe): Map[String, Any] = Map(..$toMapParams)
def fromMap(map: Map[String, Any]): $tpe = $companion(..$fromMapParams) // error 2
}
"""
}
}
}
change t.$name to t.${name.toTermName}
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)