0

I'm saving a score (KillcountRatio class) to a name (String) in a HashMap that I am saving with Jackson JSON, but when loading the saved json file, it is unable to cast the KillCountRatio class value stored in the HashMap with a certain key to KillCountRatio, it gives

java.util.LinkedHashMap cannot be cast to KillCountRatio

because the value stored in the HashMap is no longer a KillCountRatio, rather is a LinkedHashMap.

Not sure what to try.

Here is KillCountRatio class:

public final class KillCountRatio {

    private int killCount;

    private int deathCount;

}

Here is the HashMap where the above is stored and given a String key and then saved with Jackson JSON.

private HashMap<String, KillCountRatio> savedScores = new HashMap<>();

saving and loading:

public void save() {
    ObjectWriter  writer = new ObjectMapper().writer().withDefaultPrettyPrinter();
    File f = new File("data/savedScores.json");
    try {
        writer.writeValue(f, savedScores); //written here
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void load() {

    savedScores = new ObjectMapper().readValue(new File("data/savedScores.json"), new HashMap<String, KillCountRatio>().getClass());
}

This is the error:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.datarepo.KillCountRatio

What can I do to overcome this casting error? Some examples using the above code of how I can get this to work would be appreciated.

I tried this deserializer with the load method and it still gave the same error:

ObjectMapper mapper = new ObjectMapper();
        SimpleModule module = new SimpleModule();
        module.addDeserializer(KillCountRatio.class, new KillCountRatioDeserializer());
        mapper.registerModule(module);

I also tried annotating the KillCountRatio class with this:

 @JsonDeserialize(using = KillCountRatioDeserializer.class)
joe00113
  • 15
  • 4
  • use LinkedHashMap while reading? - `savedScores = new ObjectMapper().readValue(new File("data/savedScores.json"), new LinnkedHashMap().getClass());` – Rishikesh Dhokare Jun 10 '19 at 09:41

1 Answers1

0

The reason this doesn't work is because of how generics work in Java, you might want to read up a bit on type erasure.

You are trying to tell it that it's supposed to read a Map whose keys are Strings and whose values are KillCountRatios, but what the runtime version sees is that it's just supposed to read a Map (because that's all the info that's retained). And since the default behavior of the ObjectMapper is to read an unknown JSON object into a HashMap (in this case, a LinkedHashMap to preserve field order), that's exactly what it'll do.

To make the ObjectMapper correctly deserialize your JSON object into a KillCountRatios object, you will have to write your own deserializer (see a short tutorial here).

Piotr Wilkin
  • 3,228
  • 7
  • 18
  • I tried to add a deserializer to this but still gave the same error. I've edited the OP – joe00113 Jun 10 '19 at 10:22
  • That is not where you need to add it. The problem is that the deserializer has no way to know that the values of the map will be `KillCountRatio`s. You're trying to tell it "deserialize `KillCountRatio`s using my deserializer", but the problem is that it doesn't know that they should be `KillCountRatio`s in the first place. – Piotr Wilkin Jun 10 '19 at 11:26
  • Here's a good tutorial: https://www.baeldung.com/jackson-map, in short - you have to pass a `TypeReference` to the deserializer to make it know what the `Map` key and value types will be. – Piotr Wilkin Jun 10 '19 at 11:29