2010-12-28 23 views
11

以下の例のクラスをGSONを使用してJSONにシリアル化したいとします。GSONを使用してマップのマップをシリアル化する方法は?

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

私は、次のような出力を得ることが期待:GSONが地図General内の地図Rangeをシリアル化することができないようです

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

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

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

を。これはGSONの限界ですか、私はここで何か間違っていますか?

+2

正しいとデフォルトのマップシリアライザはネストされたマップを処理しません、私はGSONチームのバグレポートを提出します。それは私にとって本当に悪いデフォルトのようです。少なくとも静かに内容を飲み込むのではなく、例外を投げるべきです。 – StaxMan

+0

+1 @StaxManそれはそうです。私は以前これを見て、いくつかの回避策を考え出しました。これを行う方法があれば、それは参考になるでしょう。 – Nishant

答えて

8

Gsonのデフォルトコンストラクタは、あなたがそれ以外の場合は、手動でenably GsonBuilderを使用しなければならないデフォルトあたりのもののすべての種類を可能にするのでNishant's answer作品がある理由。 JavaDocsから

:デフォルトの設定でGsonオブジェクトを構築し

。デフォルトの設定は次のとおりです。

  • toJsonメソッドで生成されたJSONはコンパクトな表現です。つまり、不要な空白がすべて削除されます。この動作は、GsonBuilder.setPrettyPrinting()で変更できます。
  • 生成されたJSONは、nullのすべてのフィールドを省略します。配列は順序付きリストであるため、配列内のnullはそのまま保持されることに注意してください。さらに、フィールドがnullではなく、生成されたJSONが空の場合、フィールドは保持されます。 GsonBuilder.serializeNulls()を設定することによって、null値をシリアル化するようにGsonを設定できます。
  • Gsonは、Enum、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はcom.google.gson.annotationsを無視します。アノテーションから。このアノテーションをGsonBuilder.setVersion(double)を使ってGsonに使用させることができます。
  • 出力Jsonのデフォルトのフィールド命名ポリシーは、Javaの場合と同じです。したがって、JavaクラスフィールドversionNumberは、Jsonでは "versionNumber @ quot;として出力されます。着信JsonをJavaクラスにマッピングする場合、同じルールが適用されます。このポリシーはGsonBuilder.setFieldNamingPolicy(FieldNamingPolicy)で変更できます。
  • Byデフォルトで、Gsonは直列化および非直列化のための考慮から一時的または静的フィールドを除外します。あなたはGsonBuilder.excludeFieldsWithModifiers(int型)を介してこの動作を変更することができます。

OK、今私は問題が何であるかを参照してください。デフォルトのマップシリアライザは、期待どおり、ネストされたマップをサポートしていません。this source snippet from DefaultTypeAdapters(特にデバッガを使用している場合)、変数childGenericTypeはいくつかの不思議な理由によりタイプjava.lang.Objectに設定されているため、値のランタイムタイプは分析されません。

2つの溶液、私は推測する:

  1. Implement your own Map serializer/deserializer
  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(); 
    } 
    
+0

申し訳ありませんが、Nishantの答えに対する私の最初のコメントは間違っていました。彼の提案は私にとっては完全には機能しません。 – asmaier

+0

@asmaier ok、私の答えにいくつかの内容を追加 –

+0

、変わった場合、LinkedHashMapをImmutableMapに置き換えてもうまくいきます。 – Nishant

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

} 

戻ります:{ "一般":{」バージョン ":" 0.1 "、"範囲 ":{"開始時間 ":"今 "、"終了時間 ":"決して "}}}


は、明らかに、あなたは使うことができImmutableMap.copyOf(your_hashmap)here代わり

+1

それは動作しますが、なぜですか?また、少し不便です。私のクラスの例にマップを追加したい場合は、 'String out = gson.toJson(this.General);のような関数toJSON()を書く必要があります。 out + = gson.toJson(this.Map2); out + = gson.toJson(this.map3); ...返す; – asmaier

+0

仲間がわからない。私はこの問題を抱えていたので、私はこのルートを降りました。私はこれが原因だと思ったhttp://sites.google.com/site/gson/gson-user-guide#TOC-Nested-Classes-including-Inner-Clas – Nishant

+0

申し訳ありませんが、私の最初のコメントは間違っていて編集できませんそれはもはや。 '' Start '' '' '' '' '' '' '' '' '」を返します。 'gson.toJson(General) } '。しかし、私は '{" General ":{" Version ":" 0.1 "、....'あなたのソリューションは私のために完全には機能しません。 – asmaier

1

シンプルな選択肢がするだろうGSONの代わりにJacksonを使用すると、入れ子にされたマップのシリアル化はそのままの状態で動作します:

LinkedHashMap<String, Object> general; 
    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); 

    // Serialize the map to json using Jackson 
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    new org.codehaus.jackson.map.ObjectMapper().writer().writeValue(os, 
      general);  
    String json = os.toString(); 
    os.close(); 

    System.out.println(json); 

出力:

{ "バージョン": "0.1"、 "範囲":{ "START_TIME": "今"、 "END_TIME": "決して"}}他の回答がある場合は

関連する問題