0

I'm writing a wrapper for JSON Jackson pojo serialization/deserialization. So I tried to write a generic method that will return me the deserialized object generically.

I think the code would explain this better:

public <K,V, M extends Map<K, V>> M readMap(String path, Class<M> mapType, Class<K> keyClass, Class<V> valueClass) throws JsonParseException, JsonMappingException, IOException
{
    ObjectMapper mapper = new ObjectMapper();
    return mapper.readValue(new File(path), mapper.getTypeFactory().constructMapType(mapType, keyClass, valueClass));
}

The code

HashMap<String, Double> weightMap;
JSONParsedFileHandler reader = new JSONParsedFileHandler();
weightMap = reader.readMap("weights.model", HashMap.class, String.class, Double.class);

This works as expected, however, I get a type safety warning:

Type safety: The expression of type HashMap needs unchecked conversion to conform to HashMap<String,Double>

I figured this mean that the type returned is as expected except it is not parameterized as I coded.

Does anyone have any thoughts?

Eugene Krapivin
  • 1,671
  • 2
  • 17
  • 32

2 Answers2

1

The constructMapType method returns MapType, which uses Class<?> to define the keys and the content. With type erasure that basically translates to Object and there is no way for the compiler to tell what types are used in the map. The type is "parameterized as (you) coded", but Java's implementation of generics prevents any run-time knowledge of the type that you provided. Someone correct me if I'm wrong, but I believe you're only options are to deal with the warning or suppress it.

Dave
  • 4,282
  • 2
  • 19
  • 24
1

Try bounding to just the maps's class and declare the return type from K and V only:

public <K,V, M extends Map<?, ?>> Map<K, V> readMap(String path, Class<M> mapClass, Class<K> keyClass, Class<V> valueClass) throws JsonParseException, JsonMappingException, IOException {
    ObjectMapper mapper = new ObjectMapper();
    return mapper.readValue(new File(path), mapper.getTypeFactory().constructMapType(mapClass, keyClass, valueClass));
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • This solution actually compels the caller of the method to do casting (you have to explicitly cast from Map to HashMap). The reason I tried to do generic return type is to avoid it. – Eugene Krapivin Oct 05 '13 at 18:11
  • 1
    Best practise is that the caller (actually all code) should not declare the variable type as HashMap (the implementation), but just Map (the abstract type), because it doesn't matter what the implementation is - it only matters that it's a Map. See [Liskov substitution principle](http://en.wikipedia.org/wiki/Liskov_substitution_principle). If you declare the variable as Map, you'll have better code and won't need to cast. – Bohemian Oct 05 '13 at 19:58
  • thats true - however it doesn't make the warning go away :) but it's a good tip. – Eugene Krapivin Oct 06 '13 at 17:39