简体   繁体   中英

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. 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

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. 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. 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). 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?

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 . 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 . 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.

To give Gson the full type, including generic type parameters, you will have to use a TypeToken . To create the appropriate TypeToken , do this:

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. 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.

On another note, the fact that you're using HashMap instead of Map everywhere is prone to bugs. 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. If it were, Gson's choice of what type of Map to use would work just fine and this error would never have happened.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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