12

GSON を使用して、以下の Example クラスを JSON にシリアライズしたいと考えています。

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.LinkedHashMap;

public class Example
{
    private LinkedHashMap<String,Object> General;

    private static final String VERSION="Version";
    private static final String RANGE="Range";
    private static final String START_TIME="Start_Time";
    private static final String END_TIME="End_Time";

    public Example() {
        General = new LinkedHashMap<String,Object>();
        General.put(VERSION, "0.1");

        LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>();
        Range.put(START_TIME, "now");
        Range.put(END_TIME, "never");

        General.put(RANGE, Range);
    }

    public String toJSON() {
        Gson gson = new GsonBuilder().serializeNulls().create();
        return gson.toJson(this);
    }
}

次の出力が得られると予想していました。

{"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}}

しかし、関数を呼び出すとtoJSON()戻ります

{"General":{"Version":"0.1","Range":{}}}

GSON は MapRange内で MapをシリアライズできないようですGeneral。これは GSON の制限ですか、それともここで何か間違っていますか?

4

3 に答える 3

10

Nishant の答えが機能する理由は、Gson のデフォルト コンストラクターが、GsonBuilder を使用して手動で有効にする必要があるすべての種類のものをデフォルトで有効にするためです。

JavaDocsから:

デフォルト設定で Gson オブジェクトを構築します。デフォルト構成には、次の設定があります。

  • toJson メソッドによって生成される JSON はコンパクトな表現です。これは、不要な空白がすべて削除されることを意味します。この動作は GsonBuilder.setPrettyPrinting() で変更できます。
  • 生成された JSON では、null であるすべてのフィールドが省略されます。配列は順序付けられたリストであるため、配列内の null はそのまま保持されることに注意してください。さらに、フィールドが null ではないが、生成された JSON が空の場合、フィールドは保持されます。GsonBuilder.serializeNulls() を設定することで、Gson を構成して null 値をシリアル化できます。
  • Gson は、Enums、Map、java.net.URL、java.net.URI、java.util.Locale、java.util.Date、java.math.BigDecimal、および java.math.BigInteger クラスのデフォルトのシリアライズとデシリアライズを提供します。デフォルトの表現を変更したい場合は、GsonBuilder.registerTypeAdapter(Type, Object) を介して型アダプターを登録することで変更できます。
  • デフォルトの日付形式は、java.text.DateFormat.DEFAULT と同じです。この形式は、シリアル化中に日付のミリ秒部分を無視します。これを変更するには、GsonBuilder.setDateFormat(int) または GsonBuilder.setDateFormat(String) を呼び出します。
  • デフォルトでは、Gson は com.google.gson.annotations.Expose アノテーションを無視します。GsonBuilder.excludeFieldsWithoutExposeAnnotation() を使用して、Gson がこの注釈でマークされたフィールドのみをシリアル化/逆シリアル化できるようにすることができます。
  • デフォルトでは、Gson は com.google.gson.annotations.Since アノテーションを無視します。GsonBuilder.setVersion(double) を使用して、Gson がこの注釈を使用できるようにすることができます。
  • 出力 Json のデフォルトのフィールド命名ポリシーは Java と同じです。そのため、Java クラス フィールド versionNumber は、Json では "versionNumber@quot; として出力されます。同じ規則が、受信 Json を Java クラスにマッピングするために適用されます。このポリシーは、GsonBuilder.setFieldNamingPolicy(FieldNamingPolicy) で変更できます。
  • デフォルトでは、Gson はシリアライゼーションとデシリアライゼーションの考慮から一時フィールドまたは静的フィールドを除外します。この動作は、GsonBuilder.excludeFieldsWithModifiers(int) で変更できます。

OK、これで何が問題かわかりました。ご想像のとおり、デフォルトの Map シリアライザーは、ネストされたマップをサポートしていません。DefaultTypeAdapters からのこのソース スニペットでわかるように(特にデバッガーを使用してステップ実行する場合)、変数は不思議な理由でchildGenericType型に設定されているため、値の実行時の型は決して分析されません。java.lang.Object

私が推測する2つの解決策:

  1. 独自の Map シリアライザー/デシリアライザーを実装する
  2. 次のような、より複雑なバージョンのメソッドを使用します。

    public String toJSON(){
        final Gson gson = new Gson();
        final JsonElement jsonTree = gson.toJsonTree(General, Map.class);
        final JsonObject jsonObject = new JsonObject();
        jsonObject.add("General", jsonTree);
        return jsonObject.toString();
    }
    
于 2010-12-28T17:23:03.270 に答える
4

これを試して:

Gson gson = new Gson();
System.out.println(gson.toJson(General));

まだ解決策を探しているかどうかわかりませんが、これは私にとってはうまくいきます:

import java.util.LinkedHashMap;

import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

public class Example {
//  private static LinkedHashMap<String,Object> General;
    private ImmutableMap General;

    private static final String VERSION="Version";
    private static final String RANGE="Range";
    private static final String START_TIME="Start_Time";
    private static final String END_TIME="End_Time";

    public Example() {

        LinkedHashMap<String,String> Range = new LinkedHashMap<String, String>();
        Range.put(START_TIME, "now");
        Range.put(END_TIME, "never");

//        General.put(RANGE, Range);
        General = ImmutableMap.of(VERSION, "0.1", RANGE, Range);
    }

    public String toJSON() {
//        Gson gson = new GsonBuilder().serializeNulls().create();
          Gson gson = new Gson();
          return gson.toJson(this);
    }

}

戻り値: {"General":{"Version":"0.1","Range":{"Start_Time":"now","End_Time":"never"}}}


明らかに、代わりにImmutableMap.copyOf(your_hashmap)ここを使用できます

于 2010-12-28T17:05:18.570 に答える