如何用GSON序列化HashMap<Object,Object>?
How to serialize HashMap<Object,Object> with GSON?
我正在尝试序列化 HashMap,它具有自定义对象(相同类型)作为键和值。然而 gson 正在输出这样的东西:
{ key.toString():{value}}
基本上,不是序列化在地图中用作键的对象,而是使用它的 toString 值。值对象得到很好的序列化。结果 Json 显然无法反序列化。我如何说服 GSON 完全序列化关键对象?
编辑:
存储在 HashMap 中的对象包含有关玩家的信息(我正在为我们的棋盘游戏组构建自定义媒人)。它们看起来像这样:
public class Player implements Serializable{
private static final long serialVersionUID = 42L;
private String playerName,faction,teamName;
private HashMap<String,Integer> resources;
散列图应该包含有关即将到来的比赛的信息,基本上是像这样的键值对战:
HashMap<Player,Player> matchMap=new HashMap<>();
matchMap.put(player1,opponentForPlayer1);
没有具体的例子很难得出准确的答案。
您可以使用 SerializedName
注释更改密钥的命名方式:
private class SomeObject {
@SerializedName("custom_naming") private final String someField;
private final String someOtherField;
public SomeObject(String a, String b) {
this.someField = a;
this.someOtherField = b;
}
}
SomeObject someObject = new SomeObject("first", "second");
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
String jsonRepresentation = gson.toJson(someObject);
System.out.println(jsonRepresentation);
输出为:
{"custom_naming": "first", "SomeOtherField": "second"}
(无耻地从文档中窃取的示例 :)
要自定义序列化,请查看文档:https://github.com/google/gson/blob/master/UserGuide.md#custom-serialization-and-deserialization
// Step 1: writing a custom serializer
/** Here is an example of how to write a custom serializer for JodaTime DateTime class. */
private class DateTimeSerializer implements JsonSerializer<DateTime> {
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
}
// Step 2: registering it
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType.class, new DateTimeSerializer());
registerTypeAdapter call checks if the type adapter implements more than one of these interfaces and register it for all of them.
JSON
键只能是 Strings
。尝试以下使用自定义 JsonSerializer
和 JsonDeserializer
.
的解决方案
自定义 JsonSerializer
将在序列化时将键(Player
对象)转换为 JSON String
:
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class CustomMapSerializer implements JsonSerializer<Map<Player, Player>> {
@Override
public JsonElement serialize(Map<Player, Player> src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
Gson gson = new Gson();
for (Entry<Player, Player> entry : src.entrySet()) {
json.add(gson.toJson(entry.getKey()), gson.toJsonTree(entry.getValue()));
}
return json;
}
}
自定义 JsonDeserializer
以在反序列化期间将键 (JSON String
) 转换回 Player
对象:
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gson.Gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
public class CustomMapDeserializer implements JsonDeserializer<Map<Player, Player>> {
@Override
public Map<Player, Player> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Map<Player, Player> players = new HashMap<Player, Player>();
Gson gson = new Gson();
JsonObject object = json.getAsJsonObject();
for (Entry<String, JsonElement> entry : object.entrySet()) {
players.put(gson.fromJson(entry.getKey(), Player.class), gson.fromJson(entry.getValue(), Player.class));
}
return players;
}
}
参考下面的例子 serialization
和 deserialization
:
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class Solutiony {
public static void main(String[] args) {
Map<String, Integer> data = new HashMap<>();
data.put("value", 100);
Player p = new Player();
p.setFaction("0.9");
p.setPlayerName("x");
p.setTeamName("A");
p.setResources(data);
Player p2 = new Player();
p2.setFaction("1.0");
p2.setPlayerName("y");
p2.setTeamName("B");
p2.setResources(data);
Map<Player, Player> map = new HashMap<Player, Player>();
map.put(p, p2);
Gson gson = new GsonBuilder().registerTypeAdapter(map.getClass(), new CustomMapSerializer())
.registerTypeAdapter(map.getClass(), new CustomMapDeserializer())
.setPrettyPrinting().create();
//Serialization
String val = gson.toJson(map);
//De-serialization
Map<Player, Player> map2 = gson.fromJson(val, map.getClass());
}
}
序列化后的 JSON
看起来像:
{
"{\"playerName\":\"x\",\"faction\":\"0.9\",\"teamName\":\"A\",\"resources\":{\"value\":100}}": {
"playerName": "y",
"faction": "1.0",
"teamName": "B",
"resources": {
"value": 100
}
}
}
根据 fluffys 的评论,最简单的解决方案是在像这样创建 gson 对象时使用 enableComplexMapKeySerialization():
Gson gson=new GsonBuilder().enableComplexMapKeySerialization().create();
如果那不可用或出于某种原因无法工作也可以。
我正在尝试序列化 HashMap,它具有自定义对象(相同类型)作为键和值。然而 gson 正在输出这样的东西:
{ key.toString():{value}}
基本上,不是序列化在地图中用作键的对象,而是使用它的 toString 值。值对象得到很好的序列化。结果 Json 显然无法反序列化。我如何说服 GSON 完全序列化关键对象?
编辑: 存储在 HashMap 中的对象包含有关玩家的信息(我正在为我们的棋盘游戏组构建自定义媒人)。它们看起来像这样:
public class Player implements Serializable{
private static final long serialVersionUID = 42L;
private String playerName,faction,teamName;
private HashMap<String,Integer> resources;
散列图应该包含有关即将到来的比赛的信息,基本上是像这样的键值对战:
HashMap<Player,Player> matchMap=new HashMap<>();
matchMap.put(player1,opponentForPlayer1);
没有具体的例子很难得出准确的答案。
您可以使用 SerializedName
注释更改密钥的命名方式:
private class SomeObject {
@SerializedName("custom_naming") private final String someField;
private final String someOtherField;
public SomeObject(String a, String b) {
this.someField = a;
this.someOtherField = b;
}
}
SomeObject someObject = new SomeObject("first", "second");
Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).create();
String jsonRepresentation = gson.toJson(someObject);
System.out.println(jsonRepresentation);
输出为:
{"custom_naming": "first", "SomeOtherField": "second"}
(无耻地从文档中窃取的示例 :)
要自定义序列化,请查看文档:https://github.com/google/gson/blob/master/UserGuide.md#custom-serialization-and-deserialization
// Step 1: writing a custom serializer
/** Here is an example of how to write a custom serializer for JodaTime DateTime class. */
private class DateTimeSerializer implements JsonSerializer<DateTime> {
public JsonElement serialize(DateTime src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
}
// Step 2: registering it
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(MyType.class, new DateTimeSerializer());
registerTypeAdapter call checks if the type adapter implements more than one of these interfaces and register it for all of them.
JSON
键只能是 Strings
。尝试以下使用自定义 JsonSerializer
和 JsonDeserializer
.
自定义 JsonSerializer
将在序列化时将键(Player
对象)转换为 JSON String
:
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
public class CustomMapSerializer implements JsonSerializer<Map<Player, Player>> {
@Override
public JsonElement serialize(Map<Player, Player> src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject json = new JsonObject();
Gson gson = new Gson();
for (Entry<Player, Player> entry : src.entrySet()) {
json.add(gson.toJson(entry.getKey()), gson.toJsonTree(entry.getValue()));
}
return json;
}
}
自定义 JsonDeserializer
以在反序列化期间将键 (JSON String
) 转换回 Player
对象:
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gson.Gson;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
public class CustomMapDeserializer implements JsonDeserializer<Map<Player, Player>> {
@Override
public Map<Player, Player> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Map<Player, Player> players = new HashMap<Player, Player>();
Gson gson = new Gson();
JsonObject object = json.getAsJsonObject();
for (Entry<String, JsonElement> entry : object.entrySet()) {
players.put(gson.fromJson(entry.getKey(), Player.class), gson.fromJson(entry.getValue(), Player.class));
}
return players;
}
}
参考下面的例子 serialization
和 deserialization
:
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class Solutiony {
public static void main(String[] args) {
Map<String, Integer> data = new HashMap<>();
data.put("value", 100);
Player p = new Player();
p.setFaction("0.9");
p.setPlayerName("x");
p.setTeamName("A");
p.setResources(data);
Player p2 = new Player();
p2.setFaction("1.0");
p2.setPlayerName("y");
p2.setTeamName("B");
p2.setResources(data);
Map<Player, Player> map = new HashMap<Player, Player>();
map.put(p, p2);
Gson gson = new GsonBuilder().registerTypeAdapter(map.getClass(), new CustomMapSerializer())
.registerTypeAdapter(map.getClass(), new CustomMapDeserializer())
.setPrettyPrinting().create();
//Serialization
String val = gson.toJson(map);
//De-serialization
Map<Player, Player> map2 = gson.fromJson(val, map.getClass());
}
}
序列化后的 JSON
看起来像:
{
"{\"playerName\":\"x\",\"faction\":\"0.9\",\"teamName\":\"A\",\"resources\":{\"value\":100}}": {
"playerName": "y",
"faction": "1.0",
"teamName": "B",
"resources": {
"value": 100
}
}
}
根据 fluffys 的评论,最简单的解决方案是在像这样创建 gson 对象时使用 enableComplexMapKeySerialization():
Gson gson=new GsonBuilder().enableComplexMapKeySerialization().create();
如果那不可用或出于某种原因无法工作