scala-json unserialize in scala.js - scala

I'm trying to convert JSON from Ajax request to Case class in Scala.js using scala-json https://github.com/MediaMath/scala-json
Here is my classes:
sealed trait Result
sealed trait Error extends Result
sealed trait Msg extends Result
case class MsgData(msg: Seq[String], args: Seq[Int]) extends Msg
case class CommentError(#name("obj.comment") comment: Seq[MsgData]) extends Error
Here is how I'm trying to convert:
import json._
implicit val msgDataAcc = ObjectAccessor.create[MsgData]
implicit val commentErrorAcc = ObjectAccessor.create[CommentError]
println("here2")
val errors = JValue.fromString(req.responseText).toObject[CommentError]
println("here3")
This code just silently dies on string with conversion and "here3" never printed to console.
Here is my JSON from server:
{"obj.comment":[{"msg":["error.minLength"],"args":[10]}],"obj.name":[{"msg":["error.path.missing"],"args":[]}]}
What I'm doing wrong? How to fix this?

So I'm guessing this is scala-js. Any exceptions that happen at the top level (entry point) of a scala-js application aren't always echoed out correctly (depending on environment/browser), if you wrap the whole thing in a Try and print out the stack trace during the catch, you should successfully see exception being thrown.
Main issue above is that you need to define 'accessors' for the case classes. There's 2 ways of doing this, one works out of the box by adding an implicit for each type, the other way requires macro-paradise and gives you a much simpler way of defining accessors for case classes.
Here is the normal non-macro-paradise way:
case class MsgData(msg: Seq[String], args: Seq[Int]) extends Msg
object MsgData {
implicit val acc = ObjectAccessor.create[MsgData]
}
case class CommentError(#name("obj.comment") comment: Seq[MsgData]) extends Error
object CommentError {
implicit val acc = ObjectAccessor.create[CommentError]
}
The implicits can be placed anywhere (following the general rule for scala implicits). Placing them in the companion object is the best way to guarantee the implicit can be found anywhere, without special imports or anything needed.
This is 'less magical' than other libs like circe that use shapeless to automatically derive factories, sometimes in a bloated way. scala-json aims to keep the accessor visible for extension purposes, but this does lead to some explicit boilerplate.
This can be reduced down using macro-paradise:
#accessor case class MsgData(msg: Seq[String], args: Seq[Int]) extends Msg
#accessor case class CommentError(#name("obj.comment") comment: Seq[MsgData]) extends Error
This does the exact same thing as the above code, we just leverage macro-paradise to add the implicit 'acc' field to the companion object automatically.

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 kind the implementation it is?

On the akka website, you can the following definition:
sealed trait AccountCommand[Reply] extends ExpectingReply[Reply]
final case class Withdraw(amount: BigDecimal)(override val replyTo: ActorRef[OperationResult])
extends AccountCommand[OperationResult]
How to assign an ActorRef to replyTo?
I've taken the code as an example and try to implement on own type:
case object Channel (override val replyTo: ActorRef[SendMessage])
extends ExpectingReply[SendMessage]
and the compiler complains.
The way, that the compiler does not complain:
case object Channel extends ExpectingReply[SendMessage] {
override def replyTo: ActorRef[SendMessage] = ???
}
Is the example on akka website wrong?
If your message does not have fields, you can use a case class without parameters:
case class Channel()(override val replyTo: ActorRef[SendMessage])
extends ExpectingReply[SendMessage]
If you're asking about how to create an instance of such a class, then you should use the standard multi-parameter function call syntax:
val msg = Channel()(sendMessageActorRef)
That being said, it looks to me that specifically in that part of the Akka API that you linked to, you don't have to explicitly provide any ActorRefs, Effects seem to do it kind of automatically.

How do I get around type erasure on Akka receive method

I'm using cake pattern in Scala 2.10 to inject required trait to my actor acording to some bussiness logic:
I have several types f Events:
sealed abstract class Event(val timeStamp:Long)
case class StudentEvent(override val timeStamp:Long, studentId:Long) extends Event(timeStamp:Long)
case class TeacherEvent(override val timeStamp:Long, teacherIdId:Long) extends Event(timeStamp:Long)
Now I have traits which implement action for each type of event:
Abstract:
trait Action[T <: Event] {
def act[T](event:T):Unit
}
And two impls:
trait StudentAction extends Action[StudentEvent]{
override def act[StudentEvent](event:StudentEvent):Unit = println(event)
}
and
trait TeacherAction extends Action[TeacherEvent]{
override def act[TeacherEvent](event:TeacherEvent):Unit = println(event)
}
Now my Actor:
class ActionActor[T <: Event] extends Actor{
self:Action[T]=>
override def receive= {
case msg: T => act(msg)
case _ => println("Unknown Type")
}
}
And I inject required trait this way:
val actionActor = system.actorOf(Props(new ActionActor[StudentEvent] with StudentAction))
actionActor ! StudentEvent(1111L,222L)
On compile I'm getting error:
Warning:(14, 14) abstract type pattern T is unchecked since it is eliminated by erasure
case msg:T => act(msg)
^
I know that somehow I need to use TypeTag, but I failed to understand how can I do it.
Please help.
Update:
In reality, I have 10 type of events which extends from Event that I need to handle.
I want to implement business logic for each event in separate trait, because because mixing all 10 event handler functions will give me several hundreds(if not thousands) lines of code.
I don't want to create different Actor types for each event. For example:
class Event1Actor extend Actor{
def receive ={
case Event1(e) => //event1 Business Logic
}
}
class Event2Actor extend Actor{
def receive ={
case Event2(e) => //event2 Business Logic
}
}
and the same Event3Actor, Event4Actor,etc....
Such code seems ugly to me, because I need to implement business Logic inside each Actor.
I'm seeking for some kind generic solution based on design pattern, for example strategy pattern.
First, I would suggest defining your events as:
sealed trait Event { def timeStamp: Long }
case class StudentEvent(timeStamp: Long, studentId: Long)
extends Event
case class TeacherEvent(timeStamp: Long, teacherId: Long)
extends Event
This is the standard encoding for algebraic data types.
Second, this business where you're using a self-type seems really confusing to me. Surely the same object shouldn't be both an "actor" and an "action"? Why not use composition here instead of inheritance? (It kinda feels like you're just throwing Scala features together. So a general piece of advice here would be: slow down.)
But to address your main question, I think you're fundamentally on the wrong path. Almost any time you end up butting heads with type erasure and/or TypeTag, it's a sign that your design is flawed and you should back up and rethink — unless you realllllllly know what you're doing.
In any case, you're not going to be able to get Akka to attach a TypeTag to your messages. Akka just doesn't work that way. (There have been a series of efforts to add "typed actors" or "typed channels" to Akka, and you might look those up, but it's probably overkill in your use case unless you're realllllly sure it isn't.)
What is the underlying architectural problem that you're trying to solve here? What motivated this design?
Check out Composing trait behavior in Scala in an Akka receive method, it seems really similar, and after digesting it, I think you'll be in a better position to decide what to do next.

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

How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration

I am upgrading existing code from Rogue 1.1.8 to 2.0.0 and lift-mongodb-record from 2.4-M5 to 2.5.
I'm having difficulty writing MongoCaseClassField that contains a scala enum, that I really could use some help with.
For example,
object MyEnum extends Enumeration {
type MyEnum = Value
val A = Value(0)
val B = Value(1)
}
case class MyCaseClass(name: String, value: MyEnum.MyEnum)
class MyMongo extends MongoRecord[MyMongo] with StringPk[MyMongo] {
def meta = MyMongo
class MongoCaseClassFieldWithMyEnum[OwnerType <: net.liftweb.record.Record[OwnerType], CaseType](rec : OwnerType)(implicit mf : Manifest[CaseType]) extends MongoCaseClassField[OwnerType, CaseType](rec)(mf) {
override def formats = super.formats + new EnumSerializer(MyEnum)
}
object myCaseClass extends MongoCaseClassFieldWithMyEnum[MyMongo, MyCaseClass](this)
/// ...
}
When we try to write to this field, we get the following error:
could not find implicit value for evidence parameter of type
com.foursquare.rogue.BSONType[MyCaseClass]
.and(_.myCaseClass setTo myCaseClass)
We used to have this working in Rogue 1.1.8, by using our own version of the MongoCaseClassField, which made the #formats method overridable. But that feature was included into lift-mongodb-record in 2.5-RC6, so we thought this should just work now?
Answer coming from : http://grokbase.com/t/gg/rogue-users/1367nscf80/how-to-update-a-record-with-mongocaseclassfield-when-case-class-contains-a-scala-enumeration#20130612woc3x7utvaoacu7tv7lzn4sr2q
But more convenient directly here on StackOverFlow:
Sorry, I should have chimed in here sooner.
One of the long-standing problems with Rogue was that it was too easy to
accidentally make a field that was not serializable as BSON, and have it
fail at runtime (when you try to add that value to a DBObject) rather than
at compile time.
I introduced the BSONType type class to try to address this. The upside is
it catches BSON errors at compile time. The downside is you need to make a
choice when it comes to case classes.
If you want to do this the "correct" way, define your case class plus a
BSONType "witness" for that case class. To define a BSONType witness, you
need to provide serialization from that type to a BSON type. Example:
case class TestCC(v: Int)
implicit object TestCCIsBSONType extends BSONType[TestCC] {
override def asBSONObject(v: TestCC): AnyRef = {
// Create a BSON object
val ret = new BasicBSONObject
// Serialize all the fields of the case class
ret.put("v", v.v)
ret
}
}
That said, this can be quite burdensome if you're doing it for each case
class. Your second option is to define a generic witness that works for any
case class, if you have a generic serialization scheme:
implicit def CaseClassesAreBSONTypes[CC <: CaseClass]: BSONType[CC] =
new BSONType[CC] {
override def asBSONObject(v: CC): AnyRef = {
// your generic serialization code here, maybe involving formats
}
}
Hope this helps,