skip to Main Content

I am using Gson to parse JSON. What surprised me is that if I have a field of type String in my POJO class and I have a number in JSON it’s parsed correctly without throwing an exception. Similarly the other way – I wrote this test to illustrate:

    data class Parsed(
        val testString: String,
        val testNumber: Int,
    )

    @Test
    fun `test gson type parsing`() {
        val gson = Gson()

        val json = "{ "testString" : 1, "testNumber" : "1"}"

        val parsed = gson.fromJson(json, Parsed::class.java)

        assertThat(parsed.testString).isEqualTo("1") // passes
        assertThat(parsed.testNumber).isEqualTo(1) // passes
        // expected an exception because number is parsed into a string field and string is parsed into number
    }

Is there any way to change this behavior? (Only found setLenient() on GsonBuilder but it’s not related to this)

2

Answers


  1. I don’t think you can turn of type coercion in gson. Your best bet would probably be to write a custom deserializer that prevents this.

    That being said, contemplate not using gson in kotlin code as it completely circumvents the null safety of the language. You are better of using a serialization framework that is kotlin aware, such as jackson (with kotlin plugin) or kotlinx-serialization.

    Aditionally it seems like jackson allows to turn this specific type coercion off, using this flag: https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/MapperFeature.html#ALLOW_COERCION_OF_SCALARS

    Kotlinx-serialization seems to not have such an option: https://github.com/Kotlin/kotlinx.serialization/issues/1042

    Login or Signup to reply.
  2. There are (at least) the following options:

    • Subclass JsonReader and override its number reading methods (such as nextInt()) and nextString() to first call peek() and verify that the JSON data has the correct type.

      Disadvantages:

      • In theory future Gson versions could add more number reading methods to JsonReader
      • There might be type adapters for which it is acceptable to perform this conversion between numbers and strings; however by subclassing JsonReader you would break these adapters because your subclass cannot tell the adapters apart
      • Has no effect if a type adapter first deserializes the JSON data as JsonElement (and possibly performs modifications or checks on it) and then deserializes that as desired type
    • Implement a custom TypeAdapterFactory which wraps adapters for String and Number and subclasses to first call JsonReader.peek() to make sure the JSON data has the correct type

      Disadvantages:

      • It would have to cover all cases where you don’t want this type conversion; for example you might also want to cover the built-in StringBuilder adapter

    Since you are concerned with strict validation, it might be good to point out that Gson by default performs lenient parsing (see Troubleshooting Guide), and even in its ‘strict mode’ it slightly deviates from the JSON specification, see this issue.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search