one of my models includes a list of BSONObjectIDs:
case class User(
_id: BSONObjectID = BSONObjectID.generate,
email: String,
favorite_ids: List[BSONObjectID] = List(),
home_folder_id: Option[BSONObjectID] = None
)
unfortunately, the compiler complains with the following message:
No implicit format for List[reactivemongo.bson.BSONObjectID]
available.
it complains in the last line of the following snippet.
import play.api.libs.json._
import reactivemongo.bson._
import play.modules.reactivemongo.json.BSONFormats._
import play.modules.reactivemongo.json._, ImplicitBSONHandlers._
import play.modules.reactivemongo.json.collection._
implicit val userFormat = Json.format[User]
Funny observation: the Option[BSONObjectID] is working when i comment the List[] line out.
Anyone know how to include a format for lists? I figured that should be available implicitly.
thanks
You can try with snapshot "org.reactivemongo" %% "play2-reactivemongo" % "0.11.2.play24-SNAPSHOT".
scala> import play.modules.reactivemongo.json._
import play.modules.reactivemongo.json._
scala> import reactivemongo.bson._
import reactivemongo.bson._
scala> import play.api.libs.json._
import play.api.libs.json._
scala> implicitly[Reads[BSONObjectID]]
res0: play.api.libs.json.Reads[reactivemongo.bson.BSONObjectID] = play.modules.reactivemongo.json.BSONFormats$BSONObjectIDFormat$#4d27019c
scala> implicitly[Writes[BSONObjectID]]
res1: play.api.libs.json.Writes[reactivemongo.bson.BSONObjectID] = play.modules.reactivemongo.json.BSONFormats$BSONObjectIDFormat$#4d27019c
scala> implicitly[Format[BSONObjectID]]
res2: play.api.libs.json.Format[reactivemongo.bson.BSONObjectID] = play.modules.reactivemongo.json.BSONFormats$BSONObjectIDFormat$#4d27019c
scala> implicitly[Format[List[BSONObjectID]]]
res3: play.api.libs.json.Format[List[reactivemongo.bson.BSONObjectID]] = play.api.libs.json.DefaultFormat$$anon$4#43b5fbbd
scala> implicitly[Reads[JsObject]]
res4: play.api.libs.json.Reads[play.api.libs.json.JsObject] = play.api.libs.json.DefaultReads$JsObjectReads$#78a1f869
scala> implicitly[OWrites[BSONDocument]]
res5: play.api.libs.json.OWrites[reactivemongo.bson.BSONDocument] = play.modules.reactivemongo.json.ImplicitBSONHandlers$BSONDocumentWrites$#1763c4c3
The implicits are all provided by the unified import play.modules.reactivemongo.json._
Related
I defined the case class dynamically using Toolbox.
And when I do extract of json4s, I get the following exception:
import org.json4s._
import scala.reflect.runtime._
import scala.tools.reflect.ToolBox
implicit val formats = DefaultFormats
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
val parse =
toolBox.parse(
s"""
| case class Person( name:String, age:String)
| scala.reflect.classTag[ Person].runtimeClass
""".stripMargin)
val person = toolBox.compile( parse)().asInstanceOf[Class[_]]
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
val jv = js.extract[person.type ] //How do I pass the class type?
**"Exception in thread "main" org.json4s.MappingException: No constructor for type Class, JObject(List((name,JString(Tom)), (age,JString(28))))"**
But after creating a dummy instance of the dynamically created class,
Then pass in the type of that dummy class and it will be parsed.
I don't know why.
How can I parse without creating a dummy instance?
import org.json4s._
import scala.reflect.runtime._
import scala.tools.reflect.ToolBox
implicit val formats = DefaultFormats
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
val parse =
toolBox.parse(
s"""
| case class Person( name:String, age:String)
| scala.reflect.classTag[ Person].runtimeClass
""".stripMargin)
val person = toolBox.compile( parse)().asInstanceOf[Class[_]]
val dummy = person.getConstructors.head.newInstance( "a", "b") //make dummy instance
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
println( js.extract[ dummy.type ] ) // Result: Person(Tom,28)
x.type is a singleton type. So person.type can't be correct, it's the singleton type of this specific variable val person: Class[_].
Fortunately, dummy.type is correct because of the runtime reflection. This works even for ordinary case class
import org.json4s._
import org.json4s.jackson.JsonMethods
implicit val formats = DefaultFormats
case class Person(name: String, age: String)
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
val dummy0: AnyRef = Person("a", "b")
val dummy: AnyRef = dummy0
js.extract[dummy.type] // Person(Tom,28)
Actually after resolving implicits js.extract[Person] is
js.extract[Person](formats, ManifestFactory.classType(classOf[Person])
js.extract[dummy.type] is
js.extract[dummy.type](formats, ManifestFactory.singleType(dummy))
So for a toolbox-generated case class we could try
import org.json4s._
import org.json4s.jackson.JsonMethods
import scala.reflect.ManifestFactory
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
implicit val formats = DefaultFormats
val person = toolBox.eval(q"""
case class Person(name:String, age:String)
scala.reflect.classTag[Person].runtimeClass
""").asInstanceOf[Class[_]]
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
js.extract(formats, ManifestFactory.classType(person))
// java.lang.ClassCastException: __wrapper$1$6246735221dc4d64a9e372a9d0891e5e.__wrapper$1$6246735221dc4d64a9e372a9d0891e5e$Person$1 cannot be cast to scala.runtime.Nothing$
(toolBox.eval(tree) is instead of toolBox.compile(toolBox.parse(string))())
but this doesn't work.
Manifest should be captured from toolbox compile time
import org.json4s._
import org.json4s.jackson.JsonMethods
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val cm = universe.runtimeMirror(getClass.getClassLoader)
val toolBox = cm.mkToolBox()
implicit val formats = DefaultFormats
val person = toolBox.eval(q"""
case class Person(name:String, age:String)
val clazz = scala.reflect.classTag[Person].runtimeClass
scala.reflect.ManifestFactory.classType(clazz)
""").asInstanceOf[Manifest[_]]
val js = JsonMethods.parse("""{ "name":"Tom","age" : "28"}""")
js.extract(formats, person) // Person(Tom,28)
Alternatively you don't need java-reflection Class at all. You can do
import scala.reflect.runtime
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
val cm = runtime.currentMirror
val toolBox = cm.mkToolBox()
toolBox.eval(q"""
import org.json4s._
import org.json4s.jackson.JsonMethods
implicit val formats = DefaultFormats
case class Person(name: String, age: String)
val js = JsonMethods.parse(${"""{"name":"Tom","age" : "28"}"""})
js.extract[Person]
""") // Person(Tom,28)
or
import org.json4s._
import org.json4s.jackson.JsonMethods
import scala.reflect.runtime
import scala.reflect.runtime.universe._
import scala.tools.reflect.ToolBox
object Main extends App {
val cm = runtime.currentMirror
val toolBox = cm.mkToolBox()
implicit val formats = DefaultFormats
val person: ClassSymbol = toolBox.define(q"case class Person(name: String, age: String)")
val js = JsonMethods.parse("""{"name":"Tom","age" : "28"}""")
val jv = toolBox.eval(q"""
import Main._
js.extract[$person]
""")
println(jv) // Person(Tom,28)
}
I have a value of this type:
val effects : List[EitherT[Future, Error, Foo]] = ...
How do I run through the list and execute those effects? I did
effects.traverse
But that method is not defined for that type.
As mentioned in comments, it's better to get rid of Future when you are declaring some list of effects and want to execute them and gather effects in one list after. It's better to use IO or another lazy evaluated effect.
So, if you just need to traverse on Future[List[A]]:
import cats.data.EitherT
import scala.concurrent.{ExecutionContext, Future}
import cats.syntax.traverse._
import cats.instances.list._
import cats.instances.future._
implicit val ec: ExecutionContext = scala.concurrent.ExecutionContext.global
case class Foo()
val effects : List[EitherT[Future, Error, Foo]] = ???
def f(e: EitherT[Future, Error, Foo]): Future[Either[Error, Foo]] = ???
val result: Future[List[Either[Error, Foo]]] = effects.traverse(f)
this code compiles and all you need is implement f. You need to add import cats.instances.future._ to have traverse function in Furure.
but better way to construct you process on something like IO:
import cats.data.EitherT
import cats.syntax.traverse._
import cats.instances.list._
import cats.effect.IO
val effects : List[EitherT[IO, Error, Foo]] = ???
def f(e: EitherT[IO, Error, Foo]): IO[Either[Error, Foo]] = ???
val result: IO[List[Either[Error, Foo]]] = effects.traverse(f)
and call it using unsafeRunAsync.
I have a question about using Traverse together with EitherT. Let's say we have a code like this:
def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
EitherT(Future.successful(try { Right(s.toInt) } catch { case e:
NumberFormatException => Left(e)}))
}
List("1", "2").traverse(validate)
Unfortunately this code does not compile, because we are missing something:
error: could not find implicit value for evidence parameter of type cats.Applicative[G] List("1", "2").traverse(validate)
I tried to look this up and found for example this answer: Switching between EitherT and Validation to accumulate error or traverse or Validation versus disjunction
So it seems some solution could exists. But the problem is that both of them are using traverseU, which is no longer an option in scala 2.12. So how can this be done please?
EDIT
This is the code including imports:
import cats.data.EitherT
import cats.syntax.traverse._
import cats.instances.list._
import cats.instances.future._
import scala.concurrent.ExecutionContext.global
import scala.concurrent.Future
def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
EitherT(Future.successful(try { Right(s.toInt) } catch { case e:
NumberFormatException => Left(e)}))
}
List("1", "2").traverse(validate)
Usually cats will pack specific evidence implicits under different imports. In this case, you need the proofs for List and Future.
import cats.data.EitherT
import cats.syntax.traverse._
import cats.instances.list._
import cats.instances.future._
import scala.concurrent.Future
def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
EitherT(Future.successful(try { Right(s.toInt) } catch { case e: NumberFormatException => Left(e) }))
}
List("1", "2").traverse(validate)
This code compiles with cats 1.2.0 for me.
import cats.{Applicative, Monad}
import cats.data.EitherT
import cats.syntax.traverse._
import cats.instances.list._
import cats.instances.future._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
def validate(s: String): EitherT[Future, NumberFormatException, Int] = {
EitherT(Future.successful(try { Right(s.toInt) } catch { case e: NumberFormatException => Left(e) }))
}
type Tmp[T] = EitherT[Future, NumberFormatException,T]
List("1", "2").traverse[Tmp, Int](validate)
So this is how it works to me. I had to create new type.
I need to pass byte like "0x02" through tcp connection and process it on a server. Code of client is here:
package protocol
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Source, Tcp}
import akka.util.ByteString
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.{Source, Tcp}
import akka.util.ByteString
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
class UpperServiceClient(ip: String, port: Int) {
def run = {
implicit val system = ActorSystem("ClientSys")
implicit val materializer = ActorMaterializer()
val a1 = Array("0x02", "0x02").toSeq
val testInput = a1.map(ByteString(_))
val result: Future[ByteString] = Source(testInput).via(Tcp().outgoingConnection(ip, port)).
runFold(ByteString.empty) { (acc, in) => acc ++ in }
val res: ByteString = Await.result(result, 10.seconds)
}
}
But IDEA shows me error:
Type mismatch, expected: Iterable[NotInferedT], actual: Seq[ByteString]
What should I do to pass "0x02" as whole byte?
The Source factory method that you're using expects an immutable Iterable. By default, calling .toSeq on an array returns a mutable Seq. One way to address this is to call .toList instead:
val a1 = Array("0x02", "0x02").toList
This is easier to explain in code. I want to do something like:
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
val toolbox = currentMirror.mkToolBox()
val universe: scala.reflect.runtime.universe.type = scala.reflect.runtime.universe
import universe._
class A { def a = "hello A" }
val c = toolbox.compile(q"""class C(x: Int) extends A { def r = x }""")
Note how the dynamically generated class C inherits from a class A that's known/already-compiled.
Is there some way to use a toolbox that knows about A?
How do I use a dynamically generated class?
Here is an example. The "pasted" class is loaded by the REPL's class loader, so you can supply it explicitly. You can also use tb.eval.
$ scala
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_60).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import reflect.runtime._,universe._,tools.reflect.ToolBox
import reflect.runtime._
import universe._
import tools.reflect.ToolBox
scala> :pa -raw
// Entering paste mode (ctrl-D to finish)
package p { class Parent(val i: Int) }
// Exiting paste mode, now interpreting.
scala> val tb = runtimeMirror($intp.classLoader).mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl#5e316c74
scala> tb.compile(tb.parse("""case class Child(j: Int) extends p.Parent(42) ; val c = Child(17) ; c.j"""))()
res0: Any = 17
scala> val tb = currentMirror.mkToolBox()
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl#59a67c3a
scala> tb.compile(tb.parse("""case class Child(j: Int) extends p.Parent(42) ; val c = Child(17) ; c.j"""))()
res1: Any = 17
There is surely an example in the docs somewhere or on this site.