2013-06-13 9 views
13

私は内部に任意の値を持つjsonオブジェクトを持っています。そして私はそれをMap内で非直列化したい。整数を複素数に変換する以外はすべて問題ありません。例を参照してください。これにGson。整数を整数として逆数化するのではなく、doubleとしてではなく

{"id":1, "inner_obj":{"key":"value","num":666,"map":{"key":"value"}}} 

デシリアライズ(map.toString()):

{id=1.0, inner_obj={key=value, num=666.0, map={key=value}}} 

ダブルスとして整数ではなくて "ID" と "NUM" をデシリアライズするためにいくつかの簡単な方法はありますか?

+0

また、[この回答を参照してください](http://stackoverflow.com/a/43346123/179864)私は同様の質問を書いた;キャッチは、データを 'Object'として解析し、必要なものにキャストする必要があるということです。 – aditsu

+0

ジャクソンはマップの種類を検出するのにはるかに優れた仕事をしており、GSONよりも設定がはるかに簡単です:https://github.com/FasterXML/jackson-databind –

+0

Gsonの実装について明示的に質問されています。質問に固執してください。 – Megakoresh

答えて

7

JSONには整数型はありません。 1と1.0は同じです。あなたのコードで1.0から1まで解析する必要があります。または、JSONをいくつかのVOクラスにマップし、GSONがあなたが探しているものを理解できるように、クラスのフィールドのタイプを明示的に定義する必要があります。

+4

しかし、javaには整数と倍精度があります。また、Integerフィールド "num"を持つクラスを持つ場合、{"num":1}を直列化解除するのは簡単ですが、gsonがjsonをMap に逆シリアル化してDoubleを使用することが望ましい場合。だから私はこのアプローチを無効にする方法を模索している。 – Moses

+0

@MosesはMap を定義します –

+3

マップには整数だけでなく、 – Moses

2

JSONには単一のNumber型しかないため、パーサーが自動的にどの型に変換するかを指定する方法はありません。

あなたは強く型付けされたオブジェクトグラフを使用しない場合は、JsonElement種類の使用を検討してください:

JsonObject root = new Gson().fromJson(json, JsonObject.class); 
int num = root.getAsJsonObject("inner_obj").get("num").getAsInt(); 
1

それは私のコードですが

private static class MapDeserializer implements JsonDeserializer<Map<String,Object>> { 
    public Map<String,Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     Map<String,Object> m = new LinkedHashMap<String, Object>(); 
     JsonObject jo = json.getAsJsonObject(); 
     for (Entry<String, JsonElement> mx : jo.entrySet()){ 
      String key = mx.getKey(); 
      JsonElement v = mx.getValue(); 
      if(v.isJsonArray()){ 
       m.put(key, g.fromJson(v, List.class)); 
      }else if(v.isJsonPrimitive()){ 
       Number num = null; 
        try { 
         num = NumberFormat.getInstance().parse(v.getAsString()); 
        } catch (Exception e) { 
         e.printStackTrace(); 
        } 
       m.put(key,num); 
      }else if(v.isJsonObject()){ 
       m.put(key,g.fromJson(v, Map.class));  
      } 

     } 
     return m; 
    } 
} 

private static class ListDeserializer implements JsonDeserializer<List<Object>> { 
    public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     List<Object> m = new ArrayList<Object>(); 
     JsonArray arr = json.getAsJsonArray(); 
     for (JsonElement jsonElement : arr) { 
      if(jsonElement.isJsonObject()){ 
       m.add(g.fromJson(jsonElement, Map.class)); 
      }else if(jsonElement.isJsonArray()){ 
       m.add(g.fromJson(jsonElement, List.class)); 
      }else if(jsonElement.isJsonPrimitive()){ 
       Number num = null; 
       try { 
        num = NumberFormat.getInstance().parse(jsonElement.getAsString()); 
       } catch (Exception e) { 
       } 
       m.add(num); 
      } 
     } 
     return m; 
    } 
} 

private static Gson g = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserializer()).registerTypeAdapter(List.class, new ListDeserializer()).setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create(); 
1

は、ネストされた地図への解決策を探して 上記の「異種」は、些細な使用事例で実際に助けられた最初の答えでした。

私は、以下の更新されたコードを参照してください、また、文字列やブール値のための一般的な構文解析機能を提供するソリューションを更新のみ取り扱い数を上記の溶液ので:ここ

private static class MapDeserializer implements JsonDeserializer<Map<String, Object>> { 

    public Map<String, Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     Map<String, Object> m = new LinkedHashMap<String, Object>(); 
     JsonObject jo = json.getAsJsonObject(); 
     for (Entry<String, JsonElement> mx : jo.entrySet()) { 
      String key = mx.getKey(); 
      JsonElement v = mx.getValue(); 
      if (v.isJsonArray()) { 
       m.put(key, g.fromJson(v, List.class)); 
      } else if (v.isJsonPrimitive()) { 
       Number num = null; 
       ParsePosition position=new ParsePosition(0); 
       String vString=v.getAsString(); 
       try { 
        num = NumberFormat.getInstance(Locale.ROOT).parse(vString,position); 
       } catch (Exception e) { 
       } 
       //Check if the position corresponds to the length of the string 
       if(position.getErrorIndex() < 0 && vString.length() == position.getIndex()) { 
        if (num != null) { 
        m.put(key, num); 
        continue; 
        } 
       } 
       JsonPrimitive prim = v.getAsJsonPrimitive(); 
       if (prim.isBoolean()) { 
        m.put(key, prim.getAsBoolean()); 
       } else if (prim.isString()) { 
        m.put(key, prim.getAsString()); 
       } else { 
        m.put(key, null); 
       } 

      } else if (v.isJsonObject()) { 
       m.put(key, g.fromJson(v, Map.class)); 
      } 

     } 
     return m; 
    } 
} 

private static class ListDeserializer implements JsonDeserializer<List<Object>> { 

    public List<Object> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     List<Object> m = new ArrayList<Object>(); 
     JsonArray arr = json.getAsJsonArray(); 
     for (JsonElement jsonElement : arr) { 
      if (jsonElement.isJsonObject()) { 
       m.add(g.fromJson(jsonElement, Map.class)); 
      } else if (jsonElement.isJsonArray()) { 
       m.add(g.fromJson(jsonElement, List.class)); 
      } else if (jsonElement.isJsonPrimitive()) { 
       Number num = null; 
       try { 
        num = NumberFormat.getInstance().parse(jsonElement.getAsString()); 
       } catch (Exception e) { 
       } 
       if (num != null) { 
        m.add(num); 
        continue; 
       } 
       JsonPrimitive prim = jsonElement.getAsJsonPrimitive(); 
       if (prim.isBoolean()) { 
        m.add(prim.getAsBoolean()); 
       } else if (prim.isString()) { 
        m.add(prim.getAsString()); 
       } else { 
        m.add(null); 
       } 
      } 
     } 
     return m; 
    } 
} 

private static Gson g = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserializer()).registerTypeAdapter(List.class, new ListDeserializer()).setDateFormat("yyyy-MM-dd HH:mm:ss").create(); 
+0

これは私を助けました!私は小さなバグを指摘したい。 ListDeserializerでは、try {}ブロック内の "m.add(num)"を削除する必要があります。なぜなら、try/catchの後に追加されるからです。コードをそのまま使用すると、各数値が結果に2回追加されます。 – peanutman

+0

ありがとうございます、今の例を更新しました。 –

+0

私はあなたがgsonの静的インスタンスの必要性を避けるためにg.fromJson(...)の呼び出しをcontext.deserialize(...)に置き換えることができると思います(少なくともgson 2.6.2では私にとってはうまくいきます) – David

0

は私の例では、最初の部分は定義ですint型のフィールドを持つクラスの

import com.google.api.client.util.Key; 

public class Folder { 

    public static final String FIELD_NAME_CHILD_COUNT = "childCount"; 

    @Key(FIELD_NAME_CHILD_COUNT) 
    public final int childCount; 

    public Folder(int aChildCount) { 
     childCount = aChildCount; 
    } 
} 

次に、Gsonの数値型をJavaオブジェクトに変換するTypeAdapter。

GsonBuilder gsb = new GsonBuilder(); 

gsb.registerTypeAdapter(Folder.class, new JsonDeserializer<Folder>() { 

      @Override 
      public Folder deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 

       int value = json.getAsJsonObject().get("childCount").getAsJsonPrimitive().getAsInt(); 

       return new Folder(value); 

      } 
     } 
); 

第3部はテストデータであり、動作します。

String gsonData = new String("\"folder\":{\"childCount\":0}"); 
0

可能なClassCastExceptionを回避するには、最初にNumberにキャストする方がよいでしょう。次のコードではmapがJSONからMapとして非対応になりました。

int numberOfPages = ((Number) map.get("number_of_pages")).intValue(); 
関連する問題