Is there a reflection-based way (not `kotlinx.seri...
# javascript
j
Is there a reflection-based way (not
kotlinx.serialization
) in Kotlin/JS to parse JSON into Kotlin data classes?
Copy code
@Test
    fun jsonTest() {
        data class Person(val name: String)

        val expected = Person("Bob")
        val parsedPerson = JSON.parse<Person>("""{"name":"Bob"}""")

        assertEquals(expected, parsedPerson)
    }
This test gives:
Copy code
AssertionError: Expected <Person(name=Bob)>, actual <[object Object]>.
d
Reflection on JS is very limited, the answer is most likely no at this point.
r
The problem is that kotlinx.serialization guarantees type safety and restores class prototype proprely when basic
JSON.parse
constructs annonymous object with the similar layout. Could you please provide some details why kotlinx.serialization doesn’t fit your requirements?
j
I'm trying to work on a multiplatform library that needs to parse JSON into user-defined classes at some point. I can't force users of the library to annotate their code and run an annotation processor, so I can't really expect serializers to be available on user-defined classes 😕
Do you have a solution to this problem? I believe any multiplatform library (or even Kotlin/JS libraries I guess) that needs to parse JSON will run into this at some point
Isn't it misleading for
JSON.parse()
to return
T
? If we can't ensure the instance returned will be of type
T
, shouldn't we just return some sort of JS object type?
r
Unfortunatly there is no recomended solution besides ktx.serialization. Prorably you could try to set prototype manualy.
😭 2
I think this might help
Copy code
val o = js("{}")
o.__proto__ = js("Object.create(O.prtotype)")
Or even move data from json’s object into manually created
j
I'm sorry but I don't get how this works 😕 how does
equals
work in JS btw?
I can't move data because I don't know the available properties of the class (
T::class.members
is not available in Kotlin/JS)
r
Which
equals
? When you write
==
in kotlin?
j
Yes
r
It depends on, but generally it just invokes
Any.equals
j
I mean how does that translate to JS?
r
There are lot of cases. In case of general objects
a == b
becomes
a.equals(b)
Under the hood
equals
usually checks for
instanceof
j
So the generated
equals()
on data classes checks for
instanceof
and this is based on JS prototype when compiled to JS? (I'm trying to understand how/why my sample code fails)
r
Yes. If you interesting especcialy in data class equals there are general alhorithm
For
data class Dat(val start: String, val end: String)
equals in js going to be look like
Copy code
Dat.prototype.equals = function (other) {
    return this === other || (other !== null && (typeof other === 'object' && (Object.getPrototypeOf(this) === Object.getPrototypeOf(other) && (Kotlin.equals(this.start, other.start) && Kotlin.equals(this.end, other.end)))));
  };
❤️ 1
j
I understand how
==
mapping to
equals()
work, how data classes generate
equals()
, and how
equals()
work in general in the JVM world and how Kotlin translates that to the JVM world. What I don't understand is what
equals()
does in the compiled JS code. Because I can access properties of the object returned by
JSON.parse()
, and they are equal to the ones of the
expected
instance, but
equals()
fails
Oh great, thanks a lot
So it does check for prototype, and this is the part that fails in my case. Also, all the methods like
copy()
cannot be called on the object returned by
JSON.parse()
, but I only see the failure at runtime
👌 1
r
So that the reason why we recommend to use ktx.serialization to parse json
👍 1
j
Yes, I understand, I thought Kotlin would allow me to get away from JS, but JS still comes back to bite me 😄
r
Yes, that true. We are limited with platforms restrictions.
j
I guess I'll have to make the users provide the conversion function, but I'll provide built-in
kotlinx.serialization
support to simplify the API if they're willing to use it
r
Yes, that could be a good solutions I think
d
I had something working that did this for version 1.3.x not yet updated for 1.5, IF you are still interested I can give details (I know its an old thread)