我正在尝试对其中包含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<T> type) {
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
InputStreamReader isr = new InputStreamReader(input);
return gson.fromJson(isr, type);
}
如何让它正确地反序列化地图?我需要提供自定义反序列化器吗?
请注意,我在同一个班级中有常规Maps
和ConcurrentMaps
。我也是序列化类的人,所以,如果我可以提供一个自定义序列化程序来指定并发映射的类型,然后是一个反序列化程序,它指定应该如何创建它们作为应该工作的对象。
更新:我反序列化的类看起来像这样:
public class Row implements Serializable {
private static final long serialVersionUID = 1L; //there's a diff value here
private final String key;
private final ConcurrentMap<String, Double> doubleValues = Maps.newConcurrentMap();
private Map<String, String> writeOnceValues = Maps.newHashMap();
...
}
答案 0 :(得分:-1)
这是我提出的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<String, Double> doubleValues = Maps.newConcurrentMap();
private Map<String, String> writeOnceValues = Maps.newHashMap();
@Override
public String toString() {
return "Row [key=" + key.getClass() + ", doubleValues=" + doubleValues.getClass()
+ ", writeOnceValues=" + writeOnceValues.getClass() + "]";
}
}
和类型适配器,我基本上使用标准解析,但返回ConcurrentHashMap
。
public final class ConcurrentHashMapTypeAdapter<K,V> extends TypeAdapter<ConcurrentMap<K,V>> {
@Override
public synchronized ConcurrentMap<K,V> read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
Type aType = new TypeToken<LinkedTreeMap<K,V>>() {}.getType();
Gson g = new Gson();
LinkedTreeMap<K,V> ltm = g.fromJson(in, aType);
return new ConcurrentHashMap<K,V>(ltm);
}
@Override
public synchronized void write(JsonWriter out, ConcurrentMap<K, V> 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<ConcurrentMap<String,Double>>() {}.getType();
gb.registerTypeAdapter(aType, new ConcurrentHashMapTypeAdapter<String, Double>());
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]