Scala class type and common methods

I am trying to write a general extractor to parse a Json POST body using spray and json spray.

However, I'm struggling to get it to work with more than one model. Here's the case statement in the service object:

import MyJsonProtocol._ ... def receive = { case Post (Routes.person.post, p: Person) => sender ! Ok(Actions.person.post(p)) case Get (Routes.foo.forId(x)) => sender ! Ok(x) case _ => sender ! Ok("No handler") } 

And here is the extractor I wrote (this works as long as there is only JsonReader for one model in the case statement):

 //NB. Json.parse returns an Option[T] object Post extends Request { def unapply[T:JsonReader](req: HttpRequest): Option[(String, T)] = req match { case HttpRequest(POST, url, _, HttpBody(_, body), _) => Json.parse[T](body.asString).map((url, _)) case _ => None } } 

However, as soon as I add a new model (and its associated JsonReader), the code no longer compiles with this error:

 ambiguous implicit values: [error] both value personFormat in object Json of type => spray.json.RootJsonFormat[com.rsslldnphy.foam.models.Person] [error] and value animalFormat in object Json of type => spray.json.RootJsonFormat[com.rsslldnphy.foam.models.Animal] [error] match expected type spray.json.JsonReader[T] [error] case Post (Routes.person.post, p: Person) => sender ! Ok(Actions.person.post(p)) 

The fact that the common JsonReaders types are different seems to be lost. Is this an erasure of this type? Is there any way around this to get what I want?

Here's the full, compiling project code so far with a comment in ExampleService that explains what causes it to break: github.com/rsslldnphy/foam , your help is appreciated, thanks.

Or if what I want is currently not possible, can anyone suggest an alternative approach?

+4
source share
1 answer

You need to provide explicit compiler instructions to do this work. As you can see below, the compiler cannot determine what T. is. The compiler should be able to dynamically look at Json from the request and from this imply a type (of which we can only dream of executing it;))

 def unapply[T:JsonReader](req: HttpRequest): Option[(String, T)] = (...) Json.parse[T] (...) 

This means that to do this, you need to explicitly annotate the message, as shown below:

 import MyJsonProtocol._ ... def receive = { case Post[Person] (Routes.person.post, p: Person) => sender ! Ok(Actions.person.post(p)) case Get (Routes.foo.forId(x)) => sender ! Ok(x) case _ => sender ! Ok("No handler") } 

and change the definition to this

 case class Post[T: JsonReader] extends Request { def unapply(req: HttpRequest): Option[(String, T)] = req match { case HttpRequest(POST, url, _, HttpBody(_, body), _) => Json.parse[T](body.asString).map((url, _)) case _ => None } } 
+2
source

Source: https://habr.com/ru/post/1445763/


All Articles