javaandroidjsonkotlingson

Why am I getting the java.lang.UnsupportedOperationException when using Gson.asString?


The code is based on the following link: Link

I'm getting a run time exception:

java.lang.UnsupportedOperationException: JsonObject when running the following code:

data class Student(
    var name: String? = null,
    var address: String? = null) {
}

    class StudentDeserializer : JsonDeserializer<Student> {
    
        override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Student {
            json as JsonObject
    
            val name = json.asString
            val addressJson = json.get("address")
            val address = if (addressJson.isJsonObject) addressJson.toString() else addressJson.asString
            return Student(name, address)
        }
    }

the error is in:

    val name = json.asString

which is part of deserialize method that is probably being called when i'm writing:

        val student = gSon.fromJson<Student>(json2, Student::class.java)

When standing over this line and pressing the ctrl + b keyboard, it takes me to JsonElement class and I see the following method:

public String getAsString() {
  throw new UnsupportedOperationException(getClass().getSimpleName());
}

as we can see, there is only a throw statement here. But if we read the method documentation we will see that it is written there that the throw statement happen is only part of the method.

/**
* convenience method to get this element as a string value.
*
* @return get this element as a string value.
* @throws ClassCastException if the element is of not a {@link JsonPrimitive} and is not a valid
* string value.
* @throws IllegalStateException if the element is of the type {@link JsonArray} but contains
* more than a single element.
*/
public String getAsString() {
   ...

My questions are:

  1. Where is the full implementation?
  2. Why when I click on the ctrl + b in a code like: someJsonObject.asString , that I guess that it's a property, it takes me to method with the name: getAsString Does it mean that the get() implementation of asString property is: return getAsString(this)?

Solution

  • JsonElement::getAsString() only works for json primitives. Primitives are strings, numbers and booleans. Your json instance is a JsonObject and thus not a primitive which means there's no implementation for getAsString() which returns a meaningful value.

    From the tutorial, you actually should do json.get("name").asString.

    json.get("name") will return the name element which is of type JsonPrimitive -> a json primitive on which you can call getAsString().

    For further clarification, this is the content of json:

    {
       "name": "Mark",
       "address": {
            "city": "London",
            "post": "12000"
        }
     }
    

    and this is the content of json.get("name"):

    "Mark"
    

    which then will result as the string Mark when getAsString() / asString is called.


    Also see: GSON JsonElement.getAsString vs. JsonElement.toString?


    For your question about the source code. JsonPrimitive is a subclass of JsonObject. When you navigate, the IDE only knows that it must be a JsonObject, but at runtime, it will see that it's actually a primitive and calls JsonPrimitive::getAsString(). The source for that is here: https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/JsonPrimitive.java#L137-L151

    This is a result of gson utilizing inheritance. If you need further assistance to understand this, I recommend reading some beginners material in object-oriented programming for Java.