2017-02-07 7 views
2

私のJava Webアプリケーションでgsonを使用しています。私のapiモデルをjsonオブジェクトにシリアル化しています。
バージョン管理されたモデルにsuccesfuly注釈を使用しましたが、私はEnumオブジェクトをシリアル化することに失敗しています。この列挙型を使用していますHashtableか、別のPOJOをシリアル化しようとするとAction.classGson Enumのシリアル化

public enum Action { 

    @SerializedName("create") CREATE, 
    @SerializedName("read") READ; 

} 

は、私は、大文字の文字列を取得します。

... 
Gson gson = new GsonBuilder.create(); 
Hashtable<Action, String> table = new Hashtable<>(); 
table.put(Action.CREATE, ""); 
gson.toJson(table) // => { "CREATE" : "" } instead of { "create" : "" } 
... 

私は間違っていますか?あなたが本当にドロドロ場合、それはマップのために働くし、可能な場合は、あなたのデータ交換モデルを変更することを示唆していない理由を説明(MapTypeAdapterFactory@SerializedName -awareではないことを)あなたの質問へのコメントのほかに

+1

フィールドの値が列挙型の場合はどうなりますか? (また、 'Hashtable'はほとんど新しいコードで使われるべきではなく、おそらく' HashMap'が必要です。) – chrylis

+0

別のクラスのフィールドとしてenumを使うと動作します。シリアル化関数は、列挙型を小文字に変換します。 Btw、私は既存のコードで作業しているので、ハッシュマップをハッシュマップに変更するとコードが壊れる可能性があるので、今は触れません。 – itaied

+1

マップキーとして '@ SerializedName'を使うことに特有の問題があるようですね? – chrylis

答えて

1

、カスタムJsonSerializerを使用することができますMapまたはHashtableなどの使用データの袋:タイプのトークンがより正確にシリアライズ可能な列挙型を対象とし、内部のシリアル化された名前のマッピングをキャッシュするために使用されていることを

private static final TypeToken<?> actionToUnknownHashtableTypeToken = new TypeToken<Hashtable<Action, ?>>() { 
}; 

注:

final Gson gson = new GsonBuilder() 
     .registerTypeAdapter(actionToUnknownHashtableTypeToken.getType(), getSerializedNameEnumHashtableJsonSerializer(Action.class)) 
     .create(); 
final Hashtable<Action, String> table = new Hashtable<>(); 
table.put(CREATE, "item"); 
out.println(gson.toJson(table, actionToUnknownHashtableTypeToken.getType())); 

toJsonメソッドの使用にも注意してください。したがって、それぞれ特定の列挙型は、@SerializedName - 認識することができます別々に登録することができます。そして、シリアライザ自身:

final class SerializedNameEnumHashtableJsonSerializer<K extends Enum<K>, V> 
     implements JsonSerializer<Hashtable<K, V>> { 

    private final Map<K, String> serializedNames; 

    private SerializedNameEnumHashtableJsonSerializer(final Map<K, String> serializedNames) { 
     this.serializedNames = serializedNames; 
    } 

    static <K extends Enum<K>, V> JsonSerializer<Hashtable<K, V>> getSerializedNameEnumHashtableJsonSerializer(final Class<K> enumClass) { 
     try { 
      final Map<K, String> serializedNames = new HashMap<>(); 
      for (final K enumConstant : enumClass.getEnumConstants()) { 
       final String enumName = enumConstant.name(); 
       final Field field = enumClass.getField(enumName); 
       final SerializedName serializedName = field.getAnnotation(SerializedName.class); 
       if (serializedName != null) { 
        serializedNames.put(enumConstant, serializedName.value()); 
       } 
      } 
      return new SerializedNameEnumHashtableJsonSerializer<>(unmodifiableMap(serializedNames)); 
     } catch (final NoSuchFieldException ex) { 
      throw new AssertionError(ex); 
     } 
    } 

    @Override 
    public JsonElement serialize(final Hashtable<K, V> hashtable, final Type type, final JsonSerializationContext context) { 
     final JsonObject jsonObject = new JsonObject(); 
     for (final Entry<K, V> e : hashtable.entrySet()) { 
      final K key = e.getKey(); 
      final String nameCandidate = serializedNames.get(key); 
      final String serializedName = nameCandidate != null ? nameCandidate : key.name(); 
      jsonObject.add(serializedName, context.serialize(e.getValue())); 
     } 
     return jsonObject; 
    } 

} 

はまた、上記のシリアライザのみSerializedName.valueを処理し、SerializedName.alternateのために気にしないことに注意してください。出力:

は{「作成」:「アイテム」}これはキーのみで動作し、シリアライズマップ内の値で列挙型のために表示されることがあり@SerializedNameに影響を与えないこと

注意を。上記の例は、任意の列挙型を自動的に処理するために再加工することもでき、そのようなマップまたはハッシュテーブルをGsonBuilderに登録する必要はありません(serializeメソッドではおそらくキャッシング機構を使用して@SerializedNameのアノテーションを再解析する必要があります)あなたのためのデザインの選択。

関連する問題