81

文字列を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}
]
4

10 に答える 10

48

あなたは Gson に Strings から Objects へのマップのリストを探していることを伝えています。これは本質的に、オブジェクトの型に関して最善の推測をするように言っています。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 パーサーを使用することになります。

于 2013-03-19T19:04:55.623 に答える
7

私はパーティーに遅れましたが、私は自分でこれに出くわしました。私の場合、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 定義を使用するのではなくGson gs = new Gson();、整数を返すように Double.class シリアル化をオーバーライドしました。

私の場合、JSON 内に String と Integer がありますが、double がないため、これは問題になりません。

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);
}

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

于 2013-12-11T16:10:31.960 に答える
1

これは私にとってはうまくいきます。

ステップ 1: gson の ObjectTypeAdapter をプロジェクトにコピーし、パスは gson と同じにします。

com
  - xxx
    - xxx
com
  - google
    - gson
      - internal
        - bind
          ObjectTypeAdapter

ステップ 2: ObjectTypeAdapter を変更する

case NUMBER:
  return in.nextDouble();

に変更

case NUMBER:
  String number = in.nextString();
  try {
    return Long.valueOf(number);
  } catch (NumberFormatException e) {
    return Double.valueOf(number);
  }

わかった。 Gson は、プロジェクトで ObjectTypeAdapter を優先します。

于 2019-09-09T02:22:59.467 に答える
0

ジャクソンを使う

    public static Map<String, Object> jsonToMap(final String jsonString) {
    try {
        final ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.convertValue(objectMapper.readTree(jsonString), new TypeReference<Map<String, Object>>() {
        });
    } catch (final Exception e) {
        throw new InternalServiceException("lol");
    }
}
于 2021-12-16T10:23:54.887 に答える