简体   繁体   中英

Unsafe generic cast when deserializing a Collection

public Configuration(Node node, File file) {
    HashMap<String, String> conf = (HashMap<String, String>) SerializationUtils.deserialize(new FileInputStream(file));
}

I understand why this gives an unsafe cast warning, but what's the best/accepted way to do this safely? Is there any good way?

You cannot handle this situation in an entirely type-safe way using only the Java language.

Because this is something that has to be done repeatedly and you can't really get around it, I suggest using a genreic method to and to read and cast generic objects:

@SuppressWarnings("unchecked")
public static <T> T readObject(
    ObjectInputStream in
) throws IOException, ClassNotFoundException {
    return (T)in.readObject();
}

However, I suggest that you don't generally use methods like this to suppress valid warnings.

There's not really any way of doing this properly because the compile-time type information you want to check (ie String ) is not available at runtime, (ie when the cast actually occurs) through the process known as erasure . I think that the best way is for you to pass your deserialized collection thru some bespoke "checker":

Map<?,?> conf = deserialize(rsrc);
Map<String, String> checked = checkMap(conf, String.class, String.class);
//can use checked freely

where:

@SuppressWarnings("unchecked")
public static <K, V> Map<K,V> checkMap(Map<?,?> map, Class<? extends K> k, Class<? extends V> v) {
    for (Map.Entry<?, ?> e : map) {
        k.cast(e.getKey());   //will throw ClassCastException
        v.cast(e.getValue());
    }
    return (Map<K,V>) map; //unchecked 
}

To build on the earlier answer, I usually go a little further when suppressing warnings. I put the annotation on a local variable instead of the method, to reduce the scope of the suppression. This means that if anyone comes along an augments the method later, there will not be an unintentional suppression. It does add another line of code, but I think the trade off is worth it.

public static <T> T readObject(
    ObjectInputStream in
) throws IOException, ClassNotFoundException {
    @SuppressWarnings("unchecked")
    T val = (T)in.readObject();
    return val;
}

Unfortunately you cannot add an annotation to an expression (at least not yet).

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