简体   繁体   English

HashMap Java中的序列化/反序列化 <Int,Object> 使用Gson

[英]Serialization/Deserialization in Java of HashMap<Int,Object> using Gson

I am trying to use google's Gson library to serialize and de-serialize a HashMap in Java. 我正在尝试使用Google的Gson库对Java中的HashMap进行序列化和反序列化。 I'd like to serialize the hashmap shown here, save it to a file, and then read from a file at a later stage and deserialize it. 我想序列化此处显示的哈希图,将其保存到文件中,然后在以后从文件中读取并反序列化。

The HashMap is as follows HashMap如下

public static HashMap<Integer,HashMap <Integer, Type5Val>> type5Model = new HashMap<Integer, HashMap<Integer, Type5Val>>();

The Deserialization Logic for deserialization class, and the object class I have implemented so far based on examples found on the web. 到目前为止,我已经基于Web上的示例实现了反序列化的反序列化逻辑类和对象类。 is: 是:

public class Type5Val implements Serializable,JsonDeserializer<Type5Val>{

    public int modelLogLines;
    public int modelTime;       

    @Override
    public Type5Val deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {

        final JsonObject jsonObject = jsonElement.getAsJsonObject();

        System.out.println("Print JSON Object" + jsonObject.getAsString());

        final int t_modelLogLines = jsonObject.get("modelLogLines").getAsInt();
        final int t_modelTime = jsonObject.get("modelTime").getAsInt();

        //Populating
        Type5Val val = new Type5Val();
        val.modelLogLines = t_modelLogLines;
        val.modelTime = t_modelTime;

        return val;
    }
}

The following is a code for serializing, and deserializing which is called in the test function. 以下是在测试函数中调用的用于序列化和反序列化的代码。 The test function serializes an Object of HashMap above, creates a string, and then tries to deserialize it. 测试函数将上面的HashMap的Object序列化,创建一个字符串,然后尝试反序列化它。 The deserialization is currently failing: 反序列化当前失败:

//serialization code
public static String dump(){

    // Configure Gson
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Type5Val.class, new Type5Val());

    Gson g = gsonBuilder.create();
    String json = g.toJson(type5Model);
    return json;
}

//deserialization code
public static HashMap<Integer, HashMap<Integer,Type5Val>> undump(String json){

    // Configure Gson
    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(Type5Val.class, new Type5Val());

    Gson g = gsonBuilder.create();
    HashMap<Integer,HashMap <Integer, Type5Val>> newModel =  g.fromJson(json, type5Model.getClass());
    return newModel;
}

public static void printMap(HashMap<Integer,HashMap<Integer,Type5Val>> modelInput){

    Iterator<HashMap<Integer, Type5Val>> it = modelInput.values().iterator();

    while(it.hasNext()){
        HashMap<Integer,Type5Val> temp = it.next();
        Iterator<Type5Val> it2 = temp.values().iterator();

        while(it2.hasNext()){
            Type5Val temp2 = it2.next();
            System.out.println("Time: " + temp2.modelTime + " Lines: " + temp2.modelLogLines);
            System.out.println(" Queue Size " + temp2.q.size() + "\n");
        }
    }
}

public static void testcase(){

    System.out.println("Printing Initial Map");
    printMap(type5Model);

    //serialization
    String s = dump();
    System.out.println(s);

    //deserialization
    HashMap<Integer, HashMap<Integer,Type5Val>> newModel = undump(s);

    System.out.println("Printing Map After Serialization/Deserialization");
    printMap(newModel);

}

The follwing is the exception I get, I have tagged the JSON output after the serialization (which works). 以下是我得到的例外,我在序列化后标记了JSON输出(有效)。 The exception is in the deserialization. 反序列化是一个例外。

Printing Initial Map
Time: 0 Lines: 39600000
 Queue Size 0

Time: 0 Lines: 46800000
 Queue Size 0

//Json output after serialization
{"1":{"1":{"modelLogLines":39600000,"modelTime":0,"q":[]},"2":{"modelLogLines":46800000,"modelTime":0,"q":[]}}}
Printing Map After Serialization/Deserialization
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at com.simontuffs.onejar.Boot.run(Boot.java:340)
        at com.simontuffs.onejar.Boot.main(Boot.java:166)
Caused by: java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.HashMap
        at violationChecker.type5Convert.printMap(type5Convert.java:207)
        at violationChecker.type5Convert.testcase(type5Convert.java:259)
        at violationChecker.type5Convert.main(type5Convert.java:294)
        ... 6 more

What am I doing wrong here? 我在这里做错了什么? Can anyone give further tips in Deserialization in Gson? 谁能在Gson中反序列化中提供更多建议?

On this line: 在这行上:

HashMap<Integer,HashMap <Integer, Type5Val>> newModel =  g.fromJson(json, type5Model.getClass());

You are telling Gson to deserialize the String as a HashMap . 您要告诉Gson将String反序列化为HashMap Just a HashMap , not a HashMap<Integer, HashMap<Integer, Type5Val>> , because all that information about the generic type parameters is erased at runtime, and what you're passing it is the runtime known type of type5Model . 只是一个HashMap ,而不是HashMap<Integer, HashMap<Integer, Type5Val>> ,因为有关泛型类型参数的所有信息都在运行时删除,传递给您的是运行时已知的type5Model类型。 That forces Gson to guess about the types that are supposed to be in your HashMap as its keys and values, and it's making LinkedTreeMap instead of HashMap for the inner maps in your values. 这迫使Gson猜测应该在HashMap作为其键和值的类型,并且正在为值中的内部映射制作LinkedTreeMap而不是HashMap

To give Gson the full type, including generic type parameters, you will have to use a TypeToken . 要为Gson提供完整的类型,包括通用类型参数,您将必须使用TypeToken To create the appropriate TypeToken , do this: 要创建适当的TypeToken ,请执行以下操作:

new TypeToken<HashMap<Integer, HashMap<Integer, Type5Val>>>(){}.getType()

Pass the result of that to the fromJson call in place of type5Model.getClass() , and you should get what you were expecting. 将结果传递给type5Model.getClass()fromJson调用,您应该得到期望的结果。 It might be more readable to create the TypeToken on one line, store it in a temp variable, and pass the variable instead of cramming it all onto one line. TypeToken上创建TypeToken ,将其存储在temp变量中,然后传递该变量,而不是将其全部TypeToken一行,可能更具可读性。

On another note, the fact that you're using HashMap instead of Map everywhere is prone to bugs. 另一个要注意的是,您在各处都使用HashMap而不是Map的事实易于出错。 Almost certainly most of your code only really cares about the behavior specified by Map , and in that case should be written in terms of Map only. 几乎可以肯定,您的大多数代码仅真正关心Map指定的行为,在这种情况下,应仅根据Map编写。 If it were, Gson's choice of what type of Map to use would work just fine and this error would never have happened. 如果是这样,Gson选择使用哪种类型的Map将会很好,并且永远不会发生此错误。

You'd still get another error somewhere else without the TypeToken , though, because Gson would never guess without being told that some of the objects are supposed to be of the Type5Val class. 但是,如果没有TypeToken ,在其他地方仍然会出现另一个错误,因为Gson永远不会猜测,而不会被告知某些对象应该属于Type5Val类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM