JSON.parse
creates a new object with the fields it found. The created object:
- does not belong to the original class
- does not have any of the methods of the original class (e.g. no getters)
- does not extend any of the interfaces or abstract classes its original class extends
This is a common problem in the JS world too: Parsing JSON from Typescript restores data members but not type: cannot call methods on result - Stack Overflow.
Solution 1: manual hydration
// Let's imagine this is the class you want to put in the JSON
// You'll need to do this for *all* classes that become JSON
data class Point(val x: Int, val y: Int)
// To JSON
val json = JSON.stringify(Point(1, 2))
// From JSON
val deserialized = JSON.parse<Point>(json)
val result = Point(deserialized.x, deserialized.y) // force the creation of an instance of the class using the constructor
Note that if you go for this solution, you must call the constructor for all objects in the JSON, recursively, even for things like String
. JSON.parse
only behaves as you expect for JS primitives (Int
and smaller should be fine, Float
and Double
should be fine, Boolean
should be fine—that’s it). Any object or class must be instantiated manually.
Solution 2: don’t use JSON.parse
This problem is specific to JSON.stringify/JSON.parse. Another solution is to use something else, for example KotlinX.Serialization.
@Serializable
data class Point(val x: Int, val y: Int)
// To JSON
val json = Json.encodeToString(Point(2, 3))
// From JSON
val result = Json.decodeFromString<Point>(json)
KotlinX.Serialization knows what class the object came from, and is able to recreate it exactly as you’d expect.