{"id":1612,"date":"2011-05-04T20:23:15","date_gmt":"2011-05-04T19:23:15","guid":{"rendered":"http:\/\/www.gamlor.info\/wordpress\/?p=1612"},"modified":"2021-07-03T13:32:17","modified_gmt":"2021-07-03T12:32:17","slug":"elegant-event-handling-in-java","status":"publish","type":"post","link":"https:\/\/www.gamlor.info\/wordpress\/2011\/05\/elegant-event-handling-in-java\/","title":{"rendered":"Elegant Event Handling in Java"},"content":{"rendered":"<p>Event handling is something very common, especially in desktop application. So how does you\u2019re event handling code look like? Something like this?<\/p>\n<script src=\"https:\/\/gist.github.com\/955775.js?file=HandleEvents.java\"><\/script><noscript><pre><code class=\"language-java java\">private final Set&lt;NoArgumentEvent&gt; events= new HashSet&lt;NoArgumentEvent&gt;();\n\npublic void somethingChanged(){\n\tfor (NoArgumentEvent eventHandler : events) {\n\t\teventHandler.eventOccurred();\n\t}\n}\n\npublic Disposable addSimpleEvent(NoArgumentEvent event) {\n    return events.add(event);\n}<\/code><\/pre><\/noscript>\n<div id=\"attachment_1616\" style=\"width: 310px\" class=\"wp-caption aligncenter\"><a href=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2011\/05\/handle-events.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-1616\" class=\"size-medium wp-image-1616\" title=\"handle-events\" src=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2011\/05\/handle-events-300x218.png\" alt=\"Handling Events\" width=\"300\" height=\"218\" srcset=\"https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2011\/05\/handle-events-300x218.png 300w, https:\/\/www.gamlor.info\/wordpress\/wp-content\/uploads\/2011\/05\/handle-events.png 900w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-1616\" class=\"wp-caption-text\">Handling Events<\/p><\/div>\n<p>Of course you don\u2019t want to have this kind of code in every class. Therefore you create a special event-handling class. That class manages all registered events and can fire the event to all listeners.<\/p>\n<p>But how do you do that when there are multiple event types? Then the types are represented by different interfaces with different method signatures. You really want to handle all these events with the same event-handler class. Let\u2019s take a look at my solution. Here\u2019s an example where I handle different events:<\/p>\n<script src=\"https:\/\/gist.github.com\/955775.js?file=Generalhandling.java\"><\/script><noscript><pre><code class=\"language-java java\">\/\/ 1. Create a 'EventListeners'-instance for handling events\nprivate final EventListeners&lt;NoArgumentEvent&gt; simplerEvents = EventListeners.create(NoArgumentEvent.class);\nprivate final EventListeners&lt;ComplexEventHandler&gt; complexEvent = EventListeners.create(ComplexEventHandler.class);\n\n\npublic void somethingSimpleChanged(){\n\t\/\/ 2. I just can get the invoker, and then call the right method on it.\n\t\/\/ This works for every kind of interface.\n\tsimplerEvents.invoker().eventOccurred();\n}\n\npublic void somethingComplexChanged(){\n\tcomplexEvent.invoker().ohMyGod(&quot;complex&quot;,&quot;more complex&quot;,42);\n}\n\n\/\/ Delegate adding events\npublic Disposable addSimpleEvent(NoArgumentEvent event) {\n\treturn simplerEvents.add(event);\n}<\/code><\/pre><\/noscript>\n<p>As you see I use the EventListeners for representing an event. To register events I just call the add-method on it. Now to the real cool part: To fire the event, I get the invoker and just call the method I want to. That method can by any method of the event-handler interface. That makes it very flexible; I can use this for any kind of event-handler interface! I haven\u2019t seen a more elegant way to handle events in Java yet.<\/p>\n<p>How is this implemented? The internally implements the usual add\/remove and invoke-logic, but with a twist. It uses the generic argument for handling everything. For the invoke-part it creates a dynamic proxy object of the generic argument. That is the object which is returned by the invoker()-method. When you call any method on that object, it will delegate that invoke to all listeners. (Yes, for the .NET guys, that somewhat a reimplementation of a multi-cast delegate).<\/p>\n<script src=\"https:\/\/gist.github.com\/955775.js?file=EventListeners.java\"><\/script><noscript><pre><code class=\"language-java java\">public final class EventListeners&lt;T&gt; implements Disposable {\n    private final Set&lt;T&gt; listeners = new HashSet&lt;T&gt;();\n    private final T invoker;\n\n    public EventListeners(Class classInfo) {\n        this.invoker = buildInvoker(classInfo);\n    }\n\n    @Override\n    public void dispose() {\n        listeners.clear();\n    }\n\n    public Disposable add(final T event) {\n        listeners.add(event);\n        return new Disposable() {\n            @Override\n            public void dispose() {\n                removeHandler(event);\n            }\n        };\n    }\n\n    public T invoker() {\n        return invoker;\n    }\n\n    public static &lt;T&gt; EventListeners&lt;T&gt; create(Class classInfo) {\n        return new EventListeners&lt;T&gt;(classInfo);\n    }\n\n    private void removeHandler(T event) {\n        listeners.remove(event);\n    }\n\n    private void invokeEventHandling(Method method, Object[] args) {\n        for (T listener : listeners) {\n            try {\n                method.invoke(listener, args);\n            } catch (Exception e) {\n                reThrow(e);\n            }\n        }\n    }\n\n\n\n    private T buildInvoker(Class classInfo) {\n        return (T) Proxy.newProxyInstance(classInfo.getClassLoader(),\n                new Class[]{classInfo},\n                createInvocationHandler());\n    }\n\n    private InvocationHandler createInvocationHandler() {\n        return new InvocationHandler() {\n            @Override\n            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n                invokeEventHandling(method, args);\n                return null;\n            }\n        };\n    }\n}\n<\/code><\/pre><\/noscript>\n<p>For my implementation I just used a <a href=\"http:\/\/download.oracle.com\/javase\/6\/docs\/api\/java\/lang\/reflect\/Proxy.html\">Java proxy<\/a> instance. Of course the implementation adds overhead to the call and only works with interfaces. For a more advanced implementation you could use a code generator library. That probably would speed up things and also allow classes as event-handlers.<\/p>\n<p>That\u2019s it. I handle my event this way in Java. If you found an event more elegant way, let me know.<\/p>\n<p>P.S. I\u2019m wondering if I should start a small Java library which contains all these kinds of small tricks I\u2019m posting here. Hmm\u2026<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Event handling is something very common, especially in desktop application. So how does you\u2019re event handling code look like? Something like this? Of course you don\u2019t want to have this&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[15],"tags":[218,295],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/1612"}],"collection":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/comments?post=1612"}],"version-history":[{"count":7,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/1612\/revisions"}],"predecessor-version":[{"id":3891,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/posts\/1612\/revisions\/3891"}],"wp:attachment":[{"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/media?parent=1612"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/categories?post=1612"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gamlor.info\/wordpress\/wp-json\/wp\/v2\/tags?post=1612"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}