如何使用Gson反序列化ConcurrentMap

我试图反序列化一个具有ConcurrentMap的对象,但我得到一个例外。

 Caused by: java.lang.IllegalArgumentException: Can not set java.util.concurrent.ConcurrentMap field com.example.Row.doubleValues to java.util.LinkedHashMap 

我的函数看起来像这样:

 T deserialise(final InputStream input, final Class type) { GsonBuilder gsonBuilder = new GsonBuilder(); Gson gson = gsonBuilder.create(); InputStreamReader isr = new InputStreamReader(input); return gson.fromJson(isr, type); } 

如何让它正确地反序列化地图? 我需要提供自定义解串器吗?

请注意,我在同一个类中有常规MapsConcurrentMaps 。 我也是序列化类的人,因此,如果我可以提供一个指定并发映射类型的自定义序列化程序,然后是一个反序列化器,它指定应该如何创建那些应该工作的对象。

更新 :我反序列化的类看起来像这样:

 public class Row implements Serializable { private static final long serialVersionUID = 1L; //there's a diff value here private final String key; private final ConcurrentMap doubleValues = Maps.newConcurrentMap(); private Map writeOnceValues = Maps.newHashMap(); ... } 

这是我提出的使用TypeAdapter解决方案。 在向您展示代码之前,我必须说如果字段存在于解析后的字符串中,则final不应该用于字段,因为Gson将尝试为该字段赋值。

我改变了Row类,只是为了显示解决方案。

 public class Row implements Serializable { private static final long serialVersionUID = 1L; //there's a diff value here private final String key = "myKey"; private ConcurrentMap doubleValues = Maps.newConcurrentMap(); private Map writeOnceValues = Maps.newHashMap(); @Override public String toString() { return "Row [key=" + key.getClass() + ", doubleValues=" + doubleValues.getClass() + ", writeOnceValues=" + writeOnceValues.getClass() + "]"; } } 

和类型适配器,我基本上使用标准解析但返回ConcurrentHashMap

 public final class ConcurrentHashMapTypeAdapter extends TypeAdapter> { @Override public synchronized ConcurrentMap read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } Type aType = new TypeToken>() {}.getType(); Gson g = new Gson(); LinkedTreeMap ltm = g.fromJson(in, aType); return new ConcurrentHashMap(ltm); } @Override public synchronized void write(JsonWriter out, ConcurrentMap value) throws IOException { Gson g = new Gson(); out.value(g.toJson(value)); } } 

和测试方法,我告诉你它的工作原理。

 public static void main(String[] args) { Gson simpleGson = new Gson(); // deserialize row once to get a suitable JSON string String s = simpleGson.toJson(new Row()); System.out.println("JSON string: " + s); Row r; try{ r = simpleGson.fromJson(s, Row.class); } catch(Exception e){ System.out.println("Oh no, assignment is not possible"); e.printStackTrace(); } GsonBuilder gb = new GsonBuilder(); Type aType = new TypeToken>() {}.getType(); gb.registerTypeAdapter(aType, new ConcurrentHashMapTypeAdapter()); Gson gsonWithTypeAdapter = gb.create(); r = gsonWithTypeAdapter.fromJson(s, Row.class); System.out.println("Now it works"); System.out.println("Row: " +r); } 

这是我的执行:

 JSON string: {"key":"myKey","doubleValues":{},"writeOnceValues":{}} Oh no, assignment is not possible java.lang.IllegalArgumentException: Can not set java.util.concurrent.ConcurrentMap field stackoverflow.questions.q18856793.Row.doubleValues to com.google.gson.internal.LinkedTreeMap at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(Unknown Source) at java.lang.reflect.Field.set(Unknown Source) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:95) at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:172) at com.google.gson.Gson.fromJson(Gson.java:803) at com.google.gson.Gson.fromJson(Gson.java:768) at com.google.gson.Gson.fromJson(Gson.java:717) at com.google.gson.Gson.fromJson(Gson.java:689) at stackoverflow.questions.q18856793.Q18856793.main(Q18856793.java:23) Now it works Row: Row [key=class java.lang.String, doubleValues=class java.util.concurrent.ConcurrentHashMap, writeOnceValues=class com.google.gson.internal.LinkedTreeMap]