Json4s Jackson read write case class not equal - json

How can this be that a previously serialised and then deserialised case class is not equal:
import org.json4s.DefaultFormats
import org.json4s.jackson.Serialization.{write, read}
implicit val formats: DefaultFormats = DefaultFormats
case class MyCaseTestClass(two: String, num: Int)
read[MyCaseTestClass](write(MyCaseTestClass("bla", 123))) shouldBe MyCaseTestClass("bla", 123)
And running this I get:
MyCaseTestClass(bla,123) was not equal to MyCaseTestClass(bla,123)
ScalaTestFailureLocation: ...
Expected :MyCaseTestClass(bla,123)
Actual :MyCaseTestClass(bla,123)

Ok, after trying around a while I found that defining a case class inside your unit test class that is enriched with FlatSpec with Matchers this causes the issue somehow.
If defining the class outside, e.g. in a separate file / object, this doesn't happen.

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.

Circe asJson not encoding properties from abstract base class

Suppose I have the following abstract base class:
package Models
import reactivemongo.bson.BSONObjectID
abstract class RecordObject {
val _id: String = BSONObjectID.generate().stringify
}
Which is extended by the following concrete case class:
package Models
case class PersonRecord(name: String) extends RecordObject
I then try to get a JSON string using some code like the following:
import io.circe.syntax._
import io.circe.generic.auto._
import org.http4s.circe._
// ...
val person = new PersonRecord(name = "Bob")
println(person._id, person.name) // prints some UUID and "Bob"
println(person.asJso) // {"name": "Bob"} -- what happened to "_id"?
As you can see, the property _id: String inherited from RecordObject is missing. I would expect that the built-in Encoder should function just fine for this use case. Do I really need to build my own?
Let's see what happens in encoder generation. Circe uses shapeless to derive its codecs, so its enough to check what shapeless resolves into to answer your question. So in ammonite:
# abstract class RecordObject {
val _id: String = java.util.UUID.randomUUID.toString
}
defined class RecordObject
# case class PersonRecord(name: String) extends RecordObject
defined class PersonRecord
# import $ivy.`com.chuusai::shapeless:2.3.3`, shapeless._
import $ivy.$ , shapeless._
# Generic[PersonRecord]
res3: Generic[PersonRecord]{type Repr = String :: shapeless.HNil} = ammonite.$sess.cmd3$anon$macro$2$1#1123d461
OK, so its String :: HNil. Fair enough - what shapeless does is extracting all fields available in constructor transforming one way, and putting all fields back through constructor if converting the other.
Basically all typeclass derivation works this way, so you should make it possible to pass _id as constructor:
abstract class RecordObject {
val _id: String
}
case class PersonRecord(
name: String,
_id: String = BSONObjectID.generate().stringify
) extends RecordObject
That would help type class derivation do its work. If you cannot change how PersonRecord looks like... then yes you have to write your own codec. Though I doubt it would be easy as you made _id immutable and impossible to set from outside through a constructor, so it would also be hard to implement using any other way.

How to use nested case classes and spray json implicits

I am trying to convert case classes to json with spray.io json. The code below:
case class Value(amt: Int)
case class Item(name: String, count: Value)
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val itemFormat = jsonFormat2(Item)
}
import MyJsonProtocol._
import spray.json._
val json = Item("mary", Value(2)).toJson
println(json)
gives:
could not find implicit value for evidence parameter of type onextent.bluecase.examples.ex1.ExampleJson2.MyJsonProtocol.JF[Value]
I've tried to define a JsonProtocol for Value as well but get same. Searching stackoverflow I only see this error related to generics, which this is not.
What am I missing? (re-reading about implicits now...)
You need a json format for your Value class as it is part of your Item class. So your object would need to look like this:
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val valueFormat = jsonFormat1(Value)
implicit val itemFormat = jsonFormat2(Item)
}
The answer mentioned by StuartMcvean is correct. However I just want to add a note that the order in which you declare the implicits is important. For example the below declaration will still result in the same failure.
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val itemFormat = jsonFormat2(Item)
implicit val valueFormat = jsonFormat1(Value)
}

Serializing sequences of AnyVal with json4s

I have a problem when trying to serialize sequences of AnyVal using json4s in scala.
Here is a test using FunSuite that reproduces the problem:
import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.jackson.Serialization._
import org.scalatest.{FunSuite, Matchers}
case class MyId(id: String) extends AnyVal
case class MyModel(ids: Seq[MyId])
class AnyValTest extends FunSuite with Matchers {
test("should serialize correctly") {
implicit val formats = DefaultFormats
val model = MyModel(Seq(MyId("1"), MyId("2")))
val text = write(model)
parse(text).extract[MyModel] shouldBe model
}
}
The test fails when trying to extract MyModel from the JValue because it can not find a suitable value for the ids field.
I notice that it AnyVal are working fine when used directly though with something like:
case class AnotherModel(id: MyId)
Then I am able to serialise and deserialise correctly.
I know this question is one year old but I ran into the same issue. Writing what I did in case it helps someone else. You will need a custom serializer.
case class Id(asString: String) extends AnyVal
class NotificationSerializer extends CustomSerializer[Id](format ⇒ (
{case JString(s) => Id(s)},
{case Id(s) => JString(s)}))
Without above serialization, your JSON will look something like
{"ids":[[{"asString":"testId1"},{"asString":"testId2"}]]}
I am not entirely sure why AnyVal case class serialization works fine when it is a part of another case class but not standalone. My best guess is that the behavior is due to the allocation behavior of JVM for array containing value classes. See http://docs.scala-lang.org/overviews/core/value-classes.html for 'when allocation is necessary' section.

Convert polymorphic case classes to json and back

I am trying to use spray-json in scala to recognize the choice between Ec2Provider and OpenstackProvider when converting to Json and back.
I would like to be able to give choices in "Provider", and if those choices don't fit the ones available then it should not validate.
My attempt at this can be seen in the following code:
import spray.json._
import DefaultJsonProtocol._
case class Credentials(username: String, password: String)
abstract class Provider
case class Ec2Provider(endpoint: String,credentials: Credentials) extends Provider
case class OpenstackProvider(credentials: Credentials) extends Provider
case class Infrastructure(name: String, provider: Provider, availableInstanceTypes: List[String])
case class InfrastructuresList(infrastructures: List[Infrastructure])
object Infrastructures extends App with DefaultJsonProtocol {
implicit val credFormat = jsonFormat2(Credentials)
implicit val ec2Provider = jsonFormat2(Ec2Provider)
implicit val novaProvider = jsonFormat1(OpenstackProvider)
implicit val infraFormat = jsonFormat3(Infrastructure)
implicit val infrasFormat = jsonFormat1(InfrastructuresList)
println(
InfrastructuresList(
List(
Infrastructure("test", Ec2Provider("nova", Credentials("user","pass")), List("1", "2"))
)
).toJson
)
}
Unfortunately, it fails because it can not find a formatter for Provider abstract class.
test.scala:19: could not find implicit value for evidence parameter of type Infrastructures.JF[Provider]
Anyone have any solution for this?
What you want to do is not available out of the box (i.e. via something like type hints that allow the deserializer to know what concrete class to instantiate), but it's certainly possible with a little leg work. First, the example, using a simplified version of the code you posted above:
case class Credentials(user:String, password:String)
abstract class Provider
case class Ec2Provider(endpoint:String, creds:Credentials) extends Provider
case class OpenstackProvider(creds:Credentials) extends Provider
case class Infrastructure(name:String, provider:Provider)
object MyJsonProtocol extends DefaultJsonProtocol{
implicit object ProviderJsonFormat extends RootJsonFormat[Provider]{
def write(p:Provider) = p match{
case ec2:Ec2Provider => ec2.toJson
case os:OpenstackProvider => os.toJson
}
def read(value:JsValue) = value match{
case obj:JsObject if (obj.fields.size == 2) => value.convertTo[Ec2Provider]
case obj:JsObject => value.convertTo[OpenstackProvider]
}
}
implicit val credFmt = jsonFormat2(Credentials)
implicit val ec2Fmt = jsonFormat2(Ec2Provider)
implicit val openStackFmt = jsonFormat1(OpenstackProvider)
implicit val infraFmt = jsonFormat2(Infrastructure)
}
object PolyTest {
import MyJsonProtocol._
def main(args: Array[String]) {
val infra = List(
Infrastructure("ec2", Ec2Provider("foo", Credentials("me", "pass"))),
Infrastructure("openstack", OpenstackProvider(Credentials("me2", "pass2")))
)
val json = infra.toJson.toString
val infra2 = JsonParser(json).convertTo[List[Infrastructure]]
println(infra == infra2)
}
}
In order to be able to serialize/deserialize instances of the abstract class Provider, I've created a custom formatter where I am supplying operations for reading and writing Provider instances. All I'm doing in these functions though is checking a simple condition (binary here as there are only 2 impls of Provider) to see what type it is and then delegating to logic to handle that type.
For writing, I just need to know which instance type it is which is easy. Reading is a little trickier though. For reading, I'm checking how many properties the object has and since the two impls have different numbers of props, I can differentiate which is which this way. The check I'm making here is very rudimentary, but it shows the point that if you can look at the Json AST and differentiate the types, you can then pick which one to deserialize to. Your actual check can be as simple or as complicated as you like, as long as it's is deterministic in differentiating the types.