Search code examples
javagenericscastingwildcardclasscastexception

Generics wildcard isnt capable to cast to Generictype


I came across a problem I wasn't able to find a solution for.

I often make use of a mapping where the key and value are objects with matching generictypes. For each pair the generics should match. Though the generictypes between entries may varry. (Ill include an example for clarity). This can easily be accomplished with the use of the wildCard. although because of this, you cannot use the key or value in combination with eachother.

Consider the example included at the bottom. there is no (easy) way to modify the map to run into Cast exceptions. Though I still won't be able to use the map like I tried within useEntries(). So my question is, is there a workaround for this? Thanks in advance!

public class GenericWildcardTest
{   
    static Map<GenericObject<?>, Function<?, ?>> map = new HashMap<>();

    public static <S> void put(GenericObject<S> genericObject, Function<S, S> function)
    {
        map.put(genericObject, function);
    }

    public static void useEntries()
    {
        for(Entry<GenericObject<?>, Function<?, ?>> currentEntry : map.entrySet())
            //The #apply(); part simply wont compile because of cast errors.
            currentEntry.getKey().set(currentEntry.getValue().apply(currentEntry.getKey().get()));
    }



    // Simple Object with generic.
    static class GenericObject<T>
    {
        private T object;

        public GenericObject(T object)
        {
            this.object = object;
        }

        public void set(T object)
        {
            this.object = object;
        }

        public T get()
        {
            return this.object;
        }
    }
}

Solution

  • Here's how you can do it with casting:

    @SuppressWarnings("unchecked")
    public static <S> void useEntries() {
        for(Entry<GenericObject<?>, Function<?, ?>> currentEntry : map.entrySet()) {
            GenericObject<S> key = (GenericObject<S>)currentEntry.getKey();
            Function<S, S> value = (Function<S, S>)currentEntry.getValue();
            key.set(value.apply(key.get()));
        }
    }
    

    This answer assumes that your map indeed contains Function<S, S>, not Function<GenericObject<S>, S>.