Generate case classes serializer and deserializer implicitly using play-json - scala

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()

Related

What's the best way to store different types in a collection

I have a generic class:
class GenericType[T] {
def func(t: T) = ???
}
I need to implement a function that takes a List[String] and outputs the corresponding GenericType[T]. For example, if a client passes in List("SomeType1", "SomeType2"), the function should return List(GenericType[SomeType1], GenericType[SomeType2]). Basically, there's a string that maps to a type.
I don't find a good way to represent the return type for such function. Seq[GenericType[_]] as the return type can be an option but it requires the client to cast it into corresponding subclasses to invoke func as the type info is lost.
Alternatively, a case class can be used but this is not flexible as I need to modify the case class every time a new subclass is added.
case class (s1: Option[GenericType[SomeType1]] = None, s2: Option[SomeType2] = None, ...)
I'm curious what's a good way to represent the return type?
The easiest is
def stringToGenericType(s: String): GenericType[_] = s match {
case "SomeType1" => new GenericType[SomeType1]
case "SomeType2" => new GenericType[SomeType2]
}
GenericType[_] (or GenericType[Any] if you make GenericType covariant: class GenericType[+T]) would be an honest return type. You can't know at compile time which specific GenericType[...] you return based on a runtime string. Anyway you can't avoid casting somewhere because you can't guarantee the type statically. Anyway this kind of programming can't be type-safe.
Since we're doing a choice based on a runtime string, compile-time techniques (macros, implicits, Shapeless) are off the table. (*)
Actually, currently you don't need even runtime reflection. Your class GenericType[T] and method func in it seem not to do anything at runtime differently depending on type T. GenericType[SomeType1] and GenericType[SomeType2] are just GenericType[_] at runtime. So even the following implementation is possible
def stringToGenericType(s: String): GenericType[_] = new GenericType[Any]
Another situation would be if you created instances of different classes
class GenericType1[T]
class GenericType2[T]
import scala.reflect.runtime
import scala.reflect.runtime.universe._
val runtimeMirror = runtime.currentMirror
def stringToGenericTypeX(s: String): Any = {
val classSymbol = runtimeMirror.staticClass(s)
val constructorSymbol = classSymbol.typeSignature.decl(termNames.CONSTRUCTOR).asMethod
runtimeMirror.reflectClass(classSymbol).reflectConstructor(constructorSymbol).apply()
}
or you called different methods
class GenericType[T] {
def func1(t: T) = ???
def func2(t: T) = ???
}
def callFuncX(methodName: String, t: Any) = {
val classSymbol = runtimeMirror.classSymbol(classOf[GenericType[_]])
val methodSymbol = classSymbol.typeSignature.decl(TermName(methodName)).asMethod
runtimeMirror.reflect(new GenericType[Any]).reflectMethod(methodSymbol).apply(t)
}
or something behaved at runtime differently depending on type T
class GenericType[T: ClassTag] {
def func(t: T) = println(classTag[T].runtimeClass)
}
import scala.tools.reflect.ToolBox
val toolbox = runtimeMirror.mkToolBox()
def stringToGenericType(s: String): GenericType[_] = {
toolbox.eval(q"new GenericType[${TypeName(s)}]").asInstanceOf[GenericType[_]]
}
(*) Well, actually the first pattern matching (as I wrote it) can be automated with a macro
// in a different subproject
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def stringToGenericType(s: String): GenericType[_] = macro stringToGenericTypeImpl
def stringToGenericTypeImpl(c: blackbox.Context)(s: c.Tree): c.Tree = {
import c.universe._
val cases = List("SomeType1", "SomeType2").map(str =>
cq"$str => new GenericType[${TypeName(str)}]"
)
q"$s match { case ..$cases }"
}
val s = "SomeTime1"
stringToGenericType(s)
// scalacOptions += "-Ymacro-debug-lite"
//s match {
// case "SomeType1" => new GenericType[SomeType1]()
// case "SomeType2" => new GenericType[SomeType2]()
//}

How to use circe with generic case class that extends a sealed trait

I have this minimal example, I want to create encoders/decoders with circe semi-automatic derivation for the generic case class A[T]
import io.circe.{Decoder, Encoder}
import io.circe.generic.semiauto._
import io.circe.syntax._
sealed trait MyTrait
object MyTrait {
implicit val encoder: Encoder[MyTrait] = deriveEncoder
implicit val decoder: Decoder[MyTrait] = deriveDecoder
}
case class A[T](value: T) extends MyTrait
object A {
implicit def encoder[T: Encoder]: Encoder[A[T]] = deriveEncoder
implicit def decoder[T: Decoder]: Decoder[A[T]] = deriveDecoder
}
This codes does not compile and instead outputs this error
could not find Lazy implicit value of type io.circe.generic.encoding.DerivedAsObjectEncoder[A]
And the same for the decoder
What Am I doing wrong here and how can I get it working?
There are few issues. One is that MyTrait Encoder/Decoder will try to dispatch encodeing/decoding into codecs for the subtypes - since e thtrait is sealed all possible traits are known, so such list can be obtained by compiler.
BUT
While MyTrait trait does not take type parameters, its only implementation A takes. Which basically turns it into an existential type.
val myTrait: MyTrait = A(10)
myTrait match {
case A(x) =>
// x is of unknown type, at best you could use runtime reflection
// but codecs are generated with compile time reflection
}
Even if you wanted to make these codecs manually, you have no way of doing it
object Scope {
def aEncoder[T: Encoder]: Encoder[A[T]] = ...
val myTraitEncoder: Encoder[MyTrait] = {
case A(value) =>
// value is of unknown type, how to decide what Encoder[T]
// pass into aEncoder?
}
}
For similar reasons you couldn't manually implement Decoder.
To be able to implement codec manually (which is kind of prerequisite to being able to generate it), you can only remove type parameters as you go into subclasses, never add them.
sealed trait MyTrait[T]
case class A[T](value: T) extends MyTrait[T]
This would make it possible to know what kind of T is inside A since it would be passed from MyTrait, so you could write your codec manually and they would work.
Another problem is that reliable generation of ADT's usually require some configuration, e.g. whether or not to use discimination field. And that is provided by circe-generic-extras. Once you use it, (semi)automatic derivation is possible:
import io.circe.{Decoder, Encoder}
import io.circe.generic.extras.Configuration
import io.circe.generic.extras.semiauto._
import io.circe.syntax._
// can be used to tweak e.g. discriminator field name
implicit val config: Configuration = Configuration.default
sealed trait MyTrait[T]
object MyTrait {
implicit def encoder[T: Encoder]: Encoder[MyTrait[A]] = deriveEncoder
implicit def decoder[T: Decoder]: Decoder[MyTrait[A]] = deriveDecoder
}
case class A[T](value: T) extends MyTrait[T]
object A {
implicit def encoder[T: Encoder]: Encoder[A[T]] = deriveEncoder
implicit def decoder[T: Decoder]: Decoder[A[T]] = deriveDecoder
}
Among other solutions to the problem, if you really didn't want to use type parameter in MyTrait but have polymorphism in A would be to replace umbound, generic A with another ADT (or sum type in Scala 3), so that list of all possible implementations would be known and enumerated.
// x is of unknown type, at best you could use runtime reflection
I'll just comment that in principle you can define Decoder with runtime reflection (runtime compilation) based on the class of value in case class A[T](value: T)
sealed trait MyTrait
case class A[T](value: T) extends MyTrait
object A {
// custom codecs
implicit val intEnc: Encoder[A[Int]] = new Encoder[A[Int]] {
override def apply(a: A[Int]): Json = Json.obj("A" -> Json.obj("value" -> Json.fromInt(a.value)))
}
implicit val strEnc: Encoder[A[String]] = new Encoder[A[String]] {
override def apply(a: A[String]): Json = Json.obj("value" -> Json.fromString(a.value))
}
implicit val boolEnc: Encoder[A[Boolean]] = new Encoder[A[Boolean]] {
override def apply(a: A[Boolean]): Json = Json.fromBoolean(a.value)
}
}
val Integer = classOf[Integer]
val Boolean = classOf[java.lang.Boolean]
def primitiveClass[T](runtimeClass: Class[_]): Class[_] = runtimeClass match {
case `Integer` => classOf[Int]
case `Boolean` => classOf[Boolean]
//...
case _ => runtimeClass
}
object MyTrait {
implicit val encoder: Encoder[MyTrait] = new Encoder[MyTrait] {
override def apply(a: MyTrait): Json = a match {
case a1#A(t) =>
tb.eval(q"implicitly[io.circe.Encoder[A[${rm.classSymbol(primitiveClass(t.getClass)).toType}]]]")
.asInstanceOf[Encoder[A[_]]]
.apply(a1)
}
}
}
(A(1): MyTrait).asJson.noSpaces // {"A":{"value":1}}
(A("a"): MyTrait).asJson.noSpaces //{"value":"a"}
(A(true): MyTrait).asJson.noSpaces //true
But for case class A[T](value: Int) such trick would be impossible.

How to write JSON reads/writes and also ReactiveMongo handlers when case classes contain a generic type parameter?

In playframework I am trying to write the reads/writes for JSON, along with reactivemongo's BSON handlers for my case class:
import play.api.libs.json._
import reactivemongo.api.bson._
case class SomeThing[T](id: String, name: String, value: T)
object SomeThing {
implicit val stWrites = Json.writes[SomeThing]
implicit val stReads = Json.reads[SomeThing]
implicit val stHander = Macros.handler[SomeThing]
}
Because my case class as a type parameter T, I am getting this compile error currently:
class SomeThing takes type parameters
How can I solve this issue?
You need implicit polymorphic functions:
import play.api.libs.json._
import reactivemongo.api.bson._
case class SomeThing[T](id: String, name: String, value: T)
//defined as polymorphic functions
//type T in each case needs to be accompanied by some implicit evidence
implicit def stWrites[T: OWrites]: OWrites[SomeThing[T]] =
Json.writes[SomeThing[T]]
implicit def stReads[T: Reads]: Reads[SomeThing[T]] =
Json.reads[SomeThing[T]]
implicit def stHander[T: BSONDocumentHandler]: BSONDocumentHandler[SomeThing[T]] =
Macros.handler[SomeThing[T]]
stReads[String] //this works because play has an implicit StringReads available
case class OtherThing()
stReads[OtherThing] //this doesn't work we need to define a Reads[OtherThing]
implicit val otReads: Reads[OtherThing] =
Json.reads[OtherThing]
stReads[OtherThing] //now it works
Later Edit: I dropped the generic example

How to get the (static) type of an expression in Scala?

Does Scala have any equivalent to GCC's typeofextension? (Or C++ decltype?)
I'm generating code that references some external code (which may not be available yet), and I need a way to reference the type of that code in a method definition
For singleton objects, I could use Foo.type, but if Foo is an arbitrary expression, that doesn't work.
Update:
Here is a simplified example that shows the problem:
def f(x: typeof(Foo))(implicit M: Monoid[typeof(Foo)]) =
M.append(Foo, M.append(x, Foo))
The code I am working on doesn't know anything about Foo other than that it is a string representation of a Scala expression. It is outputting the above code to a .scala file which is to be later compiled as part of a separate project.
Of course the typeof(Foo) bits don't work. Using Foo.type would work only if Foo is a singleton.
Basically, I want to know if there is something I could substitute in place of typeof(Foo) that would work for arbitrary Scala expressions.
In Scala there is no typeof of that sort.
We can try to modify the method adding type parameter
def f[F](foo: F)(x: F)(implicit M: Monoid[F]) =
M.append(foo, M.append(x, foo))
and call it like f(Foo)(...), where Foo is the expression to be substituted, then F should be inferred upon compilation.
Otherwise I can imagine the following workflow. We could generate string represenation of the type of expression Foo from string represenation of Foo itself with Scalameta's SemanticDB and then insert string representation of expression Foo and this generated string represenation of the type.
One more option is to generate tree with macro annotation
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
class generate(foo: String) extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro generateMacro.impl
}
object generateMacro {
def impl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val str: String = c.prefix.tree match {
case q"new generate($s)" => c.eval[String](c.Expr(s))
}
val tree = c.typecheck(c.parse(str))
val tpe = tree.tpe.widen
annottees match {
case q"$mods def $name[..$_](...$_): $_ = $_" :: _ =>
q"""
$mods def $name(x: $tpe)(implicit M: Monoid[$tpe]): $tpe =
M.append($tree, M.append(x, $tree))
"""
}
}
}
#generate("1 + 1")
def f(): Unit = ()
// def f(x: Int)(implicit M: Monoid[Int]): Int = M.append(2, M.append(x, 2))
https://github.com/travisbrown/type-provider-examples/
https://docs.scala-lang.org/overviews/macros/typeproviders.html
Actually I guess this is close to what was asked
class TypeOf[A](a: A) {
type T = A
}
val tp = new TypeOf(Foo)
def f(x: tp.T)(implicit M: Monoid[tp.T]) = M.append(Foo, M.append(x, Foo))
Do you have a reference class for the type you want to use? Else define a custom class, and use:
classOf [Class_Name]
is equivalent typeOf
And if you re trying to know the class of your custom object, then use:
object_name.getClass

Scala: specifying a generic type that is constructible from another

I would like to do something which, more or less, boils down to the following:
def foo[S](x: String): S = S(x) // S(x) does not compile
So that if I have:
case class S1(x:String)
case class S2(x:String)
...
case class Sn(x:String)
I can write foo[Sx]("bar") to get Sx("foo").
Is there any way to specify that an instance of a class should be constructible from an instance of another (in this example String) and to actually invoke the constructor in a generic way?
You may use reflection (see #Ben Reich answer for detailed answer)
def foo[S:ClassTag](x: String): S = {
val runtimeClass = implicitly[ClassTag[S]].runtimeClass
val constructor = runtimeClass.<get a constructor with single String argument>
constructor(x) .asInstanceOf[S]
}
Or a type class that can construct an instance:
trait CanConstruct[S] {
def apply(x:String):S
}
def foo[S:CanConstruct](x: String): S = {
val constructor = implicitly[CanConstruct[S]]
constructor(x).asInstanceOf[S]
}
UPD You would need an instance of the type class for every type you wish to construct:
implicit val s1constructor = new CanConstruct[S1] { def apply(x:String) = S1(x) }
...
Also it seems to be the case for conversion functions:
implicit val convertStringToS1 = S1(_)
implicit val convertStringToS2 = S2(_)
...
Using reflection:
import reflect.ClassTag
def foo[S: ClassTag](x: String) = implicitly[ClassTag[S]]
.runtimeClass
.getConstructors
.map(a => a -> a.getParameters)
.collectFirst {
case (constructor, Array(p)) if p.getType == classOf[String]
=> constructor.newInstance(x).asInstanceOf[S]
}
Which will return an Option[S], if the proper constructor is found.
I sort of solved it with a macro:
object Construct {
import scala.language.experimental.macros
import scala.reflect.macros.Context
def construct[A,B](x:B):A = macro constructImpl[A,B]
def constructImpl[A: c.WeakTypeTag,B](c:Context)(x:c.Expr[B]) = {
import c.universe._
c.Expr[A](q"""new ${c.weakTypeOf[A]}(${x.tree})""")
}
}
I now can write things like:
case class Foo(x:String)
case class Bar(x:Int)
construct[Foo,String]("foo")
construct[Bar,Int](42)
It would be nice to find a way to avoid having to write the second type parameter, though.