Java 使用Gson反序列化映射键需要一个对象
我得到一个错误:Java 使用Gson反序列化映射键需要一个对象,java,json,serialization,deserialization,gson,Java,Json,Serialization,Deserialization,Gson,我得到一个错误: Exception in thread "main" com.google.gson.JsonParseException: Expecting object found: "com.shagie.app.SimpleMap$Data@24a37368" 尝试反序列化使用非平凡键的映射时: package com.shagie.app; import com.google.gson.Gson; import com.google.gson.GsonBuilder; im
Exception in thread "main" com.google.gson.JsonParseException:
Expecting object found: "com.shagie.app.SimpleMap$Data@24a37368"
尝试反序列化使用非平凡键的映射时:
package com.shagie.app;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.util.HashMap;
public class SimpleMap {
public static void main(String[] args) {
Wrapper w = new Wrapper();
w.m.put(new Data("f", 1), new Data("foo", 3));
w.m.put(new Data("b", 2), new Data("bar", 4));
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
Gson g = gb.create();
String json = g.toJson(w);
System.out.println(json);
w = g.fromJson(json, Wrapper.class);
System.out.println(w.m.isEmpty());
}
static public class Wrapper {
HashMap<Data, Data> m = new HashMap<Data, Data>();
}
static public class Data {
String s;
Integer i;
public Data(String arg, Integer val) { s = arg; i = val; }
}
}
package com.shagie.app;
导入com.google.gson.gson;
导入com.google.gson.GsonBuilder;
导入java.util.HashMap;
公共类SimpleMap{
公共静态void main(字符串[]args){
包装器w=新包装器();
w、 m.put(新数据(“f”,1),新数据(“foo”,3));
w、 m.put(新数据(“b”,2),新数据(“条形图”,4));
GsonBuilder gb=新的GsonBuilder();
gb.setPrettyPrinting();
Gson g=gb.create();
字符串json=g.toJson(w);
System.out.println(json);
w=g.fromJson(json,Wrapper.class);
System.out.println(w.m.isEmpty());
}
静态公共类包装器{
HashMap m=新的HashMap();
}
静态公共类数据{
字符串s;
整数i;
公共数据(字符串arg,整数val){s=arg;i=val;}
}
}
这将序列化为json:
{
"m": {
"com.shagie.app.SimpleMap$Data@24a37368": {
"s": "foo",
"i": 3
},
"com.shagie.app.SimpleMap$Data@66edc3a2": {
"s": "bar",
"i": 4
}
}
}
{
“m”:{
“com.shagie.app.SimpleMap$Data@24a37368": {
“s”:“foo”,
“i”:3
},
“com.shagie.app.SimpleMap$Data@66edc3a2": {
“s”:“bar”,
“i”:4
}
}
}
可以看到密钥试图被序列化,但肯定不是以反序列化的方式
如何序列化此对象以便将其反序列化?问题在于
toString()
在映射的键上被调用,而不是它们自己被序列化
要解决此问题,需要设置自定义序列化程序和反序列化程序,反序列化程序需要知道对象用于将自身显示为字符串的格式(toString()
方法必须返回可用于重建整个对象的字符串)
对于上述示例:
package com.shagie.app;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.util.HashMap;
public class SimpleMapFixed {
public static void main(String[] args) {
Wrapper w = new Wrapper();
w.m.put(new Data("f", 1), new Data("foo", 3));
w.m.put(new Data("b", 2), new Data("bar", 4));
GsonBuilder gb = new GsonBuilder();
gb.setPrettyPrinting();
gb.registerTypeAdapter(Data.class, new DataSerializer());
Gson g = gb.create();
String json = g.toJson(w);
System.out.println(json);
w = g.fromJson(json, Wrapper.class);
System.out.println(w.m.isEmpty());
}
static public class Wrapper {
HashMap<Data, Data> m = new HashMap<Data, Data>();
}
static public class DataSerializer implements JsonSerializer<Data>,
JsonDeserializer<Data> {
@Override
public Data deserialize(JsonElement je, Type t, JsonDeserializationContext ctx)
throws JsonParseException {
Data rv;
JsonObject jo;
System.out.println("deserialize called with: " + je.toString());
if (je.isJsonObject()) {
jo = je.getAsJsonObject();
rv = new Data(jo.get("s").getAsString(), jo.get("i").getAsInt());
} else {
String js = je.getAsString();
String[] s = js.split(":", 2); // split into two (and only two)
rv = new Data(s[1], Integer.valueOf(s[0]));
}
System.out.println("deserialize returns: " + rv.s + " " + rv.i);
return rv;
}
@Override
public JsonElement serialize(Data data, Type type, JsonSerializationContext jsonSerializationContext) {
JsonObject jo = new JsonObject();
jo.addProperty("s", data.s);
jo.addProperty("i", data.i);
System.out.println("serialize called: " + jo.toString());
return jo;
}
}
static public class Data {
String s;
Integer i;
public Data(String arg, Integer val) { s = arg; i = val; }
@Override
public String toString() {
String rv = i.toString() + ':' + s;
System.out.println("toString called: " + rv);
return rv;
}
}
}
package com.shagie.app;
导入com.google.gson.*;
导入java.lang.reflect.Type;
导入java.util.HashMap;
公共类simplemapfix{
公共静态void main(字符串[]args){
包装器w=新包装器();
w、 m.put(新数据(“f”,1),新数据(“foo”,3));
w、 m.put(新数据(“b”,2),新数据(“条形图”,4));
GsonBuilder gb=新的GsonBuilder();
gb.setPrettyPrinting();
gb.registerTypeAdapter(Data.class,新的DataSerializer());
Gson g=gb.create();
字符串json=g.toJson(w);
System.out.println(json);
w=g.fromJson(json,Wrapper.class);
System.out.println(w.m.isEmpty());
}
静态公共类包装器{
HashMap m=新的HashMap();
}
静态公共类DataSerializer实现JsonSerializer,
JsonDeserializer{
@凌驾
公共数据反序列化(JsonElement je,类型t,JsonDeserializationContext ctx)
抛出JsonParseException{
数据rv;
JsonObject jo;
System.out.println(“反序列化调用:“+je.toString()”);
if(je.isJsonObject()){
jo=je.getAsJsonObject();
rv=新数据(jo.get(“s”).getAsString(),jo.get(“i”).getAsInt());
}否则{
字符串js=je.getAsString();
String[]s=js.split(“:”,2);//拆分为两个(并且只有两个)
rv=新数据(s[1],整数.valueOf(s[0]);
}
System.out.println(“反序列化返回:+rv.s+”+rv.i);
返回rv;
}
@凌驾
公共JsonElement序列化(数据数据、类型、JsonSerializationContext JsonSerializationContext){
JsonObject jo=新的JsonObject();
jo.addProperty(“s”,data.s);
jo.addProperty(“i”,data.i);
System.out.println(“序列化调用:”+jo.toString());
返回jo;
}
}
静态公共类数据{
字符串s;
整数i;
公共数据(字符串arg,整数val){s=arg;i=val;}
@凌驾
公共字符串toString(){
字符串rv=i.toString()+':'+s;
System.out.println(“称为“+rv”的toString);
返回rv;
}
}
}
运行此代码会产生:
serialize called: {"s":"foo","i":3}
toString called: 1:f
serialize called: {"s":"bar","i":4}
toString called: 2:b
{
"m": {
"1:f": {
"s": "foo",
"i": 3
},
"2:b": {
"s": "bar",
"i": 4
}
}
}
deserialize called with: "1:f"
deserialize returns: f 1
deserialize called with: {"s":"foo","i":3}
deserialize returns: foo 3
deserialize called with: "2:b"
deserialize returns: b 2
deserialize called with: {"s":"bar","i":4}
deserialize returns: bar 4
序列化名为:{“s”:“foo”,“i”:3}
toString调用:1:f
序列化名为:{“s”:“bar”,“i”:4}
toString调用:2:b
{
“m”:{
“1:f”:{
“s”:“foo”,
“i”:3
},
“2:b”:{
“s”:“bar”,
“i”:4
}
}
}
用“1:f”反序列化调用
反序列化返回:f 1
用{“s”:“foo”,“i”:3}反序列化调用
反序列化返回:foo3
用“2:b”反序列化调用
反序列化返回:b2
用{“s”:“bar”,“i”:4}反序列化调用
反序列化返回:条4
请注意,调用toString()
是序列化的一部分。在这段代码中,字符串形式的反序列化逻辑位于数据序列化程序
中,尽管将其作为另一个构造函数移动到数据
类中可能是有意义的-它不会影响最终结果
进一步注意,
数据
本身是一个相当简单的对象,没有更深层次的结构。尝试序列化该键需要额外的工作。这取决于您如何维护HahMap键,您可以用简单而简单的方法将其反序列化
final Type typeOf = new TypeToken <Map<String, Map<String, Data>>>(){}.getType();
final Map<String, Map<String, Data>> newMap = gson.fromJson(json, typeOf);
final Map<String, Data> map = newMap.get("m");
final Iterator<Entry<String, Data>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String,Data> pair = (Map.Entry<String,Data>) it.next();
String key = pair.getKey();
System.out.println("key "+ key + " Values[ i= " + data.getI() + ", s= " +data.getS()+" ]");
}
final-Type-typeOf=new-TypeToken(){}.getType();
最终映射newMap=gson.fromJson(json,typeOf);
最终映射=newMap.get(“m”);
final Iterator it=map.entrySet().Iterator();
while(it.hasNext()){
Map.Entry对=(Map.Entry)it.next();
String key=pair.getKey();
System.out.println(“key”+key+”值[i=“+data.getI()+”,s=“+data.getS()+”]);
}
结果:
key=snippet.snippet$Data@61506150值[i=3,s=foo]
key=snippet.snippet$Data@63ff63ff值[i=4,s=bar]我在尝试解决此难题时发现了以下内容: 对于来自美国的任何互联网旅行者
{"m":[[{"s":"f", "i",1}, {"s":"foo", "i":3}], [{"s":"b", "i",2}, {"s":"bar", "i":4}]]}