Cannot find an implicit value for ContextShift - scala

I am trying to create webapp with http4s that is based on Http4sServlet.
The following code does not compile:
import cats.effect._
import org.http4s.servlet.BlockingServletIo
import org.http4s.servlet.Http4sServlet
import scala.concurrent.ExecutionContext.global
import org.http4s.implicits._
class UserSvcServlet
extends Http4sServlet[IO](service = UserSvcServer.start
, servletIo = BlockingServletIo(4096, Blocker.liftExecutionContext(global)))(IOApp)
the error message:
[error] /home/developer/scala/user-svc/src/main/scala/io/databaker/UserSvcServlet.scala:12:54: Cannot find implicit value for ConcurrentEffect[[+A]cats.effect.IO[A]].
[error] Building this implicit value might depend on having an implicit
[error] s.c.ExecutionContext in scope, a Scheduler, a ContextShift[[+A]cats.effect.IO[A]]
[error] or some equivalent type.
[error] extends Http4sServlet[IO]( service = UserSvcServer.stream
[error] ^
[error] /home/developer/scala/user-svc/src/main/scala/io/databaker/UserSvcServlet.scala:13:36: Cannot find an implicit value for ContextShift[[+A]cats.effect.IO[A]]:
[error] * import ContextShift[[+A]cats.effect.IO[A]] from your effects library
[error] * if using IO, use cats.effect.IOApp or build one with cats.effect.IO.contextShift
[error] , servletIo = BlockingServletIo(4096, Blocker.liftExecutionContext(global)))
[error] ^
[error] two errors found
[error] (Compile / compileIncremental) Compilation failed
[error] Total time: 1 s, completed May 29, 2020, 8:45:00 PM
The UserSvcServer is implemented as follows:
import org.http4s.HttpApp
import cats.effect.{ConcurrentEffect, ContextShift, Timer}
import org.http4s.implicits._
import org.http4s.server.middleware.Logger
object UserSvcServer {
def start[F[_] : ConcurrentEffect](implicit T: Timer[F], C: ContextShift[F]): HttpApp[F] = {
val helloWorldAlg = HelloWorld.impl[F]
val httpApp = UserSvcRoutes.helloWorldRoutes[F](helloWorldAlg).orNotFound
Logger.httpApp(true, true)(httpApp)
}
}
How can I import ContextShift implicitly?

Context shift is just cats' wrapper over ExecutionContext. You can create one explicitly as stated in docs:
implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
You usually create one context shift at the entry point of your app (probably in the main method).
If your app uses IOApp from cats-effect it would have already implicit for contextShift in scope. It will use execution context, which would have number of threads equal to available processors of your computer.
If you want to use created contextShift "deeper" inside your application you can pass it as an implicit parameter:
def doSomething(implicit cs: ContextShift[IO]): IO[Unit] = ???
So in order to make your code work, you need to make sure that method or class calls constructor of UserSvcServlet has implicit for contextShift:
(implicit cs: ContextShift[IO]).
You could also put it in separate object:
object AppContextShift {
implicit val cs: ContextShift[IO] = IO.contextShift(ExecutionContext.global)
implicit val t: Timer[IO] = IO.timer(ExecutionContext.global) //you will probably also need timer eventually
}
Then you can import it when contextShift is needed:
import AppContextShift._
By the way, using a global execution context for Blocker is not good idea.
Blocked is used for blocking operations and using it with ExecutionContext.global might lead to thread starvation in your app.
The most common approach is to use blocker created from cached thread pool:
Blocker.liftExecutorService(Executors.newCachedThreadPool())

Related

Could not find implicit value for parameter write eror, yet I defined the handler using the macro

I have the following:
Account.scala
package modules.accounts
import java.time.Instant
import reactivemongo.api.bson._
case class Account(id: String, name: String)
object Account {
type ID = String
implicit val accountHandler: BSONDocumentHandler[Account] = Macros.handler[Account]
// implicit def accountWriter: BSONDocumentWriter[Account] = Macros.writer[Account]
// implicit def accountReader: BSONDocumentReader[Account] = Macros.reader[Account]
}
AccountRepo.scala
package modules.accounts
import java.time.Instant
import reactivemongo.api.collections.bson.BSONCollection
import scala.concurrent.ExecutionContext
final class AccountRepo(
val coll: BSONCollection
)(implicit ec: ExecutionContext) {
import Account.{ accountHandler, ID }
def insertTest() = {
val doc = Account(s"account123", "accountName") //, Instant.now)
coll.insert.one(doc)
}
}
The error I am getting is:
could not find implicit value for parameter writer: AccountRepo.this.coll.pack.Writer[modules.accounts.Account]
[error] coll.insert.one(doc)
From what I understand the implicit handler that is generated by the macro should be enough and create the Writer. What am I doing wrong?
Reference: http://reactivemongo.org/releases/1.0/documentation/bson/typeclasses.html
The code is mismixing different versions.
The macro generated handler is using the new BSON API, as it can be seen with the import reactivemongo.api.bson, whereas the collection is using an old driver, as it can be seen as it uses reactivemongo.api.collections.bson instead of reactivemongo.api.bson.collection.
It's recommended to have a look at the documentation, and not mixing incompatible versions of related libraries.

Akka HTTP client - Unmarshal with Play JSON

I am using Akka HTTP as a client to do a POST request and parse the answer. I am using Play JSON and I get the following compiler error:
could not find implicit value for parameter um: akka.http.scaladsl.unmarshalling.Unmarshaller[akka.http.javadsl.model.ResponseEntity,B]
[ERROR] Unmarshal(response.entity).to[B].recoverWith {
This is the dependency I added to use Play JSON instead of Spray:
"de.heikoseeberger" %% "akka-http-play-json"
My class definition is:
class HttpClient(implicit val system: ActorSystem, val materializer: Materializer) extends PlayJsonSupport {
and the method definition is:
private def parseResponse[B](response: HttpResponse)(implicit reads: Reads[B]): Future[B] = {
if (response.status().isSuccess) {
Unmarshal(response.entity).to[B].recoverWith {
....
In the imports I have:
import play.api.libs.json._
import scala.concurrent.ExecutionContext.Implicits.global
import de.heikoseeberger.akkahttpplayjson.PlayJsonSupport._
It seems to me that I have the required implicits in scope. The Marshal part has a similar logic (but with Writes instead of Reads) and compiles fine. What am I missing?
Check your other imports. Based on the error message, it appears that you're using akka.http.javadsl.model.HttpResponse instead of akka.http.scaladsl.model.HttpResponse; PlayJsonSupport only supports the Scala DSL:
private def parseResponse[B](response: HttpResponse)(implicit reads: Reads[B]): Future[B] = ???
// ^ this should be akka.http.scaladsl.model.HttpResponse
In other words, use
import akka.http.scaladsl.model._
instead of
import akka.http.javadsl.model._

found java.util.Date but required java.sql.Date?

I'm trying to create a function to check if a string is a date. However, the following function got the error.
import org.apache.spark.SparkContext
import org.apache.spark.SparkContext._
import org.apache.spark.SparkConf
import java.sql._
import scala.util.{Success, Try}
def validateDate(date: String): Boolean = {
val df = new java.text.SimpleDateFormat("yyyyMMdd")
val test = Try[Date](df.parse(date))
test match {
case Success(_) => true
case _ => false
}
}
Error:
[error] C:\Users\user1\IdeaProjects\sqlServer\src\main\scala\main.scala:14: type mismatch;
[error] found : java.util.Date
[error] required: java.sql.Date
[error] val test = Try[Date](df.parse(date))
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 2 s, completed May 17, 2017 1:19:33 PM
Is there a simpler way to validate if a string is a date without create a function?
The function is used to validate the command line argument.
if (args.length != 2 || validateDate(args(0))) { .... }
Try[Date](df.parse(date)) You are not interested in type here because you ignore it. So simply omit type parameter. Try(df.parse(date)).
Your function could be shorter. Try(df.parse(date)).isSuccess instead pattern matching.
If your environment contains java 8 then use java.time package always.
import scala.util.Try
import java.time.LocalDate
import java.time.format.DateTimeFormatter
// Move creation of formatter out of function to reduce short lived objects allocation.
val df = DateTimeFormatter.ofPattern("yyyy MM dd")
def datebleStr(s: String): Boolean = Try(LocalDate.parse(s,df)).isSuccess
use this: import java.util.Date

Combine Two Slick Futures and then execute them together

I have written this code and I am trying to combine two futures obtained from separate SQL operations.
package com.example
import tables._
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.Duration
import slick.backend.DatabasePublisher
import slick.driver.H2Driver.api._
object Hello {
def main(args: Array[String]): Unit = {
val db = Database.forConfig("h2mem1")
try {
val people = TableQuery[Persons]
val setupAction : DBIO[Unit] = DBIO.seq(
people.schema.create
)
val setupFuture : Future[Unit] = db.run(setupAction)
val populateAction: DBIO[Option[Int]] = people ++= Seq(
(1, "test1", "user1"),
(2, "test2", "user2"),
(3, "test3", "user3"),
(4, "test4", "user4")
)
val populateFuture : Future[Option[Int]] = db.run(populateAction)
val combinedFuture : Future[Option[Int]] = setupFuture >> populateFuture
val r = combinedFuture.flatMap { results =>
results.foreach(x => println(s"Number of rows inserted $x"))
}
Await.result(r, Duration.Inf)
}
finally db.close
}
}
But I get an error when I try to compile this code
[error] /Users/abhi/ScalaProjects/SlickTest2/src/main/scala/Hello.scala:29:
value >> is not a member of scala.concurrent.Future[Unit]
[error] val combinedFuture : Future[Option[Int]] = setupFuture >>
populateFuture
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
The same code works, If I nest the populateFuture inside the map function of the setupFuture. But I don't want to write nested code because it will become very messy once there are more steps to do.
So I need a way to combine all futures into a single future and then execute it.
Edit:: I also tried combining the two actions
val combinedAction = setupAction.andThen(populateAction)
val fut1 = combinedAction.map{result =>
result.foreach{x =>println(s"number or rows inserted $x")}
}
Await.result(fut1, Duration.Inf)
but got error
/Users/abhi/ScalaProjects/SlickTest/src/main/scala/com/example/Hello.scala:31: type mismatch;
[error] found : scala.concurrent.Future[Option[Int]]
[error] required: PartialFunction[scala.util.Try[Unit],?]
[error] val combinedAction = setupAction.andThen(populateAction)
[error] ^
[error] one error found
[error] (compile:compileIncremental) Compilation failed
[error] Total time: 3 s, completed Jun 26, 2015 3:50:51 PM
Mohitas-MBP:SlickTest abhi$
According to http://slick.typesafe.com/doc/3.0.0/api/index.html#slick.dbio.DBIOAction, andThen() is what you are looking for:
val combinedAction = setupAction.andThen(populateAction)
val results = db.run(combinedAction)
populateAction will only run after setupAction completed successfully. This is crucial in your case since slick is fully non-blocking. The code you have now will cause problems at runtime. Both actions in your code will run asynchronously at the same time. There is no way to determine which action is executed first. But because populateAction depends on setupAction, you must ensure setupAction is executed first. Therefore use andThen.

Scalatra JSON guide code not compiling

I copied the instructions on the JSON formatting Guide found here: http://www.scalatra.org/2.2/guides/formats/json.html
Below is MyScalatraServlet.scala file with all of the code I embedded to test out JSON formatting:
package net.example.testapp
import org.scalatra._
import scalate.ScalateSupport
// JSON-related libraries
import org.json4s.{DefaultFormats, Formats}
// JSON handling support from Scalatra
import org.scalatra.json._
class MyScalatraServlet extends TestAppStack with JacksonJsonSupport {
get("/") {
FlowerData.all
}
}
// Sets up automatic case class to JSON output serialization, required by
// the JValueResult trait.
protected implicit val jsonFormats: Formats = DefaultFormats
case class Flower(slug: String, name: String)
object FlowerData {
/**
* Some fake flowers data so we can simulate retrievals.
*/
var all = List(
Flower("yellow-tulip", "Yellow Tulip"),
Flower("red-rose", "Red Rose"),
Flower("black-rose", "Black Rose"))
}
It seems the compiler does not like the following line:
protected implicit val jsonFormats: Formats = DefaultFormats
Here's the error message:
[error] /Users/test/test-app/src/main/scala/net/example/testapp/MyScalatraServlet.scala:22: expected start of definition
[error] protected implicit val jsonFormats: Formats = DefaultFormats
[error] ^
[error] one error found
[error] (compile:compile) Compilation failed
[error] Total time: 2 s, completed Jun 17, 2013 4:04:34 PM
>
Your val jsonFormats is just kinda floating there, not tied to a class or anything. A val needs to be defined as part of another construct like a trait, class or object. Try moving it inside of that servlet class, just before the call to get("/")