如何用Gson反序列化ConcurrentMap [英] How to deserialize a ConcurrentMap with Gson
问题描述
我试图反序列化一个有
引发:java.lang.IllegalArgumentException:无法将java.util.concurrent.ConcurrentMap字段com.example.Row.doubleValues设置为java.util.LinkedHashMap
$ c
$ b 我的功能如下所示:
T deserialise(final InputStream input,final Class< T> type){
GsonBuilder gsonBuilder = new GsonBuilder();
Gson gson = gsonBuilder.create();
InputStreamReader isr = new InputStreamReader(input);
返回gson.fromJson(isr,type);
$ b 如何正确地反序列化映射?我需要提供一个自定义的反序列化器吗?
请注意,我有两个常规地图
和 ConcurrentMaps
在同一个类中。我也是一个序列化类的人,所以,如果我可以提供一个指定并发映射类型的自定义序列化程序,然后是一个反序列化程序,它指定应该如何创建这些应该工作的对象。
更新:我反序列化的类看起来像这样:
public class Row implements Serializable {
private static final long serialVersionUID = 1L; //这里有一个diff值
private final String key;
private final ConcurrentMap< String,Double> doubleValues = Maps.newConcurrentMap();
私人地图< String,String> writeOnceValues = Maps.newHashMap();
...
}
解决方案这是我提出的解决方案,它带有 TypeAdapter
。在向你展示代码之前,我必须说,如果字段存在于分析字符串中,那么 final 不应该用于字段,因为Gson会尝试为该字段赋值。
我更改了 Row
类,仅用于显示解决方案。
public class Row implements Serializable {
private static final long serialVersionUID = 1L; //这里有一个diff值
private final String key =myKey;
private ConcurrentMap< String,Double> doubleValues = Maps.newConcurrentMap();
私人地图< String,String> writeOnceValues = Maps.newHashMap();
@Override
public String toString(){
returnRow [key =+ key.getClass()+,doubleValues =+ doubleValues.getClass()
+,writeOnceValues =+ writeOnceValues.getClass()+];
}
}
使用标准解析但返回 ConcurrentHashMap
。
public final class ConcurrentHashMapTypeAdapter< K,V>扩展TypeAdapter< ConcurrentMap< K,V>> {
@Override
公共同步ConcurrentMap< K,V> read(JsonReader in)抛出IOException {
if(in.peek()== JsonToken.NULL){
in.nextNull();
返回null;
}
键入aType = new TypeToken< LinkedTreeMap< K,V>>(){} .getType();
Gson g = new Gson();
LinkedTreeMap< K,V> ltm = g.fromJson(in,aType);
返回新的ConcurrentHashMap< K,V>(ltm);
$ b @Override
public synchronized void write(JsonWriter out,ConcurrentMap< K,V> value)throws IOException {
Gson g = new Gson();
out.value(g.toJson(value));
$ / code>
和一个测试方法,我告诉你它可以工作。
public static void main(String [] args){
Gson simpleGson = new Gson();
//反序列化一行以获得合适的JSON字符串
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(哦,不,分配不可能);
e.printStackTrace();
}
GsonBuilder gb = new GsonBuilder();
键入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字符串:{key:myKey,doubleValues:{},writeOnceValues:{}}
哦,不,分配是不可能的
java.lang.IllegalArgumentException:无法设置java.util.concurrent.ConcurrentMap字段stackoverflow.questions.q18856793.Row.doubleValues为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)
,位于com.google.gson.Gson.fromJson(Gson.java:8 03)
在com.google.gson.Gson.fromJson(Gson.java:768)
在com.google.gson.Gson.fromJson(Gson.java:717)
在com .google.gson.Gson.fromJson(Gson.java:689)
at stackoverflow.questions.q18856793.Q18856793.main(Q18856793.java:23)
现在它可以工作
Row:Row [key = class java.lang.String,doubleValues = class java.util.concurrent.ConcurrentHashMap,writeOnceValues = class com.google.gson.internal.LinkedTreeMap]
I am trying to deserialize an object that has a ConcurrentMap
in it but I get an exception.
Caused by: java.lang.IllegalArgumentException: Can not set java.util.concurrent.ConcurrentMap field com.example.Row.doubleValues to java.util.LinkedHashMap
My function looks something like this:
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);
}
How do I get it to deserialize the map properly? Do I need to provide a custom deserializer?
Note that I have both regular Maps
and ConcurrentMaps
in the same class. I am also the one who serializes the class, so, if I can provide a custom serializer that specifies the type of concurrent maps and then a deserializer that specifies how those should be created as objects that should work.
Update: The class that I am deserializing looks like this:
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();
...
}
解决方案 This is my proposed solution with a TypeAdapter
. Before showing you the code, I have to say that final
should not be used for a field if field is present into parsed string, since Gson will try to assign value to that field.
My changed Row
class, just for purpose of showing solution.
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() + "]";
}
}
and the type adapter where I essentially use standard parsing but return a 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));
}
}
and a test method where I show you that it works.
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);
}
This is my execution:
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]
这篇关于如何用Gson反序列化ConcurrentMap的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!