Done with mirrors: Use Reflection to catch generic actions

Although Swing's event system is powerful, it's also complex. Handling events from menus can be particularly tedious. Find out a better way using Java's Reflection API.

This week's Java tip was submitted by Muhammad Junaid Shahid from Pakistan. Junaid got tired of the complicated way menu and toolbar events must be handled in Swing and AWT and came up with the following novel workaround.

Flexible but complicated event systems
Both AWT and Swing support a flexible and powerful event-handling mechanism. But for some simple tasks, such as handling menu and toolbar commands, it requires much more work than necessary.

Let's say that you want to make an application with 15 menu items. Normally, you would make 15 ActionListener (or Action) classes and then bind them to the menu items. In most applications, all of these classes will contain only the actionPerformed() function, which will do the required task. It would be much simpler if you could make the MFC style OnActionName functions in your main application class and let the framework automatically call the corresponding function for each menu item selected by the user without the need for any extra class for each action.

One way to do this is to use a single ActionListener for all actions and use a giant if-elseif construct to transfer control to the appropriate handler. But if there are a lot of actions, this construct will really become a mess. A much cleaner approach is to use Java's Reflection API to dynamically generate the name of the function to call.

Consider the code snippet in Listing A as an example.

This program contains two menu items. When one of these is selected, control passes to the actionPerformed() method of the object dispatcher. For simplicity, we assume that the menu item name does not contain any spaces or other characters that cannot be part of a method name. The dispatcher gets the menu item name, obtains the corresponding Method object with Class.getMethod(), and then invokes the method using Method.invoke(). In this way, you can add many menu items without creating separate listener classes for each of them.

An even simpler solution
If you use the Action class instead of ActionListener, the mechanism can become simpler and more flexible. Listing B implements the above example using Action.

This approach alleviates the need to manually add the listener to each item and is also a bit more efficient because of obtaining the Method object only once.

Editor's Picks