考慮以下通用Pair
類:
final class Pair<K, V> {
@SerializedName("Key")
private final K key = null;
@SerializedName("Value")
private final V value = null;
private Pair() { }
K getKey() { return key; }
V getValue() { return value; }
}
GSON支持SerializedName
註釋,允許名稱替換,從而讓保持Java的命名約定的字段名。由於這是一個傳入的DTO類,因此它確信沒有代碼會自行實例化它,並且不提供公共構造函數。 GSON可以在沒有構造函數和訪問器的情況下工作,所以這個類可以是純粹只讀的。
常規字典JSON解串器
解串器下面可以不知曉具體類型的反序列化。主要區別在於它可以讓GSON爲Pair
課程本身選擇策略。據我瞭解,GSON會根據DTO目標類型嘗試解析適當的解串器(您的響應對象具有參數化映射map1
和map2
)。這些具體類型由GSON進一步處理。
final class GenericDictionaryJsonDeserializer<K, V>
implements JsonDeserializer<Map<K, V>> {
private static final JsonDeserializer<Map<Object, Object>> dictionaryJsonDeserializer = new GenericDictionaryJsonDeserializer<>();
private GenericDictionaryJsonDeserializer() {
}
static <K, V> JsonDeserializer<Map<K, V>> getGenericDictionaryJsonDeserializer() {
@SuppressWarnings({ "unchecked", "rawtypes" })
final JsonDeserializer<Map<K, V>> castDictionaryJsonDeserializer = (JsonDeserializer) dictionaryJsonDeserializer;
return castDictionaryJsonDeserializer;
}
@Override
public Map<K, V> deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context) {
final JsonArray array = json.getAsJsonArray();
final Map<K, V> result = new LinkedHashMap<>();
for (int i = 0; i < array.size(); i++) {
final Pair<K, V> pair = context.deserialize(array.get(i), Pair.class);
result.put(pair.getKey(), pair.getValue());
}
return result;
}
}
所有你在Gson
情況下需要的是結合Map.class
和通用字典JSON解串器。考慮遷移到另一個類,而不是Map
(比方說interface IDictionary<K,V> extends Map<K,V>
),以避免衝突,如果你想要一些地圖以「Java風格」反序列化,或者改進反序列化程序類。
有針對性的字典JSON解串器
如果當你細跟目前你要避免有針對性的課程的情況下,你可能想使用一個綁定到特定類型的替代品。
final class TargetedDictionaryJsonDeserializer<K, V>
implements JsonDeserializer<Map<K, V>> {
private final Type pairType;
private TargetedDictionaryJsonDeserializer(final Type pairType) {
this.pairType = pairType;
}
static <K, V> JsonDeserializer<Map<K, V>> getTargetedDictionaryJsonDeserializer(final TypeToken<Pair<K, V>> typeToken) {
return new TargetedDictionaryJsonDeserializer<>(typeToken.getType());
}
@Override
public Map<K, V> deserialize(final JsonElement json, final Type type, final JsonDeserializationContext context) {
final JsonArray array = json.getAsJsonArray();
final Map<K, V> result = new LinkedHashMap<>();
for (int i = 0; i < array.size(); i++) {
final Pair<K, V> pair = context.deserialize(array.get(i), pairType);
result.put(pair.getKey(), pair.getValue());
}
return result;
}
}
這些類型的適配器之間的區別是,後者接受具體類型的令牌(即完全由你的電話網站(見下面的演示)申報),並使用類型令牌類型將它委託給上下文反序列化。它確保在您需要時提供強大的型號安全性。
示範 private static final String JSON = "{" +
"'map1':[{'Key':'key1','Value':'value1'},{'Key':'key2','Value':'value2'}]," +
"'map2':[{'Key':'1','Value':'1.0'},{'Key':'2','Value':'2.0'}]" +
"}";
private static final TypeToken<Map<String, String>> stringToStringTypeToken = new TypeToken<Map<String, String>>() {
};
private static final TypeToken<Map<Integer, Float>> integerToFloatTypeToken = new TypeToken<Map<Integer, Float>>() {
};
private static final TypeToken<Pair<String, String>> stringToStringPairTypeToken = new TypeToken<Pair<String, String>>() {
};
private static final TypeToken<Pair<Integer, Float>> integerToFloatPairTypeToken = new TypeToken<Pair<Integer, Float>>() {
};
public static void main(final String... args) {
dump("by-targeted", getByTargetedTypeAdapter());
dump("by-generic", getByGenericTypeAdapter());
dump("by-mixed", getByMixTypeAdapter());
}
private static Response getByTargetedTypeAdapter() {
return new GsonBuilder()
.registerTypeAdapter(stringToStringTypeToken.getType(), getTargetedDictionaryJsonDeserializer(stringToStringPairTypeToken))
.registerTypeAdapter(integerToFloatTypeToken.getType(), getTargetedDictionaryJsonDeserializer(integerToFloatPairTypeToken))
.create()
.fromJson(JSON, Response.class);
}
private static Response getByGenericTypeAdapter() {
return new GsonBuilder()
.registerTypeAdapter(Map.class, getGenericDictionaryJsonDeserializer())
.create()
.fromJson(JSON, Response.class);
}
private static Response getByMixTypeAdapter() {
return new GsonBuilder()
.registerTypeAdapter(Map.class, getGenericDictionaryJsonDeserializer())
.registerTypeAdapter(stringToStringTypeToken.getType(), getTargetedDictionaryJsonDeserializer(stringToStringPairTypeToken))
.create()
.fromJson(JSON, Response.class);
}
private static final class Response {
private final Map<String, String> map1 = null;
private final Map<Integer, Float> map2 = null;
}
private static void dump(final String name, final Response response) {
out.print(">> ");
out.println(name);
out.print(" ");
out.println(response.map1);
out.print(" ");
out.println(response.map2);
}
的 「靶向」 模式轉到混凝土型適配器(看如何stringToStringPairTypeToken
和integerToFloatPairTypeToken
被實例化)。請注意,GsonBuilder
允許覆蓋,所以「混合」測試用例在通用測試用例之後指定了目標策略(否則總是會使用通用策略)。
所有測試用例解析JSON和打印以下輸出:
{鍵1 =值,鍵2 =值}
{1 = 1.0,2 = 2.0}