2

i am programming a kotlin websocket and want to send dtos transformed to json with gson. so i wrote a kind of wrapper dto that contains the real dto and some additional information about the dto, like the type of it. this is my wrapper dto

class WrapperDto <T : AbstractDto> {
    var type = ""
    var action = ""
    var dto : T = AbstractDto() as T
}

and this is one of the dtos that it can contain:

class Person : AbstractDto() {
    var firstName = ""
    var familyName = ""
}

here for test reasons i try to tansform it to json and back again:

    val wrapperDto2 = WrapperDto<Person>()
    wrapperDto2.type = Person::class.simpleName!!;
    wrapperDto2.action = "add"
    val person = Person()
    person.firstName = "Richard"
    person.familyName = "Lederer"
    wrapperDto2.dto = person;

    val gson1 = Gson()
    val toJson = gson1.toJson(wrapperDto2)
    println("to json: "  + toJson)
    val fromJson = gson1.fromJson(toJson, wrapperDto2::class.java)
    println("from json: " + fromJson)

the last println is never called and i get following error message:

java.lang.IllegalArgumentException: Can not set at.richardlederer.contactmanager.dto.AbstractDto field at.richardlederer.contactmanager.dto.WrapperDto.dto to com.google.gson.internal.LinkedTreeMap
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:81)

how can i solve this problem?

richard
  • 684
  • 1
  • 13
  • 34

1 Answers1

3

It is due to type erasure of generics. You need to use TokenType to retrieve the type information at runtime.

val fromJson = gson1.fromJson<WrapperDto<Person>>(toJson, object: TypeToken<WrapperDto<Person>>() {}.type)

You may also create an extension function like this:

inline fun <reified T> fromJson(json: String): T = Gson().fromJson<T>(json, object: TypeToken<T>() {}.type)

So, you can call fromJson this way:

val fromJson = fromJson<WrapperDto<Person>>(toJson)
//Or
val fromJson: WrapperDto<Person> = fromJson(toJson)    //Type inferred
BakaWaii
  • 5,602
  • 3
  • 23
  • 36