Deserialize JSON to Scala Class
There are quite a few libraries that allow us to convert a JSON String into a proper Scala Class (process called deserialization).
Some of the most common are Circe (based on Cats), play-json, Spray Json… However, most of them depend on other heavy libraries. That’s why I found upickle, by Li Haoyi, one of the simplest to use when working on a Spark environment, as it doesn't conflict with anything else.
You can add it into your POM / sbt with the following coordinates:
com.lihaoyi:upickle_2.12:2.0.0
Deserialising a simple json
Having the following json string:
{"attribute1": "Test String", "attribute2": 2}
We need a class that matches that structure:
case class Foo(attribute1: String, attribute2: Int)
And we just need to create an implicit to convert the string to the class:
import upickle.default.{read, reader}
implicit val rw = reader[ujson.Obj].map[Foo] (json => Foo(
read[String](json("attribute")),
read[Int] (json("attribute2"))
))
Now we can use the following piece of code to covert the string into an object of our class:
val jsonString: String = """{"attribute1": "Test String", "attribute2": 2}"""
val foo: Foo = upickle.default.read[Foo](jsonString)
println(foo)
-----
> Foo(Test String, 2)
Working with optional fields
We can also deal with optional fields in a similar way. We only need to write the right implicit that will deal with that situation:
import upickle.default.{read, reader}
case class Foo(attribute1: String, attribute2: Int)
implicit val rw = reader[ujson.Obj].map[Foo] (json => Foo(
read[String](json("attribute")),
if(json.obj.contains("attribute2")) {read[String](json("attribute2")) } else null,
))
val jsonString: String = """{"attribute1": "Test String", "attribute2": 2}"""
val foo: Foo = upickle.default.read[Foo](jsonString)
println(foo)
---
> Foo(Test String, 2)
---
val jsonString2: String = """{"attribute1": "Test String 2"}"""
val foo2: Foo = upickle.default.read[Foo](jsonString2)
println(foo2)
---
> Foo(Test String 2, null)
---