javakotlingson

Deserialize numbers strictly in Gson


I want to make Gson deserializing numbers strictly, for example when Gson receives "123" and needs to deserialize it to Int, it must throw an exception and not automatically convert the string to number.

The goal:

val str1 = """{"key":"123"}"""
Gson().fromJson(str1, intMapType) // throws an Exception

val str2 = """{"key":123}"""
Gson().fromJson(str2, intMapType) // returns valid Map<String, Int>

I have already tried to register cursom type adapters for Int and String:

    private class StrictIntDeserializer : JsonDeserializer<Int> {
        override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): Int {
            if (!json.isJsonPrimitive || !json.asJsonPrimitive.isNumber) {
                throw JsonParseException("Expected Int but got: $json")
            }
            return json.asInt
        }
    }

    private class StrictStringDeserializer : JsonDeserializer<String> {
        override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): String {
            if (!json.isJsonPrimitive || !json.asJsonPrimitive.isString) {
                throw JsonParseException("Expected String but got: $json")
            }
            return json.asString
        }
    }


    private val gson = GsonBuilder()
        .registerTypeHierarchyAdapter(Int::class.java, StrictIntDeserializer())
        .registerTypeHierarchyAdapter(String::class.java, StrictStringDeserializer())
        .create()

But this does not work.


Solution

  • The problem was that Gson is a Java library and all the types it uses are Java primitives, not Kotlin (e.g. Kotlin's Int = Java's java.lang.Integer). So it was necessary to register adapters specifically for the Java equivalents of Kotlin classes:

    Instead of

    .registerTypeHierarchyAdapter(Int::class.java, StrictIntDeserializer())
    

    we need

    .registerTypeHierarchyAdapter(java.lang.Integer::class.java, StrictIntDeserializer())
    

    Otherwise Gson simply never accesses this adapter.