0

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?

7
  • "Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself." You aren't describing the specific problem, you are just giving a test that fails. Commented Nov 19, 2015 at 17:40
  • I think the very top of the question mentions the functionality I am seeking.. how to serialize/deserialize a HashMap using Gson. What kind of specifics would be required apart from that for desired behavior? I'd like to serialize the Java HashMap above, save it to a file, and then deserialize the string as well Commented Nov 19, 2015 at 17:46
  • That is not a problem, it is a description of what you are trying to do. "The test-for this fails however:" How does it fail? What exception occurs? Commented Nov 19, 2015 at 17:46
  • Thanks for the suggestion, I have added the exception output, a sample json output and where it fails. Commented Nov 19, 2015 at 17:59
  • The exception is occurring in your printMap method. Please give the code for that. Commented Nov 19, 2015 at 18:11

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.