Geertjan's Blog

  • May 30, 2011


Geertjan Wielenga
Product Manager
Sometimes you'd like to register random annotations into the layer for an action. However, everything is currently predefined. Here's my proposal for how to fix that, note the section in bold:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import org.openide.awt.ActionRegistration;
import org.openide.awt.ActionReference;
import org.openide.awt.ActionReferences;
import org.openide.awt.ActionID;
import org.openide.awt.ActionSupplemental;
import org.openide.awt.ActionSupplementals;
import org.openide.util.NbBundle.Messages;
@ActionID(category = "Edit",
id = "org.demo.SomeAction")
@ActionRegistration(displayName = "#CTL_SomeAction")
@ActionReference(path = "Menu/File", position = 1300)
@ActionSupplemental(key = "foo1", value = "bar1"),
@ActionSupplemental(key = "foo2", value = "bar2"),
@ActionSupplemental(key = "foo3", value = "bar3")

public final class SomeAction implements ActionListener {
public void actionPerformed(ActionEvent e) {
// TODO implement action body

When compiled, you get this, note again the section in bold:

<folder name="Actions">
    <folder name="File">
        <file name="org-demo-action-SomeAction.instance">
                bundlevalue="org.demo.action.Bundle#CTL_SomeAction" name="displayName"/>
                methodvalue="org.openide.awt.Actions.alwaysEnabled" name="instanceCreate"/>
            <attr name="delegate" newvalue="org.demo.action.SomeAction"/>
            <attr boolvalue="false" name="noIconInMenu"/>
            <attr name="foo1" stringvalue="bar1"/>
            <attr name="foo2" stringvalue="bar2"/>
            <attr name="foo3" stringvalue="bar3"/>

<folder name="Menu">
    <folder name="File">
        <file name="org-demo-action-SomeAction.shadow">
            <attr name="originalFile" stringvalue="Actions/File/org-demo-action-SomeAction.instance"/>
            <attr intvalue="0" name="position"/>

To get to the above point, I defined two new classes in openide.awt as follows:

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface ActionSupplemental {
String key() default "";
String value() default "";
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PACKAGE})
public @interface ActionSupplementals {
ActionSupplemental[] value();

And they are used in the ActionProcessor like this:

ActionSupplemental asup = e.getAnnotation(ActionSupplemental.class);
if (asup != null) {
processSupplemental(e, asup, f);
ActionSupplementals refs = e.getAnnotation(ActionSupplementals.class);
if (refs != null) {
for (ActionSupplemental actionSupplemental : refs.value()) {
processSupplemental(e, actionSupplemental, f);
private void processSupplemental(Element e, ActionSupplemental sup, File f) throws LayerGenerationException {
f.stringvalue(sup.key(), sup.value());

It would be good to also let the user specify a type, since right now the assumption is that everything is a string. Here's the related issue, which also describes a usecase relating to the NetBeans Ribbon Bar: http://netbeans.org/bugzilla/show_bug.cgi?id=198731

Join the discussion

Comments ( 3 )
  • emxsys Tuesday, May 31, 2011
    Hi Geertjan. This is great! Is to correct to assume I'd have to re-build the platform-src to try this out?
    -- Bruce
  • emxsys Tuesday, May 31, 2011
    I attempted to create my own ActionSupplementalsProcessor to simply write out the @ActionSupplemental(s) annotations, but alas, it overwrites the ActionRegistration file in the generated-layer.xml. I guess I'll have to wait for the patch.
  • Geertjan Tuesday, May 31, 2011
    Yeah, I went into the openide.awt folder in the NetBeans sources and added the code above then rebuilt the IDE. You could do the same. Also, please go into the issue referred to at the end of the blog entry above and add your thoughts there.
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.