"unreachable" implicit val when trying to add json parsing with Play Json - json

I have something like:
sealed trait Foo
case class Bar(field: ...) extends Foo
case class Baz(otherField: ...) extends Foo
trait JsonFormat {
implicit val barWrites = Json.writes[Bar]
implicit val barReads = Json.reads[Bar]
implicit val bazWrites = Json.writes[Baz]
implicit val bazReads = Json.reads[Baz]
implicit val fooWrites = Json.writes[Foo]
implicit val fooReads = Json.reads[Foo]
// other vals that depend on Foo
}
When I compile, I get an error like:
[error] /file/path/JsonFormat.scala:68:41: unreachable code
[error] implicit val fooWrites = Json.writes[Foo]
[error] ^
[error] one error found
I'm pretty new to scala and I understand an "unreachable code" error in the context of pattern matching, but I can't figure this one out.
I'm using play 2.8.

This may not be the exact solution to the answer but possible advice to change your approach.
First, if you add your own apply() method in your class's companion object this error does happen. Check that.
Second, the best practice seems to be that you would put an implicit converter within the companion object of the class per class and I'd go ahead and implicit the formatter so both conversion directions are supported.
case class SomeClass(someString: String)
object SomeClass {
implicit val jsonFormatter: OFormat[SomeClass] = Json.format[SomeClass]
}
If you approach your JSON implicit converters this way, anywhere you use your DTOs will automatically get the implicit converter anywhere you use that class in both in and out directions.
Other place to assemble "shared" implicits is Package Object. I keep, for example, an ISO DateTime string <-> Date converter there.

Related

circe encoding putting :: when a list of case class from trait is not sealed

Hello everyone I am facing a problem with the circe library to translate between json and at scala case class any help will be highly appreciate.
in the past i have an ADT like this.
sealed trait Sons
case class Son1(name: String, belongings: List[String]) extends Sons
case class Son2(lastName: String, belongings: List[String]) extends Sons
and have no problems whatsoever but now because of the design the file in witch this trait is, is costly to change we have to remove the sealed from the trait so now we have this (with the sons in different files/libraries)
trait Sons
case class Son1(name: String, belongings: List[String]) extends Sons
case class Son2(lastName: String, belongings: List[String]) extends Sons
when trying to convert a list of sons from Scala to json the library puts :: before the list generating a problem as can be seen in this example.
object Test extends App{
implicit val encoderSon1: Encoder[Son1]=deriveEncoder[Son1]
implicit val decoderSon1: Decoder[Son1]=deriveDecoder[Son1]
implicit val encoderSon2: Encoder[Son2]=deriveEncoder[Son2]
implicit val decoderSon2: Decoder[Son2]=deriveDecoder[Son2]
implicit val encoderSon: Encoder[Sons] = Encoder.instance {
case son1: Son1 => son1.asJson
case son2: Son2 => son2.asJson
}
implicit val DecoderSon: Decoder[Sons] =
List[Decoder[Sons]](
Decoder[Son1].widen,
Decoder[Son2].widen
).reduceLeft(_ or _)
implicit val encoderSonList: Encoder[List[Sons]] = deriveEncoder
implicit val DecoderSonList: Decoder[List[Sons]] = deriveDecoder
val sonsList: List[Sons] = List(Son1("James",List()),Son2("Mike",List()))
println(s"1->${sonsList}")
println(s"2->${sonsList.asJson.noSpaces}")
val andBack=decode[List[Sons]](sonsList.asJson.noSpaces).fold(fa=>fa.getMessage,fb=>fb.toString())
println(s"3->${andBack}")
}
the prints are printint
1->List(Son1(James,List()), Son2(Mike,List()))
2->{"::":[{"name":"James","belongings":[]},{"lastName":"Mike","belongings":[]}]}
3->Attempt to decode value on failed cursor: DownField(head),DownField(::)
the problem is of course i do not want the list to be put in a field called :: when converting to JSON.
thank you for any help possible :D
Don't use semi auto for List - semiauto uses slightly different mechanism than other derivations to e.g. avoid issues like:
implicit val x: X = implicitly[X] // uses val x, so we have cyclic dependency = error in runtime
For that reason when you are using semiauto here, List instances from Encoder and Decoder are ignored, and instead macro generates code for List ADT - that is case class :: and case object Nil.
If you remove
implicit val encoderSonList: Encoder[List[Sons]] = deriveEncoder
implicit val DecoderSonList: Decoder[List[Sons]] = deriveDecoder
it will work again.

How to define format for both Y and List[X] in Play JSON when X extends from Y and Y is trait?

I can't convert list in specific case: when type is extends from trait.
When I can convert:
import play.api.libs.functional.syntax._
import play.api.libs.json._
sealed trait Item
case class Id(id: Long) extends Item
case class MyList(list: List[Id])
object MyFormat {
implicit lazy val idFormat = Json.format[Id]
implicit lazy val myListFormat = Json.format[MyList]
}
When I can not convert:
sealed trait Item
case class Id(id: Long) extends Item
case class MyList(list: List[Id])
object MyFormat {
implicit lazy val itemFormat = new Format[Item] {
override def writes(o: Item): JsValue = o match {
case i: Id => idFormat.writes(i)
}
override def reads(json: JsValue): JsResult[Item] = {
idFormat.reads(json)
}
}
implicit lazy val idFormat = Json.format[Id]
implicit lazy val myListFormat = Json.format[MyList]
}
Error:
Error:(33, 49) No instance of play.api.libs.json.Format is available for scala.collection.immutable.List[Main2.Id] in the implicit scope (Hint: if declared in the same file, make sure it's declared before)
implicit lazy val myListFormat = Json.format[MyList]
Why I can't format in 2nd case?
If I add formatter for list:
implicit lazy val idsFormat = Json.format[List[Id]]
then I got Error:(33, 46) No instance of Reads is available for scala.collection.immutable.Nil in the implicit scope (Hint: if declared in the same file, make sure it's declared before)
implicit lazy val idsFormat = Json.format[List[Id]]
PS:
The only one solution than I found:
Define custom format for List[Id]
When read or write, use format for Id
When read, use
def flatten[T](xs: Seq[JsResult[T]]): JsResult[List[T]] = {
val (ss: Seq[JsSuccess[T]], fs: Seq[JsError]) = xs.partition(_.isSuccess)
if (fs.isEmpty) JsSuccess(ss.map(_.get).toList) else fs.head
}
If play JSON features automatic/semiautomatic codec instances derivation, then it will use implicit to enable such a mechanism. It means that codecs for complex things should be introduced after their components.
In your case, it seems like play JSON tries to derive codec for List as for case class ,i. e. as for List(a1, List(a2, ..., List(an, Nil))) and when it hits Nil, it doesn't know how to derive codec for that.
I believe you want your list encoded not like a chain of folded objects but as JSON array.
Then you should search play sources for default List[T] codec and try to use it by specializing it for Id.
General tool for debugging missing implicits is compiler option "-Xlog-implicits". It will log all failed implicit searches to console, and it is possible to figure out what's missing by these messages.
It is also strongly advised to know how implicit works before working with libraries that use this feautre extensively.
And last, but not least:
Have you ever tried using circe? It features automatic and semi-automatic JSON derivation for families of sealed traits and standard scala classes. It even has integration with play framework. Circe derivation removes the most headache of writing codec code, but requires strong knowledge of implicit precedence to work properly. The way it works described here and here.
You can also try to create your own derivation for play-json if there's no adequate standard one with morphling.

Scala: Imported scala object with implicits not working for providing Read or Write format (play json)

I have some scala code that requires the use of implicits for serializing and deserializing json.
We previously had something that worked by putting these implicit statements (simplified with dummies):
(in some class SomeClass1)
implicit val some1format = Json.format[SomeItem1]
implicit val some2format = Json.format[SomeItem2]
...
All as class-level variables. Any method within the class was then able to convert from Json just fine.
However, we are trying to move the implicit definitions of these formats to a separate object.
So we created an object (for example: SomeFormatters), which only contains these implicits:
object SomeFormatters {
implicit val some1format = Json.format[SomeItem1]
implicit val some2format = Json.format[SomeItem2]
}
When I try to import this object into SomeClass1, I get a compilation error saying that no deserializer was found for SomeItem1 or SomeItem2, even though I am importing SomeFormatters. (The IDE says the import of SomeFormatters is unused though, so I already knew something was off.)
What's the proper way to get SomeClass1 to know about the implicit definitions in SomeFormatters?
The issue was that there were no type annotations for implicit values -
Instead of:
implicit val some1format = Json.format[SomeItem1]
I needed to put:
implicit val some1format: Format[SomeItem1] = Json.format[SomeItem1]

How to setup implicit json convertion for spray+akka actor

I'm Java developer and pretty new to scala.
I'm implementing some rest API that use spray and akka
The API should expose some kind of user CRUD. I'll use only create user in this question...
trait DefaultJsonFormats extends DefaultJsonProtocol with SprayJsonSupport with MetaMarshallers {}
class RegistrationService(registration: ActorRef)
(implicit executionContext: ExecutionContext)
extends Directives with DefaultJsonFormats {
implicit val timeout = Timeout(2.seconds)
implicit val userFormat = jsonFormat3(User)
implicit val registerFormat = jsonFormat1(Register)
implicit val registeredFormat = jsonFormat1(Registered)
val route =
path("register") {
post { handleWith { ru: Register => (registration ? ru).mapTo[Registered] } }
}
//------ Actor
object RegistrationActor {
case class User(id:String, name:String)
case class Register(user: User)
case class Registered(status: String)
case object NotRegistered
}
class RegistrationActor(implDef: String) extends Actor {
def receive: Receive = {
case Register(user)=>
val status=// create user real code with return status
sender ! new Registered(status)
} }
In this approach the json serialization and desiarelization is pretty annoying. For every object I need to deal with API I must define the appropriate format
implicit val userFormat = jsonFormat3(User)
implicit val registerFormat = jsonFormat1(Register)
implicit val registeredFormat = jsonFormat1(Registered)
I would like to avoid such definition and use some general json converter and return a pojo objects, so the conversion will happen under-the-hood
The question is how can I change this code to use by default Gson/Jackson/Spray default converter and avoid definition of the implicit ... jsonFormats?
For every object I need to deal with API I must define the appropriate format
It is normal to do this once, in a "JsonProtocol" class and import that where needed, rather than defining new formats each time:
import MyJsonProtocol._
val route =
path("register") {
post { handleWith { ru: Register => (registration ? ru).mapTo[Registered] } }
how can I change this code to use by default Gson/Jackson/Spray default converter and avoid definition of the implicit ... jsonFormats?
You would need to declare an implicit marshaller from Registered to HttpResponse (or an intermediate value like String) which was backed by Jackson instead of spray-json, then import that marshaller instead of SprayJsonSupport.
Have a look at the implementation of SprayJsonSupport to see how to do this. It's fairly straightforward, if you're comfortable with implicit conversions.
You can also see how this is done in Json4sSupport in Spray -- that trait implements a Marshaller[T, String] for ALL types T. Then, at runtime, the Json4s library will try to serialize the object to JSON.
In this approach the json serialization and desiarelization is pretty annoying
There are two main advantages of spray-jsons approach over Jackson's:
There is no reflection, so it is faster at runtime
This is no runtime determining of JSON formats, so any issues are caught at compile-time

Play 2.1 Scala JSON parsing harder than Jerkson?

With Jerkson, I was able to parse a String containing a JSON array, like this:
com.codahale.jerkson.Json.parse[Array[Credentials]](contents)
where contents was a String containing the following:
[{"awsAccountName":"mslinn","accessKey":"blahblah","secretKey":"blahblah"}]
... and I would get the array of Credentials.
(Brief diversion) I tried to do something similar using the new JSON parser for Play 2.1 and Scala using different data. For a simple parse, the following works fine. A case class (S3File) defines the unapply method necessary for this to work:
case class S3File(accountName: String,
bucketName: String,
endpoint: String = ".s3.amazonaws.com")
implicit val s3FileFormat = Json.format[S3File]
val jsValue = Json.parse(stringContainingJson)
Json.fromJson(jsValue).get
Let's reconsider the original string called contents containing JSON. As with all collections, an array of objects has no unapply method. That means the technique I showed in the the diversion above won't work. I tried to create a throwaway case class for this purpose:
case class ArrayCreds(payload: Array[Credentials])
implicit val credsFormat = Json.format[ArrayCreds]
val jsValue = Json.parse(contents)
val credArray = Json.fromJson(jsValue).get.payload
... unfortunately, this fails:
No unapply function found
[error] implicit val credsFormat = Json.format[ArrayCreds]
[error] ^
[error]
/blah.scala:177: diverging implicit expansion for type play.api.libs.json.Reads[T]
[error] starting with method ArrayReads in trait DefaultReads
[error] val credArray = Json.fromJson(jsValue).get
[error] ^
Is there a simple way of parsing an array of JSON using Play 2.1's new JSON parser? I expect the throwaway case class is the wrong approach, and the implicit will need to be instead:
implicit val credsFormat = Json.format[Credentials]
But I don't understand how to write the rest of the deserialization in a simple manner. All of the code examples I have seen are rather verbose, which seems contrary to the spirit of Scala. The ideal incantation would be as simple as Jerkson's incantation.
Thanks,
Mike
I think this is what you're looking for:
scala> import play.api.libs.json._
import play.api.libs.json._
scala> case class Credentials(awsAccountName: String, accessKey: String, secretKey: String)
defined class Credentials
scala> implicit val credentialsFmt = Json.format[Credentials]
credentialsFmt: play.api.libs.json.OFormat[Credentials] = play.api.libs.json.OFormat$$anon$1#1da9be95
scala> val js = """[{"awsAccountName":"mslinn","accessKey":"blahblah","secretKey":"blahblah"}]"""
js: String = [{"awsAccountName":"mslinn","accessKey":"blahblah","secretKey":"blahblah"}]
scala> Json.fromJson[Seq[Credentials]](Json.parse(js))
res3: play.api.libs.json.JsResult[Seq[Credentials]] = JsSuccess(List(Credentials(mslinn,blahblah,blahblah)),)
HTH,
Julien