如何用Gson反序列化ConcurrentMap [英] How to deserialize a ConcurrentMap with Gson

查看:326
本文介绍了如何用Gson反序列化ConcurrentMap的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图反序列化一个有 ConcurrentMap 的对象,但我得到一个异常。

 引发:java.lang.IllegalArgumentException:无法将java.util.concurrent.ConcurrentMap字段com.example.Row.doubleValues设置为java.util.LinkedHashMap 


$ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆