12

GSON を使用してシリアル化したいと思います。

"starterItems": {
    "Appeltaart": 3,
    "Soap_50": 3
}

...グアバにImmutableMap

private ImmutableMap<String,Integer> starterItems;

通常の GSON マップ解析を使用して、次のように結果の不変コピーを作成するだけだと思いました。

    gb.registerTypeAdapter(ImmutableMap.class, new JsonDeserializer<ImmutableMap>() {
        @SuppressWarnings("unchecked")
        @Override public ImmutableMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            return ImmutableMap.copyOf((Map) context.deserialize(json, Map.class));
        }
    });

しかしさすがにこれは単純すぎる(型情報がない)。エラーが発生します:

com.google.gson.JsonParseException: The JsonDeserializer MapTypeAdapter failed to deserialized json object {"Appeltaart":3,"Soap_50":3} given the type interface java.util.Map

やりたいことはできますか?

4

6 に答える 6

8

適切な型を含むマップを作成するために型パラメーターを維持する必要があるため、それほど単純ではありません。これを行うには、 を使用して、完全に指定された を使用して、TypeAdapterFactoryそこで delegate を要求できます。TypeAdapterTypeToken

public class ImmutableMapTypeAdapterFactory implements TypeAdapterFactory {

    public static final ImmutableMapTypeAdapterFactory INSTANCE = new ImmutableMapTypeAdapterFactory();

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        if (!ImmutableMap.class.isAssignableFrom(type.getRawType())) {
            return null;
        }
        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            @Override
            @SuppressWarnings("unchecked")
            public T read(JsonReader in) throws IOException {
                return (T) ImmutableMap.copyOf((Map) delegate.read(in));
            }
        };
    }
}

ここで別の問題が発生します。デフォルトの GSONMapTypeAdapterFactoryは のインスタンスを作成しImmutableMap、それを変更しようとします。これは明らかにうまくいきません。TypeToken<HashMap<K, V>>からを作成する必要がありますが、TypeToken<ImmutableMap<K, V>>正直なところ、それを行う方法がわかりません。代わりに、 anが実際に必要なときに、 an を使用しInstanceCreatorて GSON をだまして a を構築させることができます。HashMapImmutableMap

public static <K,V> InstanceCreator<Map<K, V>> newCreator() {
    return new InstanceCreator<Map<K, V>>() {
        @Override
        public Map<K, V> createInstance(Type type) {
            return new HashMap<K, V>();
        }
    };
}

明らかに、TypeAdapterFactory と InstanceCreator の両方を登録する必要があります。

GsonBuilder b = new GsonBuilder();
b.registerTypeAdapterFactory(new ImmutableMapTypeAdapterFactory());
b.registerTypeAdapter(ImmutableMap.class, ImmutableMapTypeAdapterFactory.newCreator());
于 2012-11-29T10:49:01.730 に答える
1

必要な型情報を追加すると機能します。

gb.registerTypeAdapter(
    new TypeToken<ImmutableMap<String,Integer>>(){}.getType(), 
    new JsonDeserializer<ImmutableMap>() {
            @SuppressWarnings("unchecked")
            @Override
            public ImmutableMap deserialize(JsonElement json, 
                                            Type typeOfT, 
                                            JsonDeserializationContext context)
            throws JsonParseException {
                return ImmutableMap.copyOf(
                    (Map) context.deserialize(json, new TypeToken<Map<String,Integer>>(){}.getType()));
            }
        });

ただし、そのためには、サポートする必要があるすべての種類のマップに対してそのコードを複製する必要があります。その点で、フラビオの答えはおそらくより一般的なものです。

于 2012-11-29T12:36:30.387 に答える
1

Just は Flavio の回答に基づいていますが、簡単な 2 ステップのコピー アンド ペースト形式です。

  1. GsonUtilsクラスを作成します(以下に含めました)

  2. new Gson()のすべてのインスタンスをに置き換えますGsonUtils.get()

GsonUtils.java :

package com.innomatixdata.busscan.utils;

import android.support.annotation.Nullable;

import com.google.common.collect.ImmutableMap;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.InstanceCreator;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.IOException;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;

/**
 * Use this class to get an instance of Gson that is configured for this application.
 */
public class GsonUtils {

    private static final GsonBuilder GSON_BUILDER = new GsonBuilder();

    static {
        GSON_BUILDER.registerTypeAdapterFactory(new ImmutableMapTypeAdapterFactory());
        GSON_BUILDER.registerTypeAdapter(ImmutableMap.class, ImmutableMapTypeAdapterFactory.newCreator());
    }

    public static Gson get() {
        return GSON_BUILDER.create();
    }

    public static class ImmutableMapTypeAdapterFactory implements TypeAdapterFactory {

        @Nullable
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
            if (!ImmutableMap.class.isAssignableFrom(type.getRawType())) {
                return null;
            }
            final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
            return new TypeAdapter<T>() {
                @Override
                public void write(JsonWriter out, T value) throws IOException {
                    delegate.write(out, value);
                }

                @Override
                @SuppressWarnings("unchecked")
                public T read(JsonReader in) throws IOException {
                    return (T) ImmutableMap.copyOf((Map) delegate.read(in));
                }
            };
        }

        public static <K,V> InstanceCreator<Map<K, V>> newCreator() {
            return new InstanceCreator<Map<K, V>>() {
                @Override
                public Map<K, V> createInstance(Type type) {
                    return new HashMap<K, V>();
                }
            };
        }
    }
}
于 2015-11-20T20:51:05.900 に答える