Skip to main content

How to determine if component has an addNewListener method

5 replies [Last post]
scheide
Offline
Joined: 2004-06-02
Points: 0

OK, the answer may have something to do with reflection, or it may be easier than that... here's the goal:

Basically I am creating a high-level method that passes in any type of JComponent. In the method all I know is that the component is a JComponent. I am doing something common on all components, no matter what they are. But beyond that I want to know if the component has an addActionListener method available on it, and if it does then I will add one. How can I determine programatically in this high-level method whether a JComponent has an addActionListener method?

For example, the component could be a textfield, a button, a textarea, etc. The first two mentioned have an addActionListener method, the last of the three does not. I'd like to avoid writing extensive "if (component instanceof JButton)..." type of branching. Hmmm...is there something all components that have an addActionListener method share which I can try to cast them to, and catch those that fail with a ClassCastException? I'm stumped.

Hope this makes sense and some smart person out there can give me a clue. Thanks!

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
shan-man
Offline
Joined: 2006-02-17
Points: 0

Hi scheide,

This little program shows one way to do it:
[code]
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;

public class CheckFor {
public static void main(String[] args) {
JTextField field = new JTextField();
JButton button = new JButton();
JTextArea area = new JTextArea();

if (hasActionListener(field)) {
System.out.println("JTextField has 'addActionListener'");
} else {
System.out.println("JTextField does not have 'addActionListener'");
}

if (hasActionListener(button)) {
System.out.println("JButton has 'addActionListener'");
} else {
System.out.println("JButton does not have 'addActionListener'");
}

if (hasActionListener(area)) {
System.out.println("JTextArea has 'addActionListener'");
} else {
System.out.println("JTextArea does not have 'addActionListener'");
}
}

public static boolean hasActionListener(JComponent c) {
try {
// this will throw an exception if the method doesn't exist
c.getClass().getMethod("addActionListener",
new Class[] {ActionListener.class});
return true;
} catch (NoSuchMethodException e) {
return false;
}
}
}
[/code]
Basically, you fetch the component's associated class object and call getMethod(), watching for an exception. Alternatively, you could call getMethods() and search the returned array for the name you want.

Hope that helps, and thanks for the fun exercise!
Shannon

joecole
Offline
Joined: 2003-06-10
Points: 0

Shan man,

It has always bewildered me that the methods such as addActionListener, removeActionListener and getActionListeners were not defined in an interface. It would make this type of problem very easy, which I have come across many times, and would be extremely easy to implement.

Could you enlighten me?

Joe Cole

scheide
Offline
Joined: 2004-06-02
Points: 0

Hmm... this only solves half the problem, Shan-man. In this case it seems I really do need the interface someone else mentioned. Here's why:

In your example, I say "if (hasActionListener (JComponent c))"
and I can get back true, but now how do I add one?

I mean, I can't generically says JComponent.addActionListener because not all JComponents have that method. If they shared a common interface, I could cast the component to the interface and then add one, but I don't see how to add one on the component in the situation I first described, even if I know the component has that method. See what I mean?

I am, it seems, stuck. Count me amongst those who wish there was some sort of interface shared by the components having this method. This is just one example of this sort of problem/limitation, of course, and I wish the Swing team would consider helping us here. Thanks for your answer and any other thoughts you may wish to share.

zander
Offline
Joined: 2003-06-13
Points: 0

See java.lang.reflect.Method
It is created by Class.getMethod() and you can invoke() it.

Don't you love reflection :)

joecole
Offline
Joined: 2003-06-10
Points: 0

More specifically, you could code it like this:

public void addActionListenerTo(Object object, ActionListener listener){

Method addActionListener = object.getClass().getMethod("addActionListener", new Class[]{ActionListener.class});
addActionListener.invoke(object, new Object[]{listener};

}

You will obviously have to handle all the exceptions. I think this is right, I am doing it from memory.

You can easily write wrapper methods for things like these - but why should we have to? Reflection is markedly slower and quite ugly to inexperienced coders. It is best to hide the reflective code in the background wrapper classes because it is not nice to read.

Again, any news on why we couldn't have an interface?

It was a real pain coding for every given listener - i wrote some code once that removed via reflection all unused references to help with garbage collection (anyone who has written a complex swing application knows that memory leaks are a big issue - and not easily resolvable).

Thoughts?