Skip to content Skip to sidebar Skip to footer

How To Invoke Default Deserialize With Gson

I get a json that has 'field' field. If the 'field' has data, then there is an OBJECT that has many (about 20) other fields that are also objects. I can deserialize them without a

Solution 1:

Try using GSON >= 2.2.1 and look for the TypeAdapterFactory class.

This will give you the ability to inspect the Object before you deserialize it and apply custom code while avoiding recursions.

Here is an example of the getDelegateAdapter you can use.

Solution 2:

publicclassExtrasAdapterimplementsJsonDeserializer<Extras> {
@Overridepublic Extras deserialize(JsonElement json, Type typeOf, 
              JsonDeserializationContext context)throws JsonParseException {
    try {
        JsonObjectjsonObject= json.getAsJsonObject();
        returnnewGson().fromJson(jsonObject , Extras.class); // default deserialization

    } catch (IllegalStateException e) {
        returnnull;
    }
}

Solution 3:

For anyone coming in late, you don't need to implement a TypeAdapter to solve this problem, although doing so is a perfectly valid solution.

The answer to this problem is actually in the original question:

publicclassExtrasAdapterimplementsJsonDeserializer<Extras> {

@Overridepublic Extras deserialize(JsonElement json, Type typeOf, 
          JsonDeserializationContext context)throws JsonParseException {
    try {
        JsonObjectjsonObject= json.getAsJsonObject();
        // deserialize normally// the following does not work, as it makes recursive calls // to the same function //return context.deserialize(jsonObject, new TypeToken<Object>(){}.getType());
    } catch (IllegalStateException e) {
        returnnull;
    }
}

The commented out

return context.deserialize(jsonObject, newTypeToken<Object>(){}.getType());

is almost the solution. The issue is two fold. First, jsonObject is the exact object passed into this function originally.

JsonObjectjsonObject= json.getAsJsonObject();

So passing it into context.deserialize() will create recursion, and eventually OOM. The solution here is to parse out the objects inside of jsonObject.

This leads us to the second problem, which is that there are two things getting mixed here. "Extras" is an object type, presumably with a concrete class backing it (and possibly an empty array). "Extra" is a map. Attempting to parse an "Extra" as an "Extras" isn't going to work. To that end, I would suggest the following definition of "Extras":

publicclassExtras {
    Map<String, Map<String, String>> extras;
    // you could also create a concrete class for "Extra"//and have this be a Map<String, Extra>
}

In which case the problem becomes trivial for solving with context.deserialize.

As I stated above, a TypeAdatper is a perfectly valid solution for this problem. I just believe that it's more than you need.

Solution 4:

I created an alternative TypeAdapter based on my needs to let empty arrays deserialize to null, but only for the classes I specify:

classEmptyArraysAsNullTypeAdapterFactory@Injectconstructor() : TypeAdapterFactory {

companionobject {

    // Add classes here as neededprivateval classesAllowedEmptyArrayAsNull = arrayOf(Location::class.java,
                                                         Results::class.java)

    privatefunisAllowedClass(rawType: Class<*>): Boolean {
        return classesAllowedEmptyArrayAsNull.find { rawType.isAssignableFrom(it) } != null
    }
}

overridefun<T>create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
    val delegate = gson.getDelegateAdapter(this, type)

    val rawType = type.rawType as Class<T>

    returnobject : TypeAdapter<T>() {

        overridefunwrite(out: JsonWriter, value: T?) {
            delegate.write(out, value)
        }

        overridefunread(reader: JsonReader): T? {
            returnif (reader.peek() === JsonToken.BEGIN_ARRAY && isAllowedClass(rawType)) {
                reader.beginArray()

                // If the array is empty, assume it is signifying nullif (!reader.hasNext()) {
                    reader.endArray()
                    null
                } else {
                    throw JsonParseException("Not expecting a non-empty array when deserializing: ${type.rawType.name}")
                }

            } else {
                delegate.read(reader)
            }
        }
    }
}

}

Post a Comment for "How To Invoke Default Deserialize With Gson"