Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does this cause heap pollution with varargs?

I am getting the warning:

[unchecked] Possible heap pollution from parameterized vararg type Class

But I am unsure if it will actually pollute:

public void register(EventListener listener, Class<? extends Event>... eventTypes) {}

Here is the complete implementation if that is necessary:

public class EventDispatcher {

    public static ConcurrentLinkedQueue<Event> eventQueue;
    public static ConcurrentHashMap<Class<? extends Event>, CopyOnWriteArrayList<EventListener>> eventsListenerMap =
            new ConcurrentHashMap<>();

    public static void register(EventListener listener, Class<? extends Event>... eventTypes) {
        for (Class<? extends Event> eventType : eventTypes) {
            if (eventsListenerMap.containsKey(eventType)) {
                eventsListenerMap.get(eventType).addIfAbsent(listener);
            } else {
                CopyOnWriteArrayList<EventListener> initializingListeners =
                        new CopyOnWriteArrayList<>();
                initializingListeners.add(listener);
                eventsListenerMap.put(eventType, initializingListeners);
            }
        }
    }
}

I am all up for OT-suggestions for improving this, too, but keep in mind that this class is unfinished.

like image 396
zsawyer Avatar asked Jun 30 '13 17:06

zsawyer


2 Answers

The warning about generic varargs is related to the dangers of generic arrays. Theoretically the method could abuse array covariance with the passed in array to cause heap pollution, for example:

Class<?>[] eventTypesWithWidenedType = eventTypes;
eventTypesWithWidenedType[0] = String.class;
Class<? extends Event> eventType = eventTypes[0]; // liar!

But it's fine as long as the method implementation doesn't do anything silly like that. Some basic precautions would be:

  • Don't do any assignment to eventTypes.
  • Don't return or otherwise expose eventTypes outside the method.

With Java 7, you could annotate the method with @SafeVarargs, which basically promises the compiler that generic arrays are okay (meaning it's no longer on the caller to suppress the warning).

like image 53
Paul Bellora Avatar answered Nov 20 '22 12:11

Paul Bellora


Whenever you have varargs that are genericized (for example, a genericized list) you have a possibility of heap pollution. For example:

public void doSomethingWithStrings(List<String>... strings) {
    Object[] objectArray = strings; //Valid because Object is a valid supertype 
    objectArray[0] = Arrays.asList(new Integer(42)); //Heap pollution

    String string = strings[0].get(0); //Oops! ClassCastException!
}

In your example, you have Class<? extends Event> eventTypes... which falls prey to the same problem:

public static void register(EventListener listener, Class<? extends Event>... eventTypes) {
    Object[] objectArray = eventTypes;
    objectArray[0] = String.class; //Heap pollution

    ...
    ...
}

Java is just warning you that there is a potential heap-pollution solution. In Java 7, the warnings are generated at the declaration of the method as well whereas in previous versions it was only at the call-sites.

If you are certain that heap-pollution cannot occur, you can suppress the warning using the @SafeVarargs annotation.

like image 2
Vivin Paliath Avatar answered Nov 20 '22 12:11

Vivin Paliath