Event Handler Registration in Java
Can you elaborate on that a bit? I fell like I do have a common interface (Callback) which prevents the dispatching method from having to do anything outlandish. For instance if I catch an exception and want to send it to the onError callback it looks something like 

for (Callback cb : callbacksFor(Event.ERROR))
    cb.call(this, someException);. 

  
  That's the dispatching method, right?


Right.

Problem here is that you pass the current object (having a state an business logic) as data to the callback. But you should only sent data transfer objects (without business logic and immutable by any chance).

So the common interface of the callback should look like this:

interface Callback{
   enum Key {EXCEPTION, DATA_1,DATA_2,DATA_3, ... }
   void onError(Map&lt;Key, Object);
}


and you sample would change to:

Map&lt;Key, Object&gt; currentState = copyInstanceMembersToMap(); 
currentState.put(Key.EXCEPTION, someException);
for (Callback cb : callbacksFor(Event.ERROR))
    cb.call(currentState);


Then the callbacks themselves decide which data to use. 

And you can use the same callback interface for other listeners as well.

Unfortunately you loose the type safety for the values in that map. 
But you could get that back a little:

public abstract class GenericEnum {
    enum Key {
        EXCEPTION {
            @Override
            public &lt;Exception&gt; Exception getFrom(Map&lt;Key, Object&gt; map) {
                return (Exception) map.get(this);
            }
        },
        DATA_1 {
            @Override
            public &lt;String&gt; String getFrom(Map&lt;Key, Object&gt; map) {
                return (String) map.get(this);
            }
        },
        DATA_2 {
            @Override
            public &lt;File&gt; File getFrom(Map&lt;Key, Object&gt; map) {
                return (File) map.get(this);
            }
        };
        public abstract &lt;T&gt; T getFrom(Map&lt;Key, Object&gt; map);
    }

    public static void main(String[] args) {
        Map&lt;Key, Object&gt; testMap = new HashMap&lt;&gt;();
        testMap.put(Key.EXCEPTION, new java.lang.Exception());
        testMap.put(Key.DATA_1, "test");
        testMap.put(Key.DATA_2, new File(System.getProperty("user.home")));
        Exception value1 = Key.EXCEPTION.getFrom(testMap);
        String value2 = Key.DATA_1.getFrom(testMap);
        File from = Key.DATA_2.getFrom(testMap);
        String value3 = Key.DATA_2.getFrom(testMap); // ClassCastException

    }

}