Geertjan's Blog

  • April 2, 2008

Creating a Better Java Class Wizard

Geertjan Wielenga
Product Manager
At the end of my recent Javalobby article, Overview of NetBeans Java API Samples in Plugin Portal, two users asked for a more advanced wizard for Java classes, one that would let the user specify superclasses and interfaces right in the wizard. Fine. Let's create exactly that. If you work through everything in this blog entry, you will end up with a new template in the New File dialog:

When you click Next, you'll get everything as usual, except also the possibility to fill in superclasses and interfaces (all on the same panel, hurray):

On clicking Finish, you'll have a new class, with the superclasses and interfaces you specified generated automatically right into the class, and lightbulbs to click through to generate the import statements and required methods:

If you need this, or something like that, follow along below:

  1. Create a new module, called "FancyJavaClassTemplate", with code name base "org.netbeans.modules.fancy".

  2. In the New File dialog, use the Wizard wizard to create stubs for a new wizard, with "New File" under "Registration Type" and "1" in "Number of Wizard Panels":

  3. Type values in the final panel and click Finish. Then look at the generated sources. First look at the layer.xml file, then at the Java classes, and then at nbproject/project.xml.

  4. Use FancyVisualPanel1 to design the extra panel that you want to show, making sure that you call the first field "extField" and the second "impField" (because the code later on in this blog entry will assume that you've done so):

    Don't worry about the top part of what you see in the second screenshot above, because that's simply reused from the NetBeans internals, as you will see.

  5. Set dependencies on 'Datasystems API', 'Filesystem API', 'Java project Support', 'Nodes API', 'Project API', and 'Project UI API'.

  6. Open the class called "FancyWizardIterator.java". Rewrite the start of the getPanels() method as follows and make sure to also declare the packageChooserPanel, as shown below:

    private WizardDescriptor.Panel packageChooserPanel;
    private WizardDescriptor.Panel[] getPanels() {
    Project project = Templates.getProject(wizard);
    Sources sources = (Sources) project.getLookup().lookup(Sources.class);
    SourceGroup[] groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
    packageChooserPanel = JavaTemplates.createPackageChooser(project, groups, new FancyWizardPanel1());
    if (panels == null) {
    panels = new WizardDescriptor.Panel[]{
    String[] steps = createSteps();

    Fix imports and make sure that you have ALL of these as your import statements:

    import java.awt.Component;
    import java.io.IOException;
    import java.util.Collections;
    import java.util.NoSuchElementException;
    import java.util.Set;
    import javax.swing.JComponent;
    import javax.swing.event.ChangeListener;
    import org.netbeans.api.java.project.JavaProjectConstants;
    import org.netbeans.api.project.Project;
    import org.netbeans.api.project.SourceGroup;
    import org.netbeans.api.project.Sources;
    import org.netbeans.spi.project.ui.templates.support.Templates;
    import org.openide.WizardDescriptor;

  7. Install and see the results. You should see the panels shown at the start of this blog entry. But nothing will happen when you click Finish, yet. Probably the icon will be different. (You can set that by copying from another template, if you expand "this layer in context" in the layer.xml, then find another template that has the icon you want and choose "Open Layer File(s)". Then copy the attribute that points to the icon.)

  8. Go to the Template Manager under the Tools menu and open Classes | Java Class into the editor. You should see this:

    <#assign licenseFirst = "/\*">
    <#assign licensePrefix = " \* ">
    <#assign licenseLast = " \*/">
    <#include "../Licenses/license-${project.license}.txt">
    <#if package?? && package != "">
    package ${package};
    \* @author ${user}
    public class ${name} {

    Create a new empty file, call it "Fancy.ftl", and then copy all of the above into it. Then add the bit in bold below:

    <#assign licenseFirst = "/\*">
    <#assign licensePrefix = " \* ">
    <#assign licenseLast = " \*/">
    <#include "../Licenses/license-${project.license}.txt">
    <#if package?? && package != "">
    package ${package};
    \* @author ${user}
    public class ${name} ${extends} ${implements} {

  9. Open the layer.xml file and tweak it so that it has the same content as the below. Pay particular attention to the bits that are in bold and make VERY sure that your layer.xml file has these too after you've finished tweaking it:

    <folder name="Templates">
    <folder name="Classes"><file name="fancy.java" url="Fancy.ftl">
    <attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.fancy.Bundle"/>
    <attr name="instantiatingIterator" newvalue="org.netbeans.modules.fancy.FancyWizardIterator"/>
    <attr name="template" boolvalue="true"/>
    <attr name="SystemFileSystem.icon" urlvalue="nbresloc:org/netbeans/modules/java/resources/class.gif"/>
    <attr name="templateWizardURL" urlvalue="nbresloc:/org/netbeans/modules/fancy/fancy.html"/><attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>

    In other words, make sure that the first line in bold above has ".java" as the name's extension and that "Fancy.ftl" is set as the URL. Check to make sure that your template has exactly that name. It is case sensitive, so be careful. The second line in bold above is needed because that activates the FreeMarker scripting engine, which is what you need to have the NetBeans Platform do for you in order for the template to be generated correctly.

  10. Now we will pass the values from the panel into the template above. Firstly, in the visual panel, make the values in the text fields accessible:

    public String getExtension() {
    return extField.getText();
    public String getImplementation() {
    return impField.getText();

    Also add two fields to the top of the visual panel class:

    static final String EXTENSION = "extension";
    static final String IMPLEMENTATION = "implementation";

    In the wizard panel (i.e., NOT the visual panel), retrieve the above values:

    private String getExtensionFromVisualPanel() {
    return ((FancyVisualPanel1) component).getExtension();
    private String getImplementationFromVisualPanel() {
    return ((FancyVisualPanel1) component).getImplementation();

    Store the value by overriding the store method in the wizard panel:

    public void storeSettings(Object settings) {
    ((WizardDescriptor) settings).putProperty(FancyVisualPanel1.EXTENSION, getExtensionFromVisualPanel());
    ((WizardDescriptor) settings).putProperty(FancyVisualPanel1.IMPLEMENTATION, getImplementationFromVisualPanel());

  11. To wrap it all up together, implement the iterator's instantiate() method as follows:

    public Set instantiate() throws IOException {//Prepare the arguments for passing to the FreeMarker template:
    String extension = (String) wizard.getProperty(FancyVisualPanel1.EXTENSION);
    String implementation = (String) wizard.getProperty(FancyVisualPanel1.IMPLEMENTATION);
    Map args = new HashMap();
    args.put("extends", "extends " + extension);
    args.put("implements", "implements " + implementation);//Get the template and convert it:
    FileObject template = Templates.getTemplate(wizard);
    DataObject dTemplate = DataObject.find(template);//Get the package:
    FileObject dir = Templates.getTargetFolder(wizard);
    DataFolder df = DataFolder.findFolder(dir);//Get the class:
    String targetName = Templates.getTargetName(wizard);//Define the template from the above,
    //passing the package, the file name, and the map of strings to the template:

    DataObject dobj = dTemplate.createFromTemplate(df, targetName, args);//Obtain a FileObject:
    FileObject createdFile = dobj.getPrimaryFile();//Create the new file:
    return Collections.singleton(createdFile);

  12. You're finished! Install the plugin and now the template should create the file for you.

Homework assignments—figure out what should happen when the user types NOTHING in one of the new fields in the wizard. Should you do something in the code to catch that? The wizards can provide validation functionality, which you would need to enable, causing red error messages to appear in the panel under specified conditions, such as the fields not being (correctly) filled out. Or... should you make use of the FreeMarker template to add logic to it there so that if an empty string is passed, nothing is generated? Also, figure out how to HIDE the existing Java class wizard and let your own wizard replace it.

Further resources—FreeMarker Template Sample in the Plugin Portal, which gives you additional samples for wizards just like this (including one for generating an HTML file), as well as syntax coloring and code completion for FreeMarker templates.

Today on NetBeans Zone. How Fast Can OpenOffice.org Be Extended?

Join the discussion

Comments ( 23 )
  • Sandip Wednesday, April 2, 2008


    You can use:


    to create a [Browse...] button next to Extends and Implements text field so that the user can select a Java Class or Interface from the project's Classpath. You will of course need to write proper filters to select Classes that can be extended in case of Extends (e.g. non-final classes) and Interfaces in case of Implements textfield respectively.

    See this blog entry for the usage of TypeElementFinder:


  • Aoife Nic Aodh Thursday, April 3, 2008

    No offense, but since when is implementing something core to the Java language "Fancy"? Inheritance is one of the core features of any object-oriented language, especially Java.

    It's great to see that it's possible to coerce Netbeans into behaving in a sane way but, as a student, that method was completely non-obvious to me and, as a student, unless I particularly have a pressing need to write something like this, I'm not going to; I want something that "just works", out of the box, and this is a fundamental point of operation. So, instead, I'll turn to the IDE that offers me the functionality that I need to get a job done quickly and efficiently. For years, and for almost this feature alone, my choice has been Eclipse, whenever possible - it could allow me to subclass easily, quickly and sanely.

    To me, this choice was crystallised by the fact that, at the time, Netbeans was still in commercial development, while a free product offered features more relevant to my needs.

    When I've had to work with complex projects (ones that heavily use "fancy" features such as interfaces and inheritance) using Netbeans, I've found this lack of functionality to be frustrating, to say the least. Moreover, it's reinforced my belief that Netbeans is not a project I'd ever want to use willingly.

    So, while I consider this plugin to be a good idea, I seriously believe it to be too little, too late for something so core to the Java language, especially when it's not rolled into the main functionality and has to be implemented as a bolt-on.

  • Geertjan Thursday, April 3, 2008

    Thanks for the idea, Sandip, I will pursue that for sure. Thanks for sharing your thoughts, Aoife, all the best with Eclipse.

  • Varun Thursday, April 3, 2008


    I made this module, followed all your steps, I tried running it, but to no avail!

    Would like to know, which IDE you used for developing this module? I tried it on NetBeans 6.0, didn't work as expected...


  • Geertjan Thursday, April 3, 2008

    Put your code in a ZIP file and send it to me. You're also going to have to describe exactly what you mean by "didn't work as expected".

  • Varun Thursday, April 3, 2008

    When I said, "I tried running it, but to no avail", what I meant was that I got the Wizard for file creation, but when I clicked on the Finish Button, it showed an error...


    A java.lang.reflect.UndeclaredThrowableException exception has occurred.

    Please report this at http://www.netbeans.org/community/issues.html,

    including a copy of your messages.log file as an attachment.

    The messages.log file is located in your E:\\OpenSource\\NetBeansProjects\\FancyJavaClassTemplate\\build\\testuserdir\\var\\log folder.


    Also, I got the result same as presented above in the 1st two snapshots, of this post. I have also send you the code.

    One more thing, there was one step - "Go to the Template Manager under the Tools menu and open Classes | Java Class into the editor", I had no Classes Folder, instead I opened "Java | Java Class" to get the template.

  • Ihs Friday, April 4, 2008

    Hi Geertjan

    I've read all your posts about wizards and still have a problems creating my own. How do I enable "Finish" and Disbale "Next" upon changes on wizards' pane? Could you give me (others will benefit too) some hints? :)


  • Geertjan Friday, April 4, 2008

    lhs, I will write about this soon. Varun, please also send me the file that you find here:

    E:\\OpenSource\\NetBeansProjects\\FancyJavaClassTemplate\\build\\testuserdir\\var\\log folder.

  • Ihs Friday, April 4, 2008

    Nevermind my previous post :D a big cup of coffee and everything works ;) (thought it still may be a good sample for others)


  • Geertjan Friday, April 4, 2008

    Great! Yes, it was actually the next blog entry I was planning to write, it's a perfect follow up to this one (basically, it is the 'homework assignment' I set at the end of this blog entry).

  • Geertjan Friday, April 4, 2008

    Varun, in "FancyWizardIterator.java", one of your import statements is "javax.tools.FileObject". It should be "org.openide.filesystems.FileObject" instead. Also, read step 9 again and then look at your layer.xml file. There is a difference there, even though step 9 tells you to make sure that there isn't.

  • Varun Friday, April 4, 2008

    Now, its working smoothly.

    One more thing, as you had asked earlier, to try creating this Fancy class, leaving the "Extension" and "Implementation" text-fields empty.

    There were 3 cases possible;

    1. leaving only "Extension" empty

    2. leaving only "Implementation" empty

    3. leaving both fields empty

    File gets created, but it leaves the corresponding field empty in the code as well, suppose we take case (2), as above;


    \* To change this template, choose Tools | Templates

    \* and open the template in the editor.




    \* @author Home


    public class Newfancy extends JFrame implements {


    Thank you.

  • Geertjan Friday, April 4, 2008

    Yes, Varun. That's right. Now you need to think about how you would prevent the user getting that result.

  • Jeff Saturday, September 10, 2011


    Can you please describe how to make the wizard work as a stand-alone java application? When I run the module, it starts NetBeans and I neeed to click the icon to start the wizard. I assume I need to have a main() function and change other "things" in the project, since the "project properties" does not have a "run" entry as other projects.


    Jeff N.

  • Geertjan Saturday, September 10, 2011

    Hi Jeff, this blog entry is about creating a wizard for NetBeans IDE. Hence, it is not about creating a wizard for a standalone Java application. The APIs come from NetBeans IDE itself, so what you want to do is not possible since you will always need NetBeans IDE to use the steps described in this blog entry.

  • Jan Goyvaerts Tuesday, December 13, 2011

    Hello Geertjan,

    I'd like to delegate the repetitive activities of creating a Java source file based on a number of variables.

    I'd really like define a new template in Tools > Templates, add these variables and get a Java file of that.

    Is it possible to achieve this solely by the use of freemarker templates ?

    Thanks !


  • Geertjan Tuesday, December 13, 2011

    Yes, definitely, that's what Tools | Templates is for. Add new templates in there and then you'll see them in the New File dialog.

  • Geertjan Tuesday, December 13, 2011

    Maybe you can create a new module as described here where you can register your FreeMarker templates:


  • Jan Goyvaerts Tuesday, December 13, 2011

    But is it possible to introduce new variables ?

    Which can be entered by the user in a dialog and used as ${...} in the templates ?

  • Geertjan Tuesday, December 13, 2011

    Yes. Click "Settings" in the Template manager and then define them.

  • slbmeh Monday, January 23, 2012

    This tutorial is great, the issue I have been having lately with a lot of platform tutorials is that the ones relevant to what I would like to do all extend Java projects. That is great, I have learned a good bit about extending Java, my overall goal is to translate these techniques to PHP.

    I haven't done much Java development aside from a single Java course. I am having trouble translating a lot of these projects over to PHP. I've tried many times to extend PHP and have yet to be successful with it. I have been able to create an entire project type and extend that.

    I would like to know for instance " packageChooserPanel = JavaTemplates.createPackageChooser(project, groups, new FancyWizardPanel1());", how do locate the class that you used here? Does is implement a specific interface, extend a certain class?

  • John Sunday, August 12, 2012

    how i can read an EJB or a class from my project in a wizard?

  • David Wednesday, September 12, 2012

    Hi, I really appreciate this tutorial! However, if someone could point out how the adjustments in the layer.xml file shown above should be done in netbeans 7.1 (with use of the @TemplateRegistration annotation), I would be really thankful.

Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.