Akka actor construction in Play! framework - scala

I am playing with the Play! framework and I wanted to create a factory called Services which will create new actors. I have this so far
class UserRegistration extends Actor {
def receive = {
case "foo" => "bar"
}
}
object UserRegistration {
val path: String = "user/registration"
}
object Services {
val system = ActorSystem("Services")
def apply[A<:Actor]: ActorRef = system.actorOf(Props[A], A.path)
}
And I wanted to create and pass messages to actors like this:
Services[UserRegistration] ? "hello"
but I get errors of the type could not find implicit value for evidence parameter of type ClassManifest[A]. Can anyone please tell me what am I doing wrong here? And if this is a valid construction in general (a best practice). I am pretty new in Scala and still learning stuff.
Thanks!

senia's answer works too, but if you want to specify a common path for each type of actor, you need a second implicit parameter(the first being the ClassManifest so that you can specify a path for each type of actor. Keep in mind that actor names have to be unique though, so you have to add something to that path.
First you define a class that holds the Path:
case class Path(value:String)
Then you define an implicit value in the companion object of your actor class:
object SomeActor {
implicit val path = Path("SomeActor")
}
Finally you modify the apply method to take an implicit class manifest as well as an implicit path.
def apply[A<:Actor](implicit cm:ClassManifest[A], path:Path[A]): ActorRef =
system.actorOf(Props[A], path.value + someIndex)

Method apply of object Props implicitly takes parameter of type ClassManifest[T].
apply [T <: Actor] (implicit arg0: ClassManifest[T])
You have to add such parameter into your method:
def apply[A<:Actor : ClassManifest]: ActorRef = system.actorOf(Props[A])

Related

No instance of play.api.libs.json.Format is available for akka.actor.typed.ActorRef[org.knoldus.eventSourcing.UserState.Confirmation]

No instance of play.api.libs.json.Format is available for akka.actor.typed.ActorRef[org.knoldus.eventSourcing.UserState.Confirmation] in the implicit scope (Hint: if declared in the same file, make sure it's declared before)
[error] implicit val userCommand: Format[AddUserCommand] = Json.format
I am getting this error even though I have made Implicit instance of Json Format for AddUserCommand.
Here is my code:
trait UserCommand extends CommandSerializable
object AddUserCommand{
implicit val format: Format[AddUserCommand] = Json.format[AddUserCommand]
}
final case class AddUserCommand(user:User, reply: ActorRef[Confirmation]) extends UserCommand
Can anyone please help me with this error and how to solve it?
As Gael noted, you need to provide a Format for ActorRef[Confirmation]. The complication around this is that the natural serialization, using the ActorRefResolver requires that an ExtendedActorSystem be present, which means that the usual approaches to defining a Format in a companion object won't quite work.
Note that because of the way Lagom does dependency injection, this approach doesn't really work in Lagom: commands in Lagom basically can't use Play JSON.
import akka.actor.typed.scaladsl.adapter.ClassicActorSystemOps
import play.api.libs.json._
class PlayJsonActorRefFormat(system: ExtendedActorSystem) {
def reads[A] = new Reads[ActorRef[A]] {
def reads(jsv: JsValue): JsResult[ActorRef[A]] =
jsv match {
case JsString(s) => JsSuccess(ActorRefResolver(system.toTyped).resolveActorRef(s))
case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError(Seq("ActorRefs are strings"))))) // hopefully parenthesized that right...
}
}
def writes[A] = new Writes[ActorRef[A]] {
def writes(a: ActorRef[A]): JsValue = JsString(ActorRefResolver(system.toTyped).toSerializationFormat(a))
}
def format[A] = Format[ActorRef[A]](reads, writes)
}
You can then define a format for AddUserCommand as
object AddUserCommand {
def format(arf: PlayJsonActorRefFormat): Format[AddUserCommand] = {
implicit def arfmt[A]: Format[ActorRef[A]] = arf.format
Json.format[AddUserCommand]
}
}
Since you're presumably using JSON to serialize the messages sent around a cluster (otherwise, the ActorRef shouldn't be leaking out like this), you would then construct an instance of the format in your Akka Serializer implementation.
(NB: I've only done this with Circe, not Play JSON, but the basic approach is common)
The error says that it cannot construct a Format for AddUserCommand because there's no Format for ActorRef[Confirmation].
When using Json.format[X], all the members of the case class X must have a Format defined.
In your case, you probably don't want to define a formatter for this case class (serializing an ActorRef doesn't make much sense) but rather build another case class with data only.
Edit: See Levi's answer on how to provide a formatter for ActorRef if you really want to send out there the actor reference.

What feature of Scala allows for Props[SomeActor] syntax

One aspect of Akka I've always just glossed over appears right in the canonical Hello World! example. That is, the syntax for creating a Props class:
val props = Props[MyActor]
Q. What mechanism in Scala is allowing for the type parameter (i.e. [MyActor]) to be specified in this way? I'm assuming this gets translated to a constructor/apply method on Props that takes a Class parameter? For instance, my guess is it's equivalent to:
val props = Props(classOf[MyActor])
I've always assumed classOf was "special" and somehow cheated in order to use the [] syntax. Since I see that Akka, a 3rd party library, utilizes the same syntax it would be great to see a simple REPL example that demonstrates how I can utilize this syntax for my own classes.
Instances of Props are ultimately of the following case class (https://github.com/akka/akka/blob/0511b07f3e50e0422379075ae76dd158e4d377fa/akka-actor/src/main/scala/akka/actor/Props.scala#L115):
final case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any])
Since this is a case class, scala will generate default apply method of
Props.apply(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any])
The Props companion object has several other apply methods which create instances of this class for you, using the default apply method. In the case of Props[MyActor], this is the method:
def apply[T <: Actor: ClassTag](): Props = apply(defaultDeploy, implicitly[ClassTag[T]].runtimeClass, List.empty)
Props[MyActor] is syntactic sugar for Props.apply[MyActor](). So Props is using the reflection capabilities of ClassTag in order to get the runtime class of MyActor, so it can satisfy the parameter clazz: Class[_] of the Props case class.
It is the Scala ClassTag mechanism. For instance:
object Test {
def apply[T: ClassTag](s: String): Option[T] = ...
}
val foo = Test[Foo]("foo")
In the apply method you can simply do something like
val ctor = implicitly[ClassTag[T]].runtimeClass.getConstructors.head
in order to get access to the first constructor of T for example.

spray-json and spray-routing: how to invoke JsonFormat write in complete

I am trying to figure out how to get a custom JsonFormat write method to be invoked when using the routing directive complete. JsonFormat created with the jsonFormat set of helper functions work fine, but defining a complete JsonFormat will not get called.
sealed trait Error
sealed trait ErrorWithReason extends Error {
def reason: String
}
case class ValidationError(reason: String) extends ErrorWithReason
case object EntityNotFound extends Error
case class DatabaseError(reason: String) extends ErrorWithReason
case class Record(a: String, b: String, error: Error)
object MyJsonProtocol extends DefaultJsonProtocol {
implicit object ErrorJsonFormat extends JsonFormat[Error] {
def write(err: Error) = failure match {
case e: ErrorWithReason => JsString(e.reason)
case x => JsString(x.toString())
}
def read(value: JsValue) = {
value match {
//Really only intended to serialize to JSON for API responses, not implementing read
case _ => throw new DeserializationException("Can't reliably deserialize Error")
}
}
}
implicit val record2Json = jsonFormat3(Record)
}
And then a route like:
import MyJsonProtocol._
trait TestRoute extends HttpService with Json4sSupport {
path("testRoute") {
val response: Record = getErrorRecord()
complete(response)
}
}
If I add logging, I can see that the ErrorJsonFormat.write method never gets called.
The ramifications are as follows showing what output I'm trying to get and what I actually get. Let's say the Record instance was Record("something", "somethingelse", EntityNotFound)
actual
{
"a": "something",
"b": "somethingelse",
"error": {}
}
intended
{
"a": "something",
"b": "somethingelse",
"error": "EntityNotFound"
}
I was expecting that the complete(record) uses the implicit JsonFormat for Record which in turn relies on the implicit object ErrorJsonFormat that specifies the write method that creates the appropriate JsString field. Instead it seems to both recognize the provided ErrorJsonFormat while ignoring its instructions for serializing.
I feel like there should be a solution that does not involve needing to replace implicit val record2Json = jsonFormat3(Record) with an explicit implicit object RecordJsonFormat extends JsonFormat[Record] { ... }
So to summarize what I am asking
Why does the serialization of Record fail to call the ErrorJsonFormat write method (what does it even do instead?) answered below
Is there a way to match my expectation while still using complete(record)?
Edit
Digging through the spray-json source code, there is an sbt-boilerplate template that seems to define the jsonFormat series of methods: https://github.com/spray/spray-json/blob/master/src/main/boilerplate/spray/json/ProductFormatsInstances.scala.template
and the relevant product for jsonFormat3 from that seems to be :
def jsonFormat3[P1 :JF, P2 :JF, P3 :JF, T <: Product :ClassManifest](construct: (P1, P2, P3) => T): RootJsonFormat[T] = {
val Array(p1,p2,p3) = extractFieldNames(classManifest[T])
jsonFormat(construct, p1, p2, p3)
}
def jsonFormat[P1 :JF, P2 :JF, P3 :JF, T <: Product](construct: (P1, P2, P3) => T, fieldName1: String, fieldName2: String, fieldName3: String): RootJsonFormat[T] = new RootJsonFormat[T]{
def write(p: T) = {
val fields = new collection.mutable.ListBuffer[(String, JsValue)]
fields.sizeHint(3 * 4)
fields ++= productElement2Field[P1](fieldName1, p, 0)
fields ++= productElement2Field[P2](fieldName2, p, 0)
fields ++= productElement2Field[P3](fieldName3, p, 0)
JsObject(fields: _*)
}
def read(value: JsValue) = {
val p1V = fromField[P1](value, fieldName1)
val p2V = fromField[P2](value, fieldName2)
val p3V = fromField[P3](value, fieldName3)
construct(p1v, p2v, p3v)
}
}
From this it would seem that jsonFormat3 itself is perfectly fine (if you trace into the productElement2Field it grabs the writer and directly calls write). The problem must then be that the complete(record) doesn't involve JsonFormat at all and somehow alternately marshals the object.
So this seems to answer part 1: Why does the serialization of Record fail to call the ErrorJsonFormat write method (what does it even do instead?). No JsonFormat is called because complete marshals via some other means.
It seems the remaining question is if it is possible to provide a marshaller for the complete directive that will use the JsonFormat if it exists otherwise default to its normal behavior. I realize that I can generally rely on the default marshaller for basic case class serialization. But when I get a complicated trait/case class setup like in this example I need to use JsonFormat to get the proper response. Ideally, this distinction shouldn't have to be explicit for someone writing routes to need to know the situations where its the default marshaller as opposed to needing to invoke JsonFormat. Or in other words, needing to distinguish if the given type needs to be written as complete(someType) or complete(someType.toJson) feels wrong.
After digging further, it seems the root of the problem has been a confusion of the Json4s and Spray-Json libraries in the code. In trying to track down examples of various elements of JSON handling, I didn't recognize the separation between the two libraries readily and ended up with code that mixed some of each, explaining the unexpected behavior.
In this question, the offending piece is pulling in the Json4sSupport in the router. The proper definition should be using SprayJsonSupport:
import MyJsonProtocol._
trait TestRoute extends HttpService with SprayJsonSupport {
path("testRoute") {
val response: Record = getErrorRecord()
complete(response)
}
}
With this all considered, the answers are more apparent.
1: Why does the serialization of Record fail to call the ErrorJsonFormat write method (what does it even do instead)?.
No JsonFormat is called because complete marshals via some other means. That other means is the marshaling provided implicitly by Json4s with Json4sSupport. You can use record.toJson to force spray-json serialization of the object, but the output will not be clean (it will include nested JS objects and "fields" keys).
Is there a way to match my expectation while still using complete(record)?
Yes, using SprayJsonSupport will use implicit RootJsonReader and/or RootJsonWriter where needed to automatically create a relevant Unmarshaller and/or Marshaller. Documentation reference
So with SprayJsonSupport it will see the RootJsonWriter defined by the jsonFormat3(Record) and complete(record) will serialize as expected.

Retrieving an ActorSelection from a Trait in akka/scala

I am new to scala/akka. I need to create a trait and from this trait, to retrieve actors from a context or directly from an actorSystem.
But I don't want this trait to either extends Actor, nor force to be mixed with an Actor.
Is there a way to do that?
Thanks.
Welcome to Akka :-)
You should create a trait with an abstract method, that will be used to retrieve the actor system, for example like this:
trait DoesThings {
def system: ActorSystem
def findActor(name: String) = // do actor selection using system here
}
object Example extends DoesThings {
val system = ActorSystem("example")
val ref = findActor
}
Happy hakking!
You can put an actor system val in the trait.
And with instantiation you will pass used actor system to it.
You could try something like this:
trait ActorLookup{
def actorSelection(path:ActorPath)(implicit fact:ActorRefFactory) = fact.actorSelection(path)
def actorSelection(path:String)(implicit fact:ActorRefFactory) = fact.actorSelection(path)
}
class ActorBasedImpl extends Actor with ActorLookup{
def receive = {
case _ =>
val ref = actorSelection("/foo")
}
}
class NonActorBasedImpl extends ActorLookup{
implicit val system = ActorSystem("foo")
...
val ref = actorSelection("/user/foo")
}
Within an Actor, you already have an implicit ActorRefFactory in scope so no need to define one. If you wanted to use the ActorSystem instead there, you could just pass it explicitly like so:
actorSelection("/user/foo")(context.system)
Outside an Actor, it's more likely you will be using an ActorSystem instead of an ActorContext to perform lookups, so that's why an implicit ActorSystem was defined. But again, you don't have to define it as an implicit and could just use it explicitly if desired.

How to design immutable model classes when using inheritance

I'm having trouble finding an elegant way of designing a some simple classes to represent HTTP messages in Scala.
Say I have something like this:
abstract class HttpMessage(headers: List[String]) {
def addHeader(header: String) = ???
}
class HttpRequest(path: String, headers: List[String])
extends HttpMessage(headers)
new HttpRequest("/", List("foo")).addHeader("bar")
How can I make the addHeader method return a copy of itself with the new header added? (and keep the current value of path as well)
Thanks,
Rob.
It is annoying but the solution to implement your required pattern is not trivial.
The first point to notice is that if you want to preserve your subclass type, you need to add a type parameter. Without this, you are not able to specify an unknown return type in HttpMessage
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String):X
}
Then you can implement the method in your concrete subclasses where you will have to specify the value of X:
class HttpRequest(path: String, headers: List[String])
extends HttpMessage(headers){
type X = HttpRequest
def addHeader(header: String):HttpRequest = new HttpRequest(path, headers :+header)
}
A better, more scalable solution is to use implicit for the purpose.
trait HeaderAdder[T<:HttpMessage]{
def addHeader(httpMessage:T, header:String):T
}
and now you can define your method on the HttpMessage class like the following:
abstract class HttpMessage(headers: List[String]) {
type X <: HttpMessage
def addHeader(header: String)(implicit headerAdder:HeaderAdder[X]):X = headerAdder.add(this,header) }
}
This latest approach is based on the typeclass concept and scales much better than inheritance. The idea is that you are not forced to have a valid HeaderAdder[T] for every T in your hierarchy, and if you try to call the method on a class for which no implicit is available in scope, you will get a compile time error.
This is great, because it prevents you to have to implement addHeader = sys.error("This is not supported")
for certain classes in the hierarchy when it becomes "dirty" or to refactor it to avoid it becomes "dirty".
The best way to manage implicit is to put them in a trait like the following:
trait HeaderAdders {
implicit val httpRequestHeaderAdder:HeaderAdder[HttpRequest] = new HeaderAdder[HttpRequest] { ... }
implicit val httpRequestHeaderAdder:HeaderAdder[HttpWhat] = new HeaderAdder[HttpWhat] { ... }
}
and then you provide also an object, in case user can't mix it (for example if you have frameworks that investigate through reflection properties of the object, you don't want extra properties to be added to your current instance) (http://www.artima.com/scalazine/articles/selfless_trait_pattern.html)
object HeaderAdders extends HeaderAdders
So for example you can write things such as
// mixing example
class MyTest extends HeaderAdders // who cares about having two extra value in the object
// import example
import HeaderAdders._
class MyDomainClass // implicits are in scope, but not mixed inside MyDomainClass, so reflection from Hiberante will still work correctly
By the way, this design problem is the same of Scala collections, with the only difference that your HttpMessage is TraversableLike. Have a look to this question Calling map on a parallel collection via a reference to an ancestor type