Map JSON to case class for scalatest - scala

I am trying to write test cases using scala test for the components.
My application takes JSON through the REST endpoints map it to the case class via Akka http entity mapping, Now while writing the test case all I want to do is Map my json to case class and utilize case class object without using the REST interface.
case class Sample(
projectName : String,
modelName: String,
field2 : String,
field3: FieldConf,
field4: String,
field5: String,
field6 : Seq[field7]
)
//FieldConf is another case class
how do I map my JSON string to this case class ?

When you configured your akka-http to unmarshal JSON to your case class, you had to configure some JSON library as the marshaller.
You can use the same library directly to parse and decode your case class.
For example, here's how you would do it using Circe:
import io.circe.parser.decode
decode[MyCaseClass]("{...}")

Related

play-json: mapping a json string to nested case class

I have a usecase where incoming json string doesn't have a structure similar to the case class.
I have following case classes:
case class Parent(children: Seq[Child])
case class Child(name: Option[String], age: Option[Int])
User inputs in Parent field as:
John:20, Peter:12
Incoming json is as:
{"parent":{"parent":"John:20, Peter:12"},....}
Is it possible I write json formatter to map this to the Parent case class with nested Child list, using play framework json API?

Scala generics usage for methods + json4s parsing

I am not sure if this is achievable and I have a very basic understanding of how generics work in scala. But I was wondering if this is possible.
Say I have a method:
case class Person(id:String,name:String)
case class Student(id:String,name:String, class:String)
def convertToJson[A](fileName:String):{
//read file
parse[A]
}
Is it possible to write this generic method which would parse the json based on the type of class I send when I call the convertToJson method?
Something like:
convertToJson[Student](fileName)
convertToJson[Person](fileName)
BTW the above code gives me a :
No Manifest available for A. error.
Using json4s for parsing.
Any help is appreciated.
This will convert a JSON string to a case class
import org.json4s._
import org.json4s.jackson.JsonMethods._
def convertToJson[T](json: String)(implicit fmt: Formats = DefaultFormats, mf: Manifest[T]): T =
Extraction.extract(parse(json))
Once this is defined you can parse appropriate strings to the required type:
case class Person(id: String, name: String)
case class Student(id: String, name: String, `class`: String)
val person = convertToJson[Person]("""{"name":"Jane","id":45}""")
val student = convertToJson[Student]("""{"name":"John","id":63, "class": "101"}""")
Note that this will ignore JSON data that does not match fields in the case class. If a field is optional in the JSON, make it an Option in the case class and you will get None if the field is not there.

Same case class different validation

What I'm trying to do in Scala 2.11 and akka is have one case class but two different validations based on which route is being hit.
For example, let's consider the case class below
case class User(_id: String, name: String, age: Int, address: String)
Now while the /create route is hit, I don't need _id but I need all the other fields.
But while /update route is hit, I need the _id and the fields that are to be updated (which could be one or all three)
Only declaring Option doesn't serve the purpose because then my /create route goes for a toss.
Even extending case classes doesn't really work seamlessly (there's too much code duplicity).
I would love if something like this was possible
case class User(_id: String, name: String, age: Int, address: String)
case class SaveUser() extends User {
require(name.nonEmpty)
require(age.nonEmpty)
require(address.nonEmpty)
}
case class UpdateUser() extends User {
require(_id.nonEmpty)
}
Is there an elegant solution to this? Or do I have to create two identical case classes?
My suggestion would be to encode different case classes for different requirements, but if you insist you must share code between these two cases a possible solution would be to parameterize the case class
case class User[Id[_], Param[_]](_id: Id[String], name: Param[String], age: Param[Int], address: Param[String])
Then you define an alias for the Identity type constructor and your two uses of the case class
type Identity[T] = T
type SaveUser = User[Option, Identity]
type UpdateUser = User[Identity, Option]

How to rename nested fields with Json4s

As the title states, I am trying to rename fields on generated json from case classes using Json4s.
If I try to rename fields on simple case classes like:
case class User(name: String, lastName: String)
Following examples that you can find in the documentation of json4s or here How can I rename a field during serialization with Json4s? will work.
But documentation does not mention how to do nested object renames like for example from deviceId to did in this example:
case class User(name: String, lastName: String, details: UserDetails)
case class UserDetails(deviceId: String)
I tried using things like:
FieldSerializer.renameFrom("deviceId", "did")
or
FieldSerializer.renameFrom("details.deviceId", "details.did")
or
parse(message) transformField {
case ("deviceId", value) => ("did", value)
}
or
parse(message) transformField {
case ("details.deviceId", value) => ("details.did", value)
}
And none of them worked, so my question is: Is this nested rename possible on scala4s? If yes, how can I do to for example rename deviceId to did?
For the nested object, you can create FieldSerializer to bind this nested type, like:
import org.json4s._
import org.json4s.FieldSerializer._
import org.json4s.jackson.Serialization.write
val rename = FieldSerializer[UserDetails](renameTo("deviceId", "did")) // bind UserDetails to FieldSerializer
implicit val format: Formats = DefaultFormats + rename
println(write(u))
> {"name":"name","lastName":"lastName","details":{"did":"deviceId"}}

Swagger models, dataType for case class definition

I have the following case class
case class AccountId(value: Long) extends EntityId(value)
And I use it in many DTOs, such as:
case class GetAccount(
#ApiModelProperty(dataType = "long")
id: AccountId,
email: Email
)
But in every dto in which I use AccountId I have to add ApiModelProperty to properly display the model structure in swagger.
Is it possible to annotate only the AccountIt case class definition and avoid the redundant code?