Reputation: 85
I'm trying to parse different types of events in json format using json4s. I have written some case classes to represent the different events all inheriting from a base class Event
:
abstract class Event{ def EventType : String }
case class StartSession(val EventType: String, val Platform: String) extends Event
case class AdView(val EventType: String, val EventSubtype: String) extends Event
This is the function I use to parse the StartSession
event:
def parser(json: String): Event = {
val parsedJson = parse(json)
val s = parsedJson.extract[StartSession]
return s
}
This function will correctly parse a json like {"EventType":"StartSession","Platform":"Portal"}
I am looking for a way to generalize the parser function so I can use it to parse all types of events that inherits from Event
and then do pattern matching over the return value of the function.
Upvotes: 5
Views: 1363
Reputation: 3541
Type hints provide the solution to the problem. If you have a polymorphic type, such as Event
, the type hint (here EventType
) tells json4s into which actual type a json object should be deserialized.
For reference, have a look at the github page of json4s. There is a section called "Serializing polymorphic Lists".
Since the type hint is only necessary for deserialization, we can get rid of the field EventType
in Event
.
abstract class Event
case class StartSession(Platform: String) extends Event
case class AdView(EventSubtype: String) extends Event
We need to bring a Formats
instance into the scope of extract
. The instance tells json4s how to perform deserialization. In our case, we need to specialize typeHintFieldName
and typeHints
. The first is the key of our type hint, in the example it is "EventType"
. The latter is a mapping from string values to classes. If we are using the class name as value, then ShortTypeHints
will do the trick. Othwerise, we could implement our own, specialized TypeHints
.
A concrete solution could look as follows:
def main(args: Array[String]): Unit ={
val json =
s"""
|[
| {
| "EventType": "StartSession",
| "Platform": "Portal"
| },
| {
| "EventType": "AdView",
| "EventSubtype": "SpecializedView"
| }
|]
""".stripMargin
implicit val formats = new DefaultFormats {
override val typeHintFieldName: String = "EventType"
override val typeHints: TypeHints =
ShortTypeHints(
List(classOf[StartSession], classOf[AdView])
)
}
val parsedJson = parse(json)
val s = parsedJson.extract[List[Event]]
println(s)
}
Upvotes: 3