Ok so i am writing implicit conversions for case classes in scala, using SJSON, to send messages to remote actors using the akka framework. One of the case classes looks like this
case class Example(id: String, actr: ActorRef)
How would i go about writing the implicit for this case class.
I have seen that ActorRefs do have a toBinary method but i need to send it toJson
http://doc.akkasource.org/serialization-scala . Explicit [deep] serialization may be required only for stateful actors, when underlying actor instance (under ActorRef / RemoteActorRef) holds some important runtime data. For this case, you should implement the following typeclass for your actor:
/**
* Type class definition for Actor Serialization
*/
trait FromBinary[T <: Actor] {
def fromBinary(bytes: Array[Byte], act: T): T
}
trait ToBinary[T <: Actor] {
def toBinary(t: T): Array[Byte]
}
// client needs to implement Format[] for the respective actor
trait Format[T <: Actor] extends FromBinary[T] with ToBinary[T]
If you want ScalaJSON serialization, instead of the default one, you should use SerializerBasedActorFormat trait
trait SerializerBasedActorFormat[T <: Actor] extends Format[T] {
val serializer: Serializer
def fromBinary(bytes: Array[Byte], act: T) = serializer.fromBinary(bytes, Some(act.self.actorClass)).asInstanceOf[T]
def toBinary(ac: T) = serializer.toBinary(ac)
}
with ScalaJSON serializer.
SJSON library supports serialization of plain Scala objects out-of-box, without an additional configuration (which is enough, in the most cases). If you need to ignore some properties, or define serialization policy of embedded objects, read this.
In your case, you would need something like
#BeanInfo
case class Example(id: String,
#(JSONTypeHint #field)(value = classOf[MyActor])
actr: ActorRef)
implicit object MyActorFormat extends SerializerBasedActorFormat[MyActor] {
val serializer = Serializer.ScalaJSON
}
In general, you don't need to serialize your case classes explicitly, when you're sending messages to remote actors in Akka - Akka itself serializes all data with protobufs before sending over TCP.
Why would you need serialize reference to the actor? If it's just needed to call the sender by the actor that receives the message, you can simply use self.sender, if the message was sent with !, or self.senderFuture, when the messages is sent with !! or !!!. ActorRef (or RemoteActorRef) on itself is just an abstract interface to an actor, used to encapsulate internal actor's implementation and letting externals communicate with the actor only via messages (in contrast to stdlib Actors / much like it's done in Erlang [processes]) and holds very small amount of data that makes sense to serialize and send over wire.
Related
I am looking to provide JSON encoders for the following case class:
import io.circe.generic.extras.Configuration
final case class Hello[T](
source: String,
version: Int = 1,
data: T
)
object Hello {
implicit val configuration: Configuration = Configuration.default.withDefaults
}
I would ordinarily call deriveEncoder[A] in the companion object, but that doesn't work here as there is no reference or Encoder for T available here.
The Hello type will be provided to clients as a library, so I would like to do as much of the boilerplate as possible within this type rather than depend on client code providing the encoder and decoder. Is there an idiomatic solution to this with circe so that clients provide an encoder/decoder for T and this gets used to derive the encoder/decoder for Hello[T]?
Yes, you need to add a context bound requiring an implicit encoder to be present for any type T:
import io.circe.gemeric.semiauto._
final case class Hello[T](
source: String,
version: Int = 1,
data: T
)
object Hello {
implicit def helloEncoder[T: Encoder]: Encoder[Hello[T]] = deriveEncoder
}
Such that when the user creates their own Hello[Foo] type, they'll have to make sure that Foo has its own encoder.
I'm trying to construct a trait and an abstract class to subtype by messages (In an Akka play environment) so I can easily convert them to Json.
What have done so far:
abstract class OutputMessage(val companion: OutputMessageCompanion[OutputMessage]) {
def toJson: JsValue = Json.toJson(this)(companion.fmt)
}
trait OutputMessageCompanion[OT] {
implicit val fmt: OFormat[OT]
}
Problem is, when I'm trying to implement the mentioned interfaces as follows:
case class NotifyTableChange(tableStatus: BizTable) extends OutputMessage(NotifyTableChange)
object NotifyTableChange extends OutputMessageCompanion[NotifyTableChange] {
override implicit val fmt: OFormat[NotifyTableChange] = Json.format[NotifyTableChange]
}
I get this error from Intellij:
Type mismatch, expected: OutputMessageCompanion[OutputMessage], actual: NotifyTableChange.type
I'm kinda new to Scala generics - so help with some explanations would be much appreciated.
P.S I'm open for any more generic solutions than the one mentioned.
The goal is, when getting any subtype of OutputMessage - to easily convert it to Json.
The compiler says that your companion is defined over the OutputMessage as the generic parameter rather than some specific subtype. To work this around you want to use a trick known as F-bound generic. Also I don't like the idea of storing that companion object as a val in each message (after all you don't want it serialized, do you?). Defining it as a def is IMHO much better trade-off. The code would go like this (companions stays the same):
abstract class OutputMessage[M <: OutputMessage[M]]() {
self: M => // required to match Json.toJson signature
protected def companion: OutputMessageCompanion[M]
def toJson: JsValue = Json.toJson(this)(companion.fmt)
}
case class NotifyTableChange(tableStatus: BizTable) extends OutputMessage[NotifyTableChange] {
override protected def companion: OutputMessageCompanion[NotifyTableChange] = NotifyTableChange
}
You may also see standard Scala collections for an implementation of the same approach.
But if all you need the companion for is to encode with JSON format, you can get rid of it like this:
abstract class OutputMessage[M <: OutputMessage[M]]() {
self: M => // required to match Json.toJson signature
implicit protected def fmt: OFormat[M]
def toJson: JsValue = Json.toJson(this)
}
case class NotifyTableChange(tableStatus: BizTable) extends OutputMessage[NotifyTableChange] {
override implicit protected def fmt: OFormat[NotifyTableChange] = Json.format[NotifyTableChange]
}
Obviously is you also want to decode from JSON you still need a companion object anyway.
Answers to the comments
Referring the companion through a def - means that is a "method", thus defined once for all the instances of the subtype (and doesn't gets serialized)?
Everything you declare with val gets a field stored in the object (instance of the class). By default serializers trying to serialize all the fields. Usually there is some way to say that some fields should be ignored (like some #IgnoreAnnotation). Also it means that you'll have one more pointer/reference in each object which uses memory for no good reason, this might or might not be an issue for you. Declaring it as def gets a method so you can have just one object stored in some "static" place like companion object or build it on demand every time.
I'm kinda new to Scala, and I've peeked up the habit to put the format inside the companion object, would you recommend/refer to some source, about how to decide where is best to put your methods?
Scala is an unusual language and there is no direct mapping the covers all the use cases of the object concept in other languages. As a first rule of thumb there are two main usages for object:
Something where you would use static in other languages, i.e. a container for static methods, constants and static variables (although variables are discouraged, especially static in Scala)
Implementation of the singleton pattern.
By f-bound generic - do you mean the lower bound of the M being OutputMessage[M] (btw why is it ok using M twice in the same expr. ?)
Unfortunately wiki provides only a basic description. The whole idea of the F-bounded polymorphism is to be able to access to the type of the sub-class in the type of a base class in some generic manner. Usually A <: B constraint means that A should be a subtype of B. Here with M <: OutputMessage[M], it means that M should be a sub-type of the OutputMessage[M] which can easily be satisfied only by declaring the child class (there are other non-easy ways to satisfy that) as:
class Child extends OutputMessage[Child}
Such trick allows you to use the M as a an argument or result type in methods.
I'm a bit puzzled about the self bit ...
Lastly the self bit is another trick that is necessary because F-bounded polymorphism was not enough in this particular case. Usually it is used with trait when traits are used as a mix-in. In such case you might want to restrict in what classes the trait can be mixed in. And at the same type it allows you to use the methods from that base type in your mixin trait.
I'd say that the particular usage in my answer is a bit unconventional but it has the same twofold effect:
When compiling OutputMessage the compiler can assume that the type will also somehow be of the type of M (whatever M is)
When compiling any sub-type compiler ensures that the constraint #1 is satisfied. For example it will not let you to do
case class SomeChild(i: Int) extends OutputMessage[SomeChild]
// this will fail because passing SomeChild breaks the restriction of self:M
case class AnotherChild(i: Int) extends OutputMessage[SomeChild]
Actually since I had to use self:M anyway, you probably can remove the F-bounded part here, living just
abstract class OutputMessage[M]() {
self: M =>
...
}
but I'd stay with it to better convey the meaning.
As SergGr already answered, you would need an F-Bounded kind of polymorphism to solve this as it is right now.
However, for these cases, I believe (note this is only my opinion) is better to use Typeclasses instead.
In your case, you only want to provide a toJson method to any value as long as they have an instance of the OFormat[T] class.
You can achieve that with this (more simple IMHO) piece of code.
object syntax {
object json {
implicit class JsonOps[T](val t: T) extends AnyVal {
def toJson(implicit: fmt: OFormat[T]): JsVal = Json.toJson(t)(fmt)
}
}
}
final case class NotifyTableChange(tableStatus: BizTable)
object NotifyTableChange {
implicit val fmt: OFormat[NotifyTableChange] = Json.format[NotifyTableChange]
}
import syntax.json._
val m = NotifyTableChange(tableStatus = ???)
val mJson = m.toJson // This works!
The JsonOps class is an Implicit Class which will provide the toJson method to any value for which there is an implicit OFormat instance in scope.
And since the companion object of the NotifyTableChange class defines such implicit, it is always in scope - more information about where does scala look for implicits in this link.
Additionally, given it is a Value Class, this extension method does not require any instantiation in runtime.
Here, you can find a more detailed discussion about F-Bounded vs Typeclasses.
I am trying to build a generic CRUD interface that receives an element, searches for an implicit CRUD implementation from an evidence and also serialize the necessary object based on the parametrized type.
The code goes as follow:
private def createElement[T <: AnyRef](element: String)
(implicit ev: ResourceManager[T], m: Manifest[T]): Response = Try {
val e = Serializer.fromJson(element, m.runtimeClass)
ev.create(e, persistence)
ResponseBuilder.newBuilder().status(202).build()
}.getOrElse(ResponseBuilder.newBuilder().status(412).build())
As you can see. I receive a String, an evidence of a ResourceManager that implements the create method and a Manifest. When trying to serialize i make sure that the T type is of AnyRef but that is not the issue.
The problem is that m.runtimeClass returns Class[_] instead of Class[T].
My question is, if manifest does do what i want, how can i do this without explicitly passing the class name or whatever?
Thank you!
In spray / akka http I can marshal/unmarshal a case class like so:
case class Latitude(value:Double)
object Latitude extends DefaultJsonProtocol with SprayJsonSupport {
implicit val LatitudeFormat = jsonFormat1(Latitude.apply)
}
However this will marshal a Latitude(42) to an object {value:42}. I rather want it to be marshalled to just a JsNumber 42. To do so I did the following:
case class Latitude(value:Double)
object Latitude extends DefaultJsonProtocol with SprayJsonSupport {
implicit object LatitudeFormat extends RootJsonFormat[Latitude] {
def write(lat: Latitude) = lat.value.toJson
def read(value: JsValue) = ??? //too much code with decent error handling, but working
}
}
However I don't want to do this for every "simple value case class".
My goal is to e.g. create a function (or maybe a macro) that works exactly like spray's jsonFormat1 except it does not write/read objects but simple values, depending on the case class I use it on.
Unfortunately there does not seem to be any way to extend or compose the jsonRootFormat object that is returned from the jsonFormat1 function. The function itself seems to use already deprecated stuff (like ClassManifest) so I'm not sure if I want to copy and adjust it for my needs. What is my best option in this situation to get/create such a simple case class to JsValue function?
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