Hi y'all. I'm looking for feedback and discussion on the use of annotations to eliminate the boilerplate code for linking buttons and methods. Hopefully this will be especially useful in RAD or rapid prototyping environments.
Over the weekend I hacked together a little proof of concept that supports two ways of doing this - one by annotating the button with the name of its associated method, the other by annotating the method with the name of its associated button...

@ActionMethod(name = "okMethod")
JButton okButton = new JButton("OK");

or

@ActionMethod(button = "okButton")
public void okMethod(ActionEvent e) { ...

All that's required from the "user" is a single call

ActionMethodHandler.activate(this);

In either case, in the background I use reflection on the class to find these annotations and add an action listeners to the buttons to call the methods.

So - opinions please
Is this a good idea or should I bury it quickly before it does any harm?
If it is a good idea, which version is better, any why?
Is there a third option that's better than both?

Don't be shy.
J

Recommended Answers

All 11 Replies

another java forum, and don't forget something about crosspost ....

another java forum, and don't forget something about crosspost ....

??? This is the only forum I've posted this in.

I think that your question (Swing + Annotations + BackGroungTask + Reflections) isn't question for this forum, but for another Java Forum(s)

maybe splitOut your question for Swing + Annotations and Task + Reflections,

or you have to wait for two??? gurus from US, sure maybe is jwenting around

maybe splitOut your question for Swing + Annotations and Task + Reflections

Can't split them, they are all integral to the solution. Forget the "background task" - what I really meant was that there was some processing of the annotations that was done "out of sight" of the user to make this work. Basically you add the annotations then call a single method that uses Reflection to scan your class, find the annotated fields/methods, creates suitable ActionListeners. and adds them to the appropriate fields.

:-)

I originally thought that based on positive/negative comparisons you'd create endUserGUI in the background Task

hmmm comes: maybe I had wrong view, because this descriptions touch SingleSingOn, where Ldap or AD sending basic access to "Autentificator", and and after successful userLogin is generated proper GUI

James, a side by side comparison using a non-trivial example would be helpful in evaluating this. My reasoning being if the LOC/effort being saved isn't significant, there is no need to ditch the compile time checks IMO. Plus, given that no source code is supplied, you might want to delve a bit deeper on how it works under the hood.

Thanks for the reply. This is something I wrote myself during the weekend, so I have all the source code both on disk and in my head! I'm happy to post it if anyone's interested, but in short, after setting up your window you call a single method that scans the view and controller instances for these annotations, validates that the source object is accessible and supports addActionListener(ActionListener), validates that the method is accessible and has the right signature, then adds a little ActionListener to the source that simply calls the method. This is all done using simple Reflection methods.
As for with/without comparisons, here's a little sample:
Suppose we have a JButton and a method we want to execute when the button ispressed:

//before
JButton myButton = new JButton("ok");
myButton.addActionListener(new ActionListener() {
   public void actionPeformed(ActionEvent e) {
     myButtonMethod(e);
   }
});

//after
@ActionMethod(method = "myButtonMethod")
JButton myButton = new JButton("ok");

Now multiply that by the number of (buttons + toolbar items + menu items) in the window.
Of course you can have a single Action handler for all of them, then get the actionCommand, but then you have a hideous set of if tests to call the right methods (until Java 7 gives us switches on Strings). This also puts the code that links buttons to methods in a third place that's not obvious from either.

What I'm particularly interested to hear opinions about is whether to annotate the source component with its method, or annotate the method with a list of ActionEvent sources that can call it (or do both and cross-validate them?).
Thanks for your time
J

I don't do a lot of UI programming but a few more queries/suggestions:

  • What kind of targets are supported by this annotation?
  • How well does this annotation cope up with dynamically created UI components (think of a calculator)? Maybe an example? And how would the method `ActionMethodHandler.activate(this);` come into play with dynamic components?
  • What's the behaviour when ActionMethodHandler is called multiple times? It simply returns? Overrides the previous bindings?
  • Any error/warning shown when the user uses conflicting configuration (i.e. method "abc()" is annotated for button "Btn1" whereas "Btn1" actually refers method "xyz()")?

I personally feel that the same annotation name used for both cases is a bit confusing. How about @ActionMethod decorator for methods and @ActionedComponent for the targeted Swing components?

1. When annotating a field the ActionMethodHandler.activate(...) gets the object currently referred to by the field and checks whether that object has an addActionListener(ActionListener) method. If so, it adds the listener. Thus it works for buttons, menu items, etc but logs an error for objects without that method.
2. See 1. It adds a listener to the object referred to by the annotated field at the time that activate is called - so it's essentially a static kind of thing. I don't see alot wrong with the ordinary way of doing things in these more complex cases; I was really thinking about the ordinary day-to-day stuff where you have 24 menu items, 12 toolbar icons and 6 buttons, each of which simply binds to one action handling method.
3. The current proof of concept code just adds another action listener - this obviously needs to be better if I take this any further, but considering the intended use maybe its enough to log an error and return if called twice for the same view or controller object.
4. No. I implemented both ways of annotating to see which felt better. Currently I'm leaning towards just annotating the field because one JComponent typically has just one action method, but the same action method may be called from different components (eg menu item, toolbar icon).
5. Yes. I had the same name while hacking this POC together because it's one less file. I'm expecting one or the other usage not to make it into any further development.

1. When annotating a field the ActionMethodHandler.activate(...) gets the object currently referred to by the field and checks whether that object has an addActionListener(ActionListener) method. If so, it adds the listener. Thus it works for buttons, menu items, etc but logs an error for objects without that method.

When I mentioned 'target', I was actually referring to @Target annotation.

Sorry, misunderstood. The current annotation definition is
@Target({ElementType.METHOD , ElementType.FIELD})
but that's just because I'm using the same annotation for two different purposes for now. Obviously that will change in the next iteration.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.