I'm trying to send an object to a remote actor and I got this exception:
ERROR akka.remote.EndpointWriter - Transient association error (association remains live)
java.io.NotSerializableException: scala.collection.immutable.MapLike$$anon$2
The object being serialized is a case class:
case class LocationReport(idn: String, report: String, timestamp: Option[String], location: Attr, status: Attr, alarms: Attr, network: Attr, sensors: Attr) extends Message(idn) {
val ts = timestamp getOrElse location("fix_timestamp")
def json =
(report ->
("TIME" -> ts) ~
("location" -> location) ~
("alarms" -> alarms) ~
("network" -> network) ~
("sensors" -> ((status ++ sensors) + ("CUSTOMCLOCK" -> Report.decodeTimestamp(ts)))))
}
And Attr is a type re-definition:
type Attr = Map[String, String]
The Message class is pretty simple:
abstract class Message(idn: String) {
def topic = idn
def json(): JValue
}
I'm wondering if the type alias/redefinition is confusing the serializer. I think I'm using ProtoBuf serialization, but I do see JavaSerializer in the stacktrace.
More Debugging Info
I newed up a JavaSerializer and individually serialized each of the Maps. Only one (alarms) fails to serialize. Here's the toString of each of them:
This one failed:
alarms = Map(LOWBATTERY -> 1373623446000)
These succeeded:
location = Map(a_value -> 6, latitude -> 37.63473, p_value -> 4, longitude -> -97.41459, fix_timestamp -> 3F0AE7FF, status -> OK, fix_type -> MSBL, CUSTOMCLOCK -> 1373644159000)
network = Map(SID -> 1271, RSSI -> 85)
sensors = Map(HUMIDITY -> -999, PRESSURE -> -999, LIGHT -> -999 9:52 AM)
status = Map(TEMPERATURE_F -> 923, CYCLE -> 4, TEMPERATURE1_C -> 335, CAP_REMAINING -> 560, VOLTAGE -> 3691, CAP_FULL -> 3897)
The problem is that Map.mapValues produces an object that's not serializable. When alarms was created, it's run through something like alarms.mapValues(hex2Int). The problem and workaround is described here:
https://issues.scala-lang.org/browse/SI-7005
In short, the solution is to do alarms.mapValues(hex2Int).map(identity)
Not sure whether this works in all cases but my workaround was simply to convert the map into a sequence (just .toSeqbefore the sequence) before serialization. toMap should give you the same map after deserialization.
Related
I have ane map that maps ids to integers. I need to create another map which will map ids to a particular type (interval) which has a tuple of integers.
val secondValue = 5
input: Map[Identifier, Integer]
val newInput: Map[Identifier, Interval] = input.map({
case (x, d) => (x -> Interval(d, secondValue))
})
Interval is defined in a file and it is imported here. This code does not work as newInput is not changed. Can you guide me where I am doing wrong?
The required type of input is Identifier -> Integer and newInput is Identifier -> [Integer, Integer], but I am getting Identifier -> Integer for both input and newInput.
Since you are not providing Identifier and Interval, I created my own. After initializing input properly, your code seems to work fine:
case class Interval(x: Int, d: Int)
case class Identifier(x:Int)
val secondValue = 5
val input: Map[Identifier, Integer] = Map(Identifier(1) -> 10)
val newInput: Map[Identifier, Interval] = input.map({
case (x, d) =>
x -> Interval(d, secondValue)
})
I have a map in my scala code, that has a string as a key and a userdefined object as the value. I want to split this map to three different map objects based on a property of the value.
Is this possible? Can someone share a way to do this? I have been trying to search but no example could be found. I am a novice at scala and appreciate any help...
Lets say you had a map of person's and you wanted to divide that into three maps based on the age of a person.
case class Person(name: String, age: Int)
val map = Map(
"p1" -> Person("person_1", 15),
"p2" -> Person("person_2", 30),
"p3" -> Person("person_3", 40),
"p4" -> Person("person_4", 55),
"p5" -> Person("person_5", 65)
)
// map: scala.collection.immutable.Map[String,Person] = Map(p4 -> Person(person_4,55), p5 -> Person(person_5,65), p3 -> Person(person_3,40), p2 -> Person(person_2,30), p1 -> Person(person_1,15))
val dividedMaps = map.groupBy({ case (key, person) =>
if (person.age < 20 ) "teenager"
else if (person.age < 50) "adult"
else "old"
})
// dividedMaps: scala.collection.immutable.Map[String,scala.collection.immutable.Map[String,Person]] = Map(old -> Map(p4 -> Person(person_4,55), p5 -> Person(person_5,65)), teenager -> Map(p1 -> Person(person_1,15)), adult -> Map(p3 -> Person(person_3,40), p2 -> Person(person_2,30)))
I'm running a ScalaTest asserting the right data type is returned by my actor.
The actor named "testActor" converts data from SortedMap[Long, SortedMap[String, Double]] to SortedMap[String, Array[Double]]
The current code is:
val data: SortedMap[Long, SortedMap[String, Double]] = SortedMap (1000L -> SortedMap("c1" -> 1., "c2" -> 2.1), 2000L -> SortedMap("c1" -> 1.1), 3000L -> SortedMap("c1" -> 0.95))
val expectedResult = SortedMap("t1" -> Array(1., 1.1, 0.95), "t2" -> Array(2.1))
actor ! testActor(data)
expectMsg(replyTestActor(expectedResult)
For some reason the assert is done on the map physical address, i.e.
assertion failed: expected replyTestActor(Map(c1 -> [D#60b8a8f6, c2 -> [D#7b5ce015),2,2000), found replyTestActor(Map(c1 -> [D#e7bc1f9, c2 -> [D#5efbc9dc),2,2000)
I must comment that in debug mode, when i enter "Expression Evaluation" on a break point the actor message and the "expectedValue" are identical×¥
The problem is the values in your SortedMap.
> Array(42) == Array(42)
res0: Boolean = false
Array does not provide a friendly equal implementation.
Edit: plus, Array is a mutable structure, usually not recommend to use them while passing messages between actors.
I need help for passing HashMap to queryParam as shown below, as I have so many request with same queryParams and just last queryParam changes with each request.
val asset_sort_by_displays = exec(http("Sort by Displays")
.get("/data/analytics/reports/")
.queryParamMap(GatlingConfig.asset_query_string_map)
.queryParam("""sort""", """displays""")
Where in my config file I have a object GatlingConfig{} where I've defined asset_query_string_map as.
val asset_query_string_map = Map("""report_type""" -> """performance""",
"""start_date""" -> "2014-07-07",
"""end_date""" -> "2014-07-10",
"""metrics""" -> """plays""",
"""metrics""" -> """displays""",
"""metrics""" -> """video_starts""")
But, it throws " value asset_query_string_map is not a member of io.gatling.http.request.builder.HttpRequestBuilder " error.
Please guide me , how can I pass Map value to queryParams?
Where in my config file I have created
I don't get it. This is to be defined in some Scala code and imported/placed in scope.
Then, queryParam is for unique values. You'd have to use queryParamMap instead.
With current snapshot, you'd have:
val asset_query_string_map = Map("""report_type""" -> """performance""",
"""start_date""" -> "2014-07-07",
"""end_date""" -> "2014-07-10",
"""metrics""" -> """plays""",
"""metrics""" -> """displays""",
"""metrics""" -> """video_starts""")
val asset_sort_by_displays = exec(http("Sort by Displays")
.get("/data/analytics/reports/")
.queryParamMap(asset_query_string_map)
.queryParam("""sort""", """displays"""))
I was able to perform simple validations on simple json structures like this one:
object RestTest extends Controller {
case class Address(street: String,
number: Int)
case class Person(name: String,
age: Int,
address: Address)
implicit val address = Json.reads[Address]
implicit val rds = Json.reads[Person]
def restTest = Action(parse.json) {
request =>
request.body.validate[Person].map {
case person => Ok(Json.obj("e" -> 0, "message" -> ("The name is: " + person.name + " and he lives in " + person.address.street)))
}.recoverTotal(e => Ok("e" -> 1)
}
}
Now I have the following structure that contains arrays, but I wasn't able to validate it correctly so far. I have tried many different ways, but I keep receiving compilation errors.
case class SecondStructure(index: Int)
case class EntryStructure(field1: String,
muSecondJsonArray: List[SecondStructure])
case class MyJsonArray(allEntries: List[EntryStructure])
How can I validate this json?
Thanks
First of all, ensure you are using the latest Play 2.1.1 releases. There was an issue with earlier versions when validating case classes with a single field. After that, it should all work - please see below for an example:
object JsonTest {
case class SecondStructure(index: Int)
case class EntryStructure(field1: String, muSecondJsonArray: List[SecondStructure])
case class MyJsonArray(allEntries: List[EntryStructure])
// Use the macro "inception" feature to automatically build your Readers.
implicit val ssReads = Json.reads[SecondStructure]
implicit val esReads = Json.reads[EntryStructure]
implicit val arrayReads = Json.reads[MyJsonArray]
// Defining an example instance...
val testArray = MyJsonArray(
List(
EntryStructure("foo", List(SecondStructure(1), SecondStructure(2))),
EntryStructure("bar", List(SecondStructure(3), SecondStructure(4)))))
// And the equivilant JSON structure...
val testJson = Json.obj("allEntries" ->
Json.arr(
Json.obj("field1" -> "foo", "muSecondJsonArray" -> Json.arr(
Json.obj("index" -> 1), Json.obj("index" -> 2))),
Json.obj("field1" -> "bar", "muSecondJsonArray" -> Json.arr(
Json.obj("index" -> 3), Json.obj("index" -> 4)))))
testJson.validate[MyJsonArray].map {
case foo if foo == testArray => println("Okay, we're good!")
}
}