Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GSON exceptions - print field names that give errors when serialize a Nan

Tags:

java

nan

gson

I'm using Gson, ran into a problem serializing an object:

java.lang.IllegalArgumentException: NaN is not a valid double
    value as per JSON specification. To override this behavior, 
    use GsonBuilder.serializeSpecialFloatingPointValues() method.
    at com.google.gson.Gson.checkValidFloatingPoint(Gson.java:296)
    ...

Is there a way to have Gson print the class name/field name it is having a problem with? I can use the serializeSpecialFloatingPointValues() method as suggested, but ideally I'd like to understand where my objects have a NaN.

-------- Update ----------------

After painstakingly stepping through this, I think the cause is an uninitiatlized double. My setup looks like this:

public class Foo {
    private double price;
}

String jsonFromNet = ...;
Foo foo = Gson.fromJson(jsonFromNet);
Gson.toJson(foo, Foo.class); <-- throws the exception

The return json from my api is not including the attribute "price", so I guess the member variable "d" is left uninitialized. When I go to serialize it, gson throws the error.

If I give "price" an explicit value before serialization, or it happens to be in the api json response, everything works fine.

Also if I change "price" from a double to a float, it doesn't seem to mind the uninitialized state.

I'll look into GsonBuilder.serializeSpecialFloatingPointValues() now, I just wonder how the double gets serialized in this state. I'd be ok with a default value of zero or something.

Thanks

like image 700
user291701 Avatar asked Sep 20 '13 16:09

user291701


People also ask

Does Gson serialize static fields?

Gson can serialize static nested classes quite easily. NOTE: The above class B can not (by default) be serialized with Gson.

Does Gson ignore extra fields?

As you can see, Gson will ignore the unknown fields and simply match the fields that it's able to.

Does Gson ignore transient fields?

By default, GSON excludes transient and static fields from the serialization/deserialization process.

What does Gson toJson do?

Gson is the main actor class of Google Gson library. It provides functionalities to convert Java objects to matching JSON constructs and vice versa. Gson is first constructed using GsonBuilder and then toJson(Object) or fromJson(String, Class) methods are used to read/write JSON constructs.


2 Answers

The easiest way to get around this problem of Nan Parsing is to replace the default

Gson()

by

GsonBuilder().serializeSpecialFloatingPointValues().create()

Here is an example of Android Unit test class as an example (Kotlin)

import com.google.gson.GsonBuilder
import org.junit.Assert
import org.junit.Test

class NanGSONParsingTest {
    data class FloatContainer(val includedFloat: Float)

    @Test
    fun gsonCanHandleNanParsing() {
        val container = FloatContainer(Float.NaN)
        val gson = GsonBuilder().serializeSpecialFloatingPointValues().create()
        val jsonString = gson.toJson(container)//{"includedFloat":NaN}
        val parsedBackContainer = gson.fromJson<FloatContainer>(jsonString, FloatContainer::class.java)
        Assert.assertEquals(container,parsedBackContainer)
    }
}
like image 59
Stanislas Heili Avatar answered Oct 19 '22 18:10

Stanislas Heili


Strictly speaking the answer is no. I checked source code and, to my best knowledge, I cannot see a point where you can customize behavior getting what you need using Gson.

But when thinking about this answer, 4 ideas come to my mind to get anyway the info you need. The end goal is to spot the field at any cost, isn't it?.

  1. Download Gson code, put a breakpoint before the exception is thrown in checkValidFloatingPoint method and check value of boundField.name in com.google.gson.internal.bind.Adapter<T>.write. That's the offending field.
  2. Download Gson code and customize method of previous point to print out the offending field when the IllegalArgumentException is caught. (propose the patch ;) )
  3. Using serializeSpecialFloatingPointValues(), serialize to the JSON string, then using a regular expression search, find every Nan in string. Nearby there's the field name or the array field name you are looking for.
  4. Build your own class scanner that through reflection check every double field to inspect if value is null. Of course, in this case, Gson is not needed. It would be an interesting exercise, anyway.
like image 3
giampaolo Avatar answered Oct 19 '22 18:10

giampaolo