web-dev-qa-db-ja.com

Gsonが整数を浮動小数点数として表現しないようにする方法

文字列をjsonに変換しようとすると、Gsonの動作がおかしくなります。以下のコードは、文字列ドラフトをJSON応答に変換します。 gsonがすべての整数値に '.0を追加するのを防ぐ方法はありますか?

ArrayList<Hashtable<String, Object>> responses;
Type ResponseList = new TypeToken<ArrayList<Hashtable<String, Object>>>() {}.getType();
responses = new Gson().fromJson(draft, ResponseList);

draft:
[ {"id":4077395,"field_id":242566,"body":""},
  {"id":4077398,"field_id":242569,"body":[[273019,0],[273020,1],[273021,0]]},
  {"id":4077399,"field_id":242570,"body":[[273022,0],[273023,1],[273024,0]]}
]

responses:
[ {id=4077395.0, body=, field_id=242566.0},
  {id=4077398.0, body=[[273019.0, 0.0], [273020.0, 1.0], [273021.0, 0.0]], field_id=242569.0},
  {id=4077399.0, body=[[273022.0, 0.0], [273023.0, 1.0], [273024.0, 0.0]], field_id=242570.0}
]
47
Mark Murphy

オブジェクトへの文字列のマップのリストを探していることをGsonに伝えています。これは、基本的に、オブジェクトのタイプに関して最良の推測を行うようにと言っています。 JSONは整数フィールドと浮動小数点フィールドを区別しない なので、Gsonは数値フィールドの場合はデフォルトでFloat/Doubleにする必要があります。

Gsonは、データを解析する方法を決定するために、挿入するオブジェクトのタイプを検査するために基本的に構築されています。ヒントを付けないと、うまく機能しません。 1つのオプションはカスタムJsonDeserializerを定義することですが、HashMapを使用せず(そしてHashtableを絶対に使用しないでください!)、代わりにGsonに予想されるデータのタイプに関する詳細情報を提供する方が良いでしょう。

class Response {
  int id;
  int field_id;
  ArrayList<ArrayList<Integer>> body; // or whatever type is most apropriate
}

responses = new Gson()
            .fromJson(draft, new TypeToken<ArrayList<Response>>(){}.getType());

繰り返しますが、Gsonの重要なポイントは、構造化データを構造化オブジェクトにシームレスに変換することです。オブジェクトのマップのリストのようなほぼ未定義の構造を作成するように要求する場合、Gsonのポイント全体を無効にしていることになり、さらに単純なJSONパーサーを使用する可能性があります。

35
dimo414

これは動作します:

 Gson gson = new GsonBuilder().
        registerTypeAdapter(Double.class,  new JsonSerializer<Double>() {   

    @Override
    public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
        if(src == src.longValue())
            return new JsonPrimitive(src.longValue());          
        return new JsonPrimitive(src);
    }
 }).create();
21
Martin Wickman

基本的に、この問題に対する完璧な答えはありません。すべての「ソリューション」は、一部のケースでのみ機能します。これはgsonチームに報告された問題であり、残念ながらgsonがJava javascriptではないことを認識していないように「javascriptには整数型がない」と主張しているようです。今日まで(2018年現在)、jacksonのような他のlibには、そのような簡単な修正にもかかわらず、このような問題はまったくありません。ファイルはgson/src/main/Java/com/google/gson/internal/bind/ObjectTypeAdapter.Java

case NUMBER:
   return in.nextDouble();
6
Leon

私はパーティーに遅れましたが、私は自分でこれに出くわしました。私の場合、ArrayListにInteger型を指定したくありませんでした-String型またはInteger型である可能性があるためです。

私の解決策は次のとおりです。

_GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Double.class,  new JsonSerializer<Double>() {

    public JsonElement serialize(Double src, Type typeOfSrc,
                JsonSerializationContext context) {
            Integer value = (int)Math.round(src);
            return new JsonPrimitive(value);
        }
    });

Gson gs = gsonBuilder.create();
_

Gson gs = new Gson();でデフォルトのGson定義を使用するのではなく、Double.classシリアル化をオーバーライドして整数を返しました。

私の場合、JSONには文字列と整数がありますが、倍精度はありませんので、これは問題になりません。

Double値またはfloat値が必要な場合、各データ型に固有の属性の値をテストし、適切な値を返すロジックを追加できると思います。何かのようなもの

_if(/*source has a decimal point*/){
  return new JsonPrimitive(src); 
} else if (/* source has some attribute of a Float */){
  Float value = /*convert the src value from double to a Float */;
  return new JsonPrimitive(value);
} else {
  //it looks like an integer
  Integer value = (int)Math.round(src);
  return new JsonPrimitive(value);
}
_

これらのデータ型をテストする方法や頭の外で変換する方法はわかりませんが、これで正しい道に進むはずです。

5
Steve Kallestad