java - Gson 中的自定义 Java 映射反序列化器
问题描述
是否可以通过从每对中选择值来将对象对数组转换为 a Map
,而无需创建中间 POJO?
例如,假设有 2 个Java
类 ( Key.class
, Value.class
) 和一个JSON
由其对象的序列化对构造的数组,如下所示
[
{"key":{}, "value":{}}, // Objects k1, v1
{"key":{}, "value":{}}, // Objects k2, v2
{"key":{}, "value":{}}, // Objects k3, v3
{"key":{}, "value":{}}, // Objects k4, v4
]
可以Gson
“直接”(即,没有 POJO 定义)将上述数组反序列化为 a Map
,其中实际的键和值是通过对相应Key
和Value
对象而不是“完整”对象
换句话说,给定两种Java
类型K
andV
可能与Key
and不同Value
,每对的反序列化应该是
(k1:Key, v1:Value) --> (k1':K, v1':V)
在哪里
k1' = function(k1)
v1' = function(v1)
像这样的自定义适配器不起作用:
GsonBuilder builder = new GsonBuilder();
Type type = (new TypeToken<Map<K, V>>() {}).getType();
builder.registerTypeAdapter(type, new JsonDeserializer<Map<Key, Value>>() {
@Override
public Map<K, V> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
// Custom deserialization block,
// invoking the `function()` method
}
Gson gson = builder.create();
使用上述适配器会导致Gson
将整个数组传递给deserialize()
方法,在该方法中必须手动操作,既繁琐又容易出错。
有一个POJO
像
public class KeyValue {
Key k;
Value v;
}
上面的JSON
数组可以反序列化为一个数组或一组KeyValue
对象,然后可以将其转换为Map<K, V>
. KeyValue
但是如果没有POJO也可以这样做吗?
解决方案
如果您想避免使用您所指的 POJO 类,因为KeyValue
我认为使用 gson 做到这一点的唯一方法是创建一个适配器。原因是您的 JSON 不符合任何通用的内置类,因此如果没有自定义逻辑,gson 将无法理解它。
由于您有Key
和Value
类,因此您可以在自定义适配器中利用它。我想你会发现这减少了代码的乏味。
public static void main(String[] args) throws IOException {
GsonBuilder builder = new GsonBuilder();
Type type = (new TypeToken<Map<Key, Value>>() {}).getType();
builder.registerTypeAdapter(type, new JsonDeserializer<Map<Key, Value>>() {
@Override
public Map<Key, Value> deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException {
Map<Key, Value> resultMap = new HashMap<>();
JsonArray jArr = json.getAsJsonArray();
for(int i=0; i < jArr.size(); i++){
JsonObject item = jArr.get(i).getAsJsonObject();
processKeyValue(item, resultMap);
}
return resultMap;
}
private void processKeyValue(JsonObject mapEntry, Map<Key, Value> resultMap){
Gson gson = new Gson();
Key key = gson.fromJson(mapEntry.get("key"), Key.class);
Value value = gson.fromJson(mapEntry.get("value"), Value.class);
resultMap.put(key, value);
}
});
Gson gson = builder.create();
//Note: assume that the variable "json" is a JSON string. I removed my code for getting the string since I'm just reading from a file and I don't know how you're getting your data.
// Deserialization
Map<Key,Value> outputMap = gson.fromJson(json, type);
System.out.println("RESULTS: "+outputMap.toString());
}
我使用了您的示例数据,但稍作修改以获得更多内容。Key
我为and创建了两个非常简单的 POJO 类Value
- 它们只有一个String
名为 的字段id
、该字段的 getter 和 setter 以及一个toString
方法。
这是我在运行上述代码时使用的输入:
[
{"key":{"id":"k1"}, "value":{"id":"v1"}},
{"key":{"id":"k2"}, "value":{"id":"v2"}},
{"key":{"id":"k3"}, "value":{"id":"v3"}},
{"key":{"id":"k4"}, "value":{"id":"v4"}}
]
输出是:
RESULTS: {Key [id=k2]=Value [id=v2], Key [id=k1]=Value [id=v1], Key [id=k3]=Value [id=v3], Key [id=k4]=Value [id=v4]}
推荐阅读
- elasticsearch - logstash -> Elasticsearch:更新非规范化数据
- mybatis - Mybatis foreach之HashMap
- c++ - map::lower_bound() 和 map::upper_bound 如何在 C++ 中工作?
- javascript - Javascript:循环到任何带有偶数/奇数描述的数字。为什么它只记录用户输入?
- python - 快速创建具有序列号的列表
- javascript - Kotlin XML 解析
- sbt - 如何运行 sbt,评估表达式并离开?
- android - 如何使用 XmlPullParser Android 读取没有 StartTag 或 Endtag 的 XML 标记
- html - 电子邮件不在 Outlook 中居中
- javascript - ReactDOM.render() 与导出默认类?