Implicit FromRequestUnmarsharell not found - scala

I am trying to use my domain objects as a request/response body parameters. I am using spray-routing and as[T] to unmarshall object. But constantly I'm getting could not find implicit value for parameter um: spray.httpx.unmarshalling.FromRequestUnmarshaller. Eventhough I've added implicit unmarshaller manually to companion object I'm getting same error. I have no idea what is wrong. This JSON serializer/deserializer for Event I've written because I need to serialize joda DateTime object.
package services
import spray.routing.HttpService
import org.joda.time.DateTime
import org.joda.time.format.{DateTimeFormatter, ISODateTimeFormat}
import spray.httpx.unmarshalling.FromRequestUnmarshaller
import spray.json._
import services.EventsService.Event
import spray.httpx.SprayJsonSupport
trait EventsService extends HttpService {
val eventsRoute =
path("/events") {
get {
import EventsService._
entity(as[Event]) { event =>
complete(s"${event.toString}")
}
}
}
}
object EventsService extends DefaultJsonProtocol with SprayJsonSupport{
trait DateFormatter {
val formatter: DateTimeFormatter
}
trait DateParser {
val parser: DateTimeFormatter
}
implicit object EventFormatter extends RootJsonFormat[Event] with DateFormatter with DateParser {
def read(json: JsValue): Event = json match {
case obj: JsObject =>
val name = obj.fields.get("name").map(_.asInstanceOf[JsString].value).
getOrElse(deserializationError("field name not present"))
val city = obj.fields.get("city").map(_.asInstanceOf[JsString].value).
getOrElse(deserializationError("field city not present"))
val starts = obj.fields.get("starts").map(x => parser.parseDateTime(x.asInstanceOf[JsString].value)).
getOrElse(deserializationError("field starts not present"))
val ends = obj.fields.get("ends").map(x => parser.parseDateTime(x.asInstanceOf[JsString].value)).
getOrElse(deserializationError("ends field not present"))
Event(name, city, starts, ends)
case _ => deserializationError("wrong object to deserialize")
}
def write(e: Event): JsValue =
JsObject(Map(
"name" -> JsString(e.name),
"city" -> JsString(e.city),
"starts" -> JsString(formatter.print(e.starts)),
"ends" -> JsString(formatter.print(e.ends))
))
val formatter = ISODateTimeFormat.dateTimeNoMillis()
val parser = ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed()
}
case class Event(name: String, city: String, starts: DateTime, ends: DateTime)
}

Ok, I've figured that out. The order of structures is wrong. First should be companion object and second trait with route. I don't know why, yet but it works now.

Related

Implicit JsonWriter for trait not working

I have class as below
trait RiskCheckStatusCode {
def code: String
def isSuccess: Boolean
}
object RiskCheckStatusCode {
val SUCCESS = SuccessRiskCheckStatusCode("1.1.1")
val FAIL = FailRiskCheckStatusCode("2.2.2")
case class SuccessRiskCheckStatusCode(code: String) extends RiskCheckStatusCode {
override def isSuccess = true
}
object SuccessRiskCheckStatusCode {
import spray.json.DefaultJsonProtocol._
implicit val formatter = jsonFormat1(SuccessRiskCheckStatusCode.apply)
}
case class FailRiskCheckStatusCode(code: String) extends RiskCheckStatusCode {
override def isSuccess = false
}
object FailRiskCheckStatusCode {
import spray.json.DefaultJsonProtocol._
implicit val formatter = jsonFormat1(FailRiskCheckStatusCode.apply)
}
}
and now I would like to convert the list of RiskCheckStatusCode to json
object Main extends App{
import spray.json._
import spray.json.DefaultJsonProtocol._
val l = List(RiskCheckStatusCode.SUCCESS, RiskCheckStatusCode.FAIL)
implicit object RiskCheckStatusCodeJsonFormat extends JsonWriter[RiskCheckStatusCode] {
override def write(obj: RiskCheckStatusCode): JsValue = obj match {
case obj: SuccessRiskCheckStatusCode => obj.toJson
case obj: FailRiskCheckStatusCode => obj.toJson
}
}
def json[T](list: T)(implicit formatter: JsonWriter[T]) = {
print(list.toJson)
}
json(l)
}
but the json method can not find jsonWriter[RiskCheckStatusCode].
Can you explain why? Maybe should I do it differently for trait type?
Edit:
It works for
val l: RiskCheckStatusCode = RiskCheckStatusCode.SUCCESS
so the problem is with List[RiskCheckStatusCode] because I have a formatter for RiskCheckStatusCode, not for List[RiskCheckStatusCode]. I tried import DefaultJsonProtocol but it still does not work.
import spray.json.DefaultJsonProtocol._
I have to change the definitions? From
implicit object RiskCheckStatusCodeJsonFormat extends JsonWriter[RiskCheckStatusCode]
to
implicit object RiskCheckStatusCodeJsonFormat extends JsonWriter[List[RiskCheckStatusCode]]
error:
Error:(28, 7) Cannot find JsonWriter or JsonFormat type class for List[com.example.status.RiskCheckStatusCode]
json(l)
Error:(28, 7) not enough arguments for method json: (implicit formatter: spray.json.JsonWriter[List[com.example.status.RiskCheckStatusCode]])Unit.
Unspecified value parameter formatter.
json(l)
Your code is fine you are just not having toJson in your scope (it is located in the package object of spray.json).
Add it and your code should compile:
object Main extends App with DefaultJsonProtocol {
import spray.json._
// ...
}
Furthermore spray has some issues to lift JsonWriter through derived formats (see this for details).
You can switch to JsonFormat instead:
implicit object RiskCheckStatusCodeJsonFormat extends JsonFormat[RiskCheckStatusCode] {
override def write(obj: RiskCheckStatusCode): JsValue = obj match {
case obj: SuccessRiskCheckStatusCode => obj.toJson
case obj: FailRiskCheckStatusCode => obj.toJson
}
override def read(json: JsValue): RiskCheckStatusCode = ???
}
In addition, to cleanup the type of your List change the definition of RiskCheckStatusCode to (this explains more details):
sealed trait RiskCheckStatusCode extends Serializable with Product

How to create generic JSON serializer/deserializer in Scala?

I wanted to serialize and deserialize some case classes and realized I was repeating code. Unfortunately I cannot figure out a way to keep things DRY. Hoping someone can provide some assistance. Below I will provide a sample problem that is not DRY.
Sample Problem
import org.json4s.jackson.Serialization
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import org.json4s.JsonAST.JString
import org.json4s.{CustomSerializer, DefaultFormats}
case class Bar(bar: String, date: ZonedDateTime)
case class Foo(foo: String)
trait JsonParser {
private case object ZDTSerializer extends CustomSerializer[ZonedDateTime](_ => (
{ case JString(s) => ZonedDateTime.parse(s) },
{ case zdt: ZonedDateTime => JString(zdt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"))) }
))
implicit val formats = DefaultFormats + ZDTSerializer
}
object BarParser extends JsonParser {
def deserialize(jsonBar: String): Bar = {
Serialization.read[Bar](jsonBar)
}
def serialize(bar: Bar): String = {
Serialization.write[Bar](bar)
}
}
object FooParser extends JsonParser {
def deserialize(jsonFoo: String): Foo = {
Serialization.read[Foo](jsonFoo)
}
def serialize(foo: Foo): String = {
Serialization.write[Foo](foo)
}
}
object Main {
def main(args: Array[String]): Unit = {
val foo = Foo("foo")
println(FooParser.serialize(foo)) // {"foo":"foo"}
println(FooParser.deserialize(FooParser.serialize(foo))) // Foo(foo)
}
}
Above it is clear that the logic to serialize and deserialize is repeated. This is one of the things I've tried (which doesn't compile).
Attempt to Solve
case class Bar(product: String, date: ZonedDateTime)
case class Foo(title: String)
abstract class GenericJsonParser[T] {
private case object ZDTSerializer extends CustomSerializer[ZonedDateTime](_ => (
{ case JString(s) => ZonedDateTime.parse(s) },
{ case zdt: ZonedDateTime => JString(zdt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"))) }
))
implicit val formats = DefaultFormats + ZDTSerializer
def deserialize(json: String): T = {
Serialization.read[T](json) // No Manifest available for T
}
def serialize(thing: T): String = {
Serialization.write[T](thing) // type arguments [A] conform to the bounds of none of the overloaded alternatives ...
}
}
object BarJsonParser extends GenericJsonParser[Bar]
object FooParser extends GenericJsonParser[Foo]
Any guidance would be appreciated.
I think you can use Json.format[ACaseClass], for example:
import play.api.libs.json.{Format, Json}
case class ACaseClass(value: String, anotherValue: Int)
implicit val formatACaseClass = Json.format[ACaseClass]
I guess for Seralization.read and write you still have to pass an implicit value, jvm need must know how to read/write your object/

How to read string as enum class in Play Scala?

In Scala with Play and Slick, I've implemented enum Country as a case class, and would like to read/write it to JSON as a string. This is the complete code:
package models.enums
import play.api.libs.json._
import slick.lifted.MappedTo
case class Country(id: String) extends MappedTo[String] {
override def value: String = id
}
object Country {
val France = Country("FR")
val Germany = Country("DE")
implicit val writes = Writes[Country](
(site: Country) => JsString(site.value)
)
// this line I need help with
implicit val reads = Json.reads[Country]
}
The Country enum is used by other models, e.g.
{
"name": "Robo"
"country": "DE"
}
The code above writes the enum as a plain String which is what I want, but I can't figure out how to implement the implicit read part. Currently the read would only work if the JSON is like:
{
"name": "Robo"
"country": {
"id": "DE"
}
}
I'm sure the answer is simple, just can't figure out the correct syntax.
import play.api.libs.json._
import play.api.libs.json.Reads._
implicit val reads = new Reads[Country] {
override def reads(json: JsValue): JsResult[Country] = for {
id <- (json \ "country").validate[String]
} yield Country(id)
}
(json \ "country").validate[String] returns a JsResult[String] which is then mapped (via yield) to a JsResult[Country]
or
import play.api.libs.json._
import play.api.libs.json.Reads._
implicit val reads = new Reads[Country] {
override def reads(json: JsValue): JsResult[Country] =
(json \ "country").validate[String].map(Country(_))
or
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.functional.syntax._
implicit val reads: Reads[Country] = (__ \ "country").reads[String].map(Country(_))
EDIT:
Regarding your comment on validation, I'd just add that to your case class, not the json parser:
case class Country(id: String) extends MappedTo[String] {
private val validIds = Set(France, Germany).map(_.id)
require(validIds contains id, s"id must be one of $validIds")
override def value: String = id
}
the trick is that statements you put in the body of your class will be part of the constructor. The require call there will throw an exception if anyone tries to create a Country with an ID which is not in your list of allowed IDs.
I recommend using sealed class. If the selector of a pattern match is an instance of a sealed class, the compilation of pattern matching can emit warnings which diagnose that a given set of patterns is not exhaustive, i.e. that there is a possibility of a MatchError being raised at run-time.
Example from my project:
import com.pellucid.sealerate
import play.api.libs.json._
sealed abstract class TokenKind(val value: String)
object TokenKind {
case object PasswordReset extends TokenKind("passwordReset")
case object AccountConfirmation extends TokenKind("accountConfirmation")
def values: Set[TokenKind] = sealerate.values[TokenKind]
def apply(value: String): TokenKind = values.find(_.value == value).getOrElse(throw new RuntimeException(s"Can't construct TokenKind from: $value"))
implicit def tokenKindWrites = new Writes[TokenKind] {
override def writes(o: TokenKind): JsValue = JsString(o.value)
}
implicit def tokenKindReads = new Reads[TokenKind] {
override def reads(json: JsValue): JsResult[TokenKind] = json match {
case JsString(string) => JsSuccess(TokenKind(string))
case _ => JsError("validate.error.invalidTokenKind")
}
}
}
I had a similar problem that solved this way:
object VoteType extends Enumeration {
val Up, Down = Value
implicit val voteTypeMappeer = MappedColumnType.base[VoteType.Value, String](_.toString, VoteType.withName)
}

Serialize and Deserialize scala enumerations or case objects using json4s

Suppose I have an enumeration or sealed group of case objects as follows:
sealed abstract class Status
case object Complete extends Status
case object Failed extends Status
case object Pending extends Status
case object Unknown extends Status
or
object Status extends Enumeration {
val Complete, Failed, Pending, Unknown = Value
}
What is the easiest way to create json formats for these so that I can very easily (programmatically) generate json formats for use in a custom JsonFormat factory method, such as the following, which works for all normal case classes, strings, collections, etc., but produces {} or {"name": null} for the above two types of enumerations?:
import org.json4s.DefaultFormats
import org.json4s.jackson.JsonMethods.parse
import org.json4s.jackson.Serialization
import org.json4s.jvalue2extractable
import org.json4s.string2JsonInput
trait JsonFormat[T] {
def read(json: String): T
def write(t: T): String
}
object JsonFormat {
implicit lazy val formats = DefaultFormats
def create[T <: AnyRef: Manifest](): JsonFormat[T] = new JsonFormat[T] {
def read(json: String): T = parse(json).extract[T]
def write(t: T): String = Serialization.write(t)
}
}
We've used org.json4s.ext.EnumNameSerializer to serialize enumerations:
import org.json4s._
import org.json4s.ext.EnumNameSerializer
class DoesSomething {
implicit lazy val formats = DefaultFormats + new EnumNameSerializer(Status)
...stuff requiring serialization or deserialization...
}
In practice we have mixin trait that adds the implicit format and defines all of our custom serializer/desrializers:
trait OurFormaters extends Json4sJacksonSupport {
implicit lazy val json4sJacksonFormats:Formats = DefaultFormats +
UuidSerializer +
new EnumNameSerializer(Status) +
...
}
object UuidSerializer extends CustomSerializer[UUID](format =>
(
{
case JString(s) => UUID.fromString(s)
case JNull => null
},
{
case x: UUID => JString(x.toString)
}
)
)

(Un)marshall JSON with named root for Ember Data using Scala case class on Spray

I am writing a RESTful interface and I would like to marshall and unmarshall JSON ready for Ember Data.
The wrinkle is that Ember Data wants the entity name and the two libraries I've tried, spray-json and json4s, don't appear to do this easily.
Desired Ember Data format
{
"coursePhoto": {
"photoId": 1
}
}
Current default format:
{"photoId":15}
This should come from a case class:
case class CoursePhoto(photoId: Long)
I did get it running with the following custom code:
object PtolemyJsonProtocol extends DefaultJsonProtocol {
implicit object CoursePhotoFormat extends RootJsonFormat[CoursePhoto] {
def write(cp: CoursePhoto) =
JsObject("CoursePhoto" -> JsObject("photoId" -> JsNumber(cp.photoId)))
def read(value: JsValue) = value match {
case coursePhotoJsObject: JsObject => {
CoursePhoto(coursePhotoJsObject.getFields("CoursePhoto")(0).asJsObject
.getFields("photos")(0).asInstanceOf[JsArray].elements(0)
.asInstanceOf[JsNumber].value.toLong)
}
case _ => deserializationError("CoursePhoto expected")
}
}
That code seems horrifyingly fragile and ugly with all the asInstanceOf and (0).
Given that I'm writing in Spray with Scala what's the nice way to get named root JSON output? I am quite happy to do this with any JSON library that integrates nicely with Spray and is reasonably performant.
Is the following solving your problem?
scala> import spray.json._
import spray.json._
scala> import DefaultJsonProtocol._
import DefaultJsonProtocol._
scala> case class CoursePhoto(photoId: Long)
defined class CoursePhoto
scala> case class CoursePhotoEmber(coursePhoto: CoursePhoto)
defined class CoursePhotoEmber
scala> implicit val jsonFormatCoursePhoto = jsonFormat1(CoursePhoto)
jsonFormatCoursePhoto: spray.json.RootJsonFormat[CoursePhoto] = spray.json.ProductFormatsInstances$$anon$1#6f5d66b6
scala> implicit val jsonFormatCoursePhotoEmber = jsonFormat1(CoursePhotoEmber)
jsonFormatCoursePhotoEmber: spray.json.RootJsonFormat[CoursePhotoEmber] = spray.json.ProductFormatsInstances$$anon$1#401a0d22
scala> """{ "coursePhoto": { "photoId": 1 } }""".parseJson.convertTo[CoursePhotoEmber]
res0: CoursePhotoEmber = CoursePhotoEmber(CoursePhoto(1))
scala> res0.toJson
res1: spray.json.JsValue = {"coursePhoto":{"photoId":1}}
This problem made me wonder if it were possible to do it in a re-usable way. I believe I've figured out a reasonable way to do this for multiple types.
object PtolemyJsonProtocol extends DefaultJsonProtocol {
implicit val CoursePhotoFormat = new NamedRootFormat("CoursePhoto", jsonFormat1(CoursePhoto))
}
import PtolemyJsonProtocol._
class NamedRootFormat[T](rootName: String, delegate: RootJsonFormat[T]) extends RootJsonFormat[T] {
def write(obj: T): JsValue = {
JsObject((rootName, delegate.write(obj)))
}
def read(json: JsValue): T = json match {
case parentObject: JsObject => {
delegate.read(parentObject.getFields(rootName).head)
}
case _ => deserializationError("CoursePhoto expected")
}
}