8

私はGsonを使用していますが、オブジェクトのシリアル化で問題が発生しました:

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)
    ...

Gsonに問題のあるクラス名/フィールド名を出力させる方法はありますか? 提案どおりにメソッドを使用できますserializeSpecialFloatingPointValues()が、理想的には、オブジェクトのどこに NaN があるかを理解したいと考えています。

- - - - アップデート - - - - - - - -

これを丹念に踏んだ後、原因は初期化されていないダブルだと思います。私のセットアップは次のようになります。

public class Foo {
    private double price;
}

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

私のAPIから返されたjsonには属性「価格」が含まれていないため、メンバー変数「d」は初期化されていないと思います。シリアル化しようとすると、gson がエラーをスローします。

シリアル化の前に「price」に明示的な値を指定した場合、またはたまたま api json 応答に含まれていた場合、すべて正常に動作します。

また、「価格」を double から float に変更しても、初期化されていない状態は問題ないようです。

ここで GsonBuilder.serializeSpecialFloatingPointValues() を調べます。この状態で double がどのようにシリアル化されるのか疑問に思います。デフォルト値はゼロか何かで問題ありません。

ありがとう

4

2 に答える 2

4

Nan Parsing のこの問題を回避する最も簡単な方法は、デフォルトを置き換えることです。

Gson()

GsonBuilder().serializeSpecialFloatingPointValues().create()

例としてAndroidユニットテストクラスの例を次に示します(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)
    }
}
于 2020-01-10T09:39:04.287 に答える
2

厳密に言えば、答えはノーです。ソース コードを確認しましたが、私の知る限り、Gson を使用して必要なものを取得する動作をカスタマイズできるポイントがわかりません。

しかし、この答えを考えると、とにかく必要な情報を得るために 4 つのアイデアが頭に浮かびます。最終的な目標は、何としてもフィールドを見つけることですよね。

  1. Gson コードをダウンロードし、メソッドで例外がスローされる前にブレークポイントを配置し、echeckValidFloatingPointの値を確認します。それが問題のフィールドです。boundField.namecom.google.gson.internal.bind.Adapter<T>.writ
  2. Gson コードをダウンロードし、前のポイントのメソッドをカスタマイズして、IllegalArgumentException がキャッチされたときに問題のあるフィールドを出力します。(パッチを提案してください;))
  3. を使用serializeSpecialFloatingPointValues()して、JSON 文字列にシリアル化し、正規表現検索を使用して、文字列内のすべての Nan を検索します。近くに、探しているフィールド名または配列フィールド名があります。
  4. リフレクションを介してすべての double フィールドをチェックし、値が null かどうかを検査する独自のクラス スキャナーを構築します。もちろん、この場合、Gson は必要ありません。とにかく、それは興味深い演習になるでしょう。
于 2013-09-20T20:52:15.853 に答える