Generate toString() plugin

Introduction

GenerateToString is a action plugin for IDEA that is used to create or update java classes toString() method. The reason is valuebeans usually needs to dump their field values for debug purpose, and it's tedious to write the dump code for this. This plugin generates the toString() method dumping all the fields in a simple manner.

Usage

Press alt + ins to active the generate menu and select toString.

Example

In the code below we need to override the public toString method so the fields can be dumped:
    public class MyServerConfigBean {
        private String name;
        private String url;
        private int port;
        private String[] validIPs;
        ...
    }
  
After invoking the GenerateToString action the bean is now added with the following method
    public String toString() {
        return "MyServerConfigBean{" +
                    "name='" + name + "'" +
                    ", url='" + url + "'" +
                    ", port=" + port +
                    ", validIPs=" + (validIPs == null ? null : "length:" + validIPs.length + Arrays.asList(validIPs)) +
                    "}";
    }
  
And if you change the fields you can run the action again and have it update the toString() method. In this situation where the toString() method already exists a dialog is displayed with options to: The plugin uses Velocity Template Language to generate the code, so it is very flexible to customize. The template can be changed from the settings.

Enable getters in code generation

Using this feature getter methods that does not directly use an existing field are avail in the Velocity Template Macro language as the variable $methods.
The example again with getters enabled:
    public class MyServerConfigBean {
        private String name;
        private String url;
        private int port;
        private String[] validIPs;
        ...

        public String getServerAddress() {
           return url + ":" + port;
        }

    }
  
And so after invoking the action, the result is:
    public String toString() {
        return "MyServerConfigBean{" +
                    "name='" + name + "'" +
                    ", url='" + url + "'" +
                    ", port=" + port +
                    ", serverAddress='" + getServerAddress() + "'" +
                    ", validIPs=" + (validIPs == null ? null : Arrays.asList(validIPs)) +
                    "}";
    }
  
The getter getServerAddress is now outputted in the toString method.

Adding super class aware

The plugin supports calling super.toString() in the generated code this is done using a test in the velocity macro. Here is an example:
        #if ($class.hasSuper)
            return super.toString() + " :: $classname{" +
        #else
            return "$classname{" +
        #end
  

Settings

You can change the settings of the plugin in File -> Settings.
ConfigurationDescription
Use field chooser dialogA dialog for selecting fields is used (like the getter/setter dialog).
Always use default conflict resolution policyWill use the option selected from the Conflict Resolution Policy settings.
Enable on-the-fly code inspectionIf selected the code inspection for toString() will be run in the background (on-the-fly) and report any errors as warnings. This is like some existing IDEA code inspection for fields not used etc.
Use fully qualified classnameThe dumped classname will be including its packagename. (The $classname variable in the Velocity Context)
Enable getters in code generationIf selected the code generator will have $methods avail in the Velocity Macro Language.
Move caret to generated methodIf selected the caret will be moved/scrolled to the generated toString method.
Sort fieldsIf selected the fields will be sorted. This feature is only working when not using the dialog chooser as it has it's own sort function you should use.
Default Conflict Resolution PolicyPolicy what to do when there already exists a toString() method.
Replace Existing = automatic replace existing toString() code.
Duplicate = Create a duplicate toString() method (will not erase you existing code).
Cancel = No code changes.
Insert New Method PolicyPolicy what to do when inserting a new toString() method.
At caret = inserted at caret position.
After equals/hashCode = inserted after the equals/hashCode if present in the javafile, if not it will be inserted at the current caret position.
Last = inserted as the last method.
Exclude all constant fieldsIf checked then any fields that's a constant will not be part of available fields for the code generator.
Exclude all static fieldsIf checked then any fields that's has a static modifier will not be part of available fields for the code generator.
Exclude all transient fieldsIf checked then any fields that has a transient modifier will not be part of available fields for the code generator.
Exclude all enum fieldsIf checked then any fields that is an enum type (JDK1.5) will not be part of available fields for the code generator.
Exclude loggersIf checked then any field that is a either a Log4j Logger, Java JDK Logger or a Jakarta Commons Logger will not be part of available fields for the code generator.
Exclude fields by namePerforms a regular expression matching on the field name. If the result is true the field will not be part of available fields for the code generator.
Exclude fields by typenamePerforms a regular expression matching on the field type name (fully qualified name). If the result is true the field will not be part of available fields for the code generator.
Exclude methods by namePerforms a regular expression matching on the method name. If the result is true the method will not be part of available methods for the code generator.
Exclude methods by return typenamePerforms a regular expression matching on the method return typename (fully qualified name). If the result is true the method will not be part of available methods for the code generator.
Automatic add implements java.io.SerializableWill automatic add implements Serializable to the java bean class if not already implemented. This is useful for value objects that usually have to implement this interface for working in J2EE environments.
Automatic import packagesWill automatic import the packages. Additional packages can be separated using comma. IDEA will optimize the imports so java.util.* will be optimized to java.util.List;java.util.Arrays etc.
Can be used to import your own classes that might be added to the generated code in the toString method.
TemplatesA list of predefined templates to choose. To use a new template first select it and click the Use this template button.
Active templateActivates the current selected template. A confirm dialog will be prompted.
Save templateSaving the current template to a file. A file chooser dialog will be prompted.
Syntax checkPerforms a Velocity syntax check of the current template code from the text area. Can be used to catch early syntax errors during customizing of templates.
Method body (Velocity Macro Language)The java code for the toString() method body is generated using Velocity Macro Language. In this text area you can change how the code is generated.

Excluding fields

Usually you don't want constant fields as debug information in your toString() method. So you can check this filtering option, and prevent constant fields in the output. Also you can filter by the field's name. You could have an internal debug field not to be used in the toString method. So you type ^debug in the textfield Exclude fields by name (reg exp), to prevent debug fields.
The example again using excluded fields:
    public class MyServerConfigBean {
        private final static String USERNAME = "scott";
        private final static String PASSWORD = "tiger";
        private String name;
        private String url;
        private int port;
        private String[] validIPs;
        private boolean debug = true;
        ...
    }
  
And so after invoking the action, the result is still:
    public String toString() {
        return "MyServerConfigBean{" +
                    "name='" + name + "'" +
                    ", url='" + url + "'" +
                    ", port=" + port +
                    ", validIPs=" + (validIPs == null ? null : Arrays.asList(validIPs)) +
                    "}";
    }
  
We do not output the constant fields (USERNAME, PASSWORD). And the regular expression excluded the debug field. The excluded fields will also not be in the choose fields dialog.

Excluding methods

Only the methodname can be excluded for methods using a regular expression test.
Typing ^getCausedBy.* in the textfield By methodname (regexp), to prevent outputting methods starting with the name getCausedBy.

JavaDoc

It is possible to add javadoc comments to the generated toString() method. This is done by inserting the javadoc comments in the velocity template. See the supplied javadoc template example. A requirement is to use /** and */ enclosing the javadoc comments. The javadoc comments should be in the top of the template.

Here is an example:

    /**
     * Insert your javadoc comments here
     *
     * @return   a string representation of the object.
     */
    return "$classname{}";
  

Template Quick Selection List

This feature let you on the fly choose what template to use. When the action is invoked a little list is displayed with the templates you have selected to be in this list. For instance if you add the two default templates for toString you could chose between the concat or StringBuffer style.

Support for generating other methods

This plugin was meant only to generate toString() methods. But why can't it be useful to generate other methods as well? It does have a lot of class information in the velocity context so it should be possible to create a compareTo template.
This is now possible as you have to provide the method signature in the top of the template:
      public String toString() {
        TEMPLATE CODE HERE
      }
  
The template code must be enclosed in { }.

Template repository

The template repository is a new feature in the settings dialog where you can choose a new template from the 4 included default templates. Additional templates stored in the folder IDEA_HOME\plugins\tostring-plugin will be listed also. Hence you can store your own templates in a text file (.vm, .txt or other) and have it listed here. This avoids any problem upgrading this plugin to a new version and loosing your customized template.

Saving templates

You can save your custom template to a file using the Save template button. The save dialog will default to the IDEA_HOME\plugins\tostring-plugin folder where it is possible to store additional templates to be listed in the template repository list. Storing templates outside this folder will not list the template in the list. If the filename has not been given an extension the .vm will be used (.vm = Velocity Macro).

Annotations

You can add annotations to your method. There is a default template included that illustrates this.
Here is a short example:
      @Override
      public String toString() {
         ...
      }
  

A Velocity Macro Example: The default template

This is the default velocity template that is used in this plugin:
  public String toString() {
      #if ( $fields.size() > 0 )
          #set ( $i = 0 )
              return "$classname{" +
          #foreach( $field in $fields )
              #if ( $i == 0 )
                  "##
              #else
                  ", ##
              #end
              #if ( $field.objectArray )
                  $field.name=" + ($field.name == null ? null : Arrays.asList($field.name)) +
              #elseif ( $field.string )
                  $field.name='" + $field.name + "'" +
              #else
                  $field.name=" + $field.name +
              #end
              #set ( $i = $i + 1 )
          #end
          "}";
      #else
          return "$classname{}";
      #end
  }
  
The macro code can be changed to your needs. Just change the code in the text area. The active template is always the template that is editable.

Inspection

This plugin provides two code inspections: The Field not used in toString() method inspection can be used to identify out of synchronization situations where you have an existing toString() method that dumps the fields. However some fields have been added to the class later and these new fields are not dumped in the toString() method.
This inspection can use on-the-fly code inspection by enabling it to show errors as warnings. This will highlight any unused fields on-the-fly in the java editor - also the right gutter will indicate the location of the error using a yellow marker. This is the same feature as the build in inspection 'Field XXX is never assigned'. Enabling the on-the-fly feature can be done from setting settings -> Errors -> ToString() Issues. Also on-the-fly should be enabled from the settings to the plugin.

The inspection Class does not override toString() method can be used to identify any classes where you might have forgotten to add a toString() method. This inspection will use the exclude settings from the plugin configuration to ignore classes having fields not supposed to be dumped. An additional settings is to exclude certain classes by using a regular expression matching their classname. As default this is used to exclude any Exception classes. This setting can be changed from settings -> Errors -> ToString() Issues. Also on-the-fly should be enabled from the settings to the plugin.

Keymaps

You can assign a keymap to this action from the settings. This keymap can be active even if the action is disabled from the code and editor popup menus. The Generate toString() action is located under other in the keymap tree.

Velocity context

There are now three type of elements avail in the macro language:
A member is the common for both fields and methods. So using $member.string is the same as $field.string or $method.string.
A field extends a member. Field have a few extra special field related attributes.
A method extends a member. Method has a few extra special method related attributes.
In the table below $member can be used for both $field and $method.

The following variables are possible in the Velocity Template (variables are stored in the Velocity Context):
VariableReturnsDescription
$classnameStringThe name of the class (can be the qualified classname if this is selected in the settings)
$FQClassnameString@deprecated (use $class.qualifiedName) - The fully qualified name of the class
$fieldsjava.util.ListList of FieldElement objects
$methodsjava.util.ListList of MethodElement objects
$membersjava.util.ListList of both FieldElement and MethodElement objects
$memberElementThe Element object
$member.accessorStringThe accessor of the field or method. For field it is the $field.name and for method it is $method.methodName
$member.typeNameStringThe classname of the type (Object, String, List etc.)
$member.typeQualifiedNameStringThe qualified classname of the type (java.lang.Object, java.lang.String, java.uti.List etc.)
$member.arraybooleanTests if the type is an array type (either a primitive array or object array)?
$member.primitiveArraybooleanIs the type a primitive array type? (int[], short[], float[] etc.)
$member.objectArraybooleanIs the type an Object array type? (Object[], String[] etc.)
$member.stringArraybooleanIs the type an String array type? (String[])
$member.collectionbooleanIs the type assignable from java.util.Collection?
$member.listbooleanIs the type assignable from java.util.List?
$member.mapbooleanIs the type assignable from java.util.Map?
$member.setbooleanIs the type assignable from java.util.Set?
$member.primitivebooleanIs the type a primitive type? (int, char, float etc.)
$member.modifierStaticbooleanDoes the type have a static modifier?
$member.modifierPublicbooleanDoes the type have a public modifier?
$member.modifierProtectedbooleanDoes the type have a protected modifier?
$member.modifierPackageLocalbooleanDoes the type have a package-local modifier?
$member.modifierPrivatebooleanDoes the type have a private modifier?
$member.modifierFinalbooleanDoes the type have a final modifier?
$member.stringbooleanIs the type assignable from java.lang.String?
$member.numericbooleanIs the type either assignable from java.lang.Numeric or a primitive type of byte, short, int, long, float, double?
$member.objectbooleanIs the type assignable from java.lang.Object?
$member.datebooleanIs the type assignable from java.util.Date?
$member.calendarbooleanIs the type assignable from java.util.Calendar?
$member.booleanbooleanIs the type assignable from java.lang.Boolean? or a primitive boolean
$fieldFieldElementThe FieldElement object
$field.nameStringThe name of the field
$field.modifierTransientbooleanDoes the field have a transient modifier?
$field.modifierVolatilebooleanDoes the field have a volatile modifier?
$field.constantbooleanIs the field a constant type? (has static modified and its name is in UPPERCASE only)
$field.matchName(regexp)booleanPerforms a regular expression matching on the fieldname.
$field.enumbooleanIs this field a enum type?
$methodMethodElementThe MethodElement object
$method.nameStringEither: 1) The name of the field this getter method covers or 2) the name of the method 'getFoo' when the method does not cover a field as in situation 1
$method.methodNameStringThe name of the method (getFoo).
$method.fieldNameStringThe name of the field this getter method covers - null if the method is not a getter for a field
$method.modifierAbstractbooleanIs this method an abstract method?
$method.modifierSynchronizedbooleanIs this method a synchronized method?
$method.returnTypeVoidbooleanIs this method a void method (does not return anything) ?
$method.getterbooleanIs this a getter method?
$method.matchName(regexp)booleanPerforms a regular expression matching on the methodname.
$method.deprecatedbooleanIs this method deprecated?
$classClassElementThe ClassElement object
$class.nameStringThe name of the class
$class.matchName(regexp)booleanPerforms a regular expression matching on the classname.
$class.qualifiedNameStringThe fully qualified name of the class
$class.hasSuperbooleanDoes the class have a superclass? (extends another class - note extending java.lang.Object is not considered having a superclass)
$class.superNameStringThe name of the superclass (empty if no superclass)
$class.superQualifiedNameStringThe fully qualified name of the superclass (empty if no superclass)
$class.implements(interfaceNames)booleanTests if the class implements the given interface name. Testing several interfaces names can be done by separating the names with comma. Tests is based using the short classname.
$class.implementNamesString[]Returns the classnames of the interfaces the class implements. An empty array is returned if the class does not implement any interfaces.
$class.extends(classNames)booleanTests if the class extends any of the the given class names. Testing several class names can be done by separating the names with comma. Tests is based using the short classname.
$class.exceptionbooleanIs this class an exception class (extends Throwable)?
$class.deprecatedbooleanIs this class deprecated?
$class.enumbooleanIs this class an enum class?
$class.abstractbooleanIs this class abstract?

The following output variables are possible in the Velocity Template (variables are stored in the Velocity Context): Output parameters will be available for the plugin generate after the Velocity context has been executed and act upon.
VariableParameterDescription
$autoImportPackagesStringPackagenames that should automatically be imported. Use comma to separate packagenames.

For an example see the included template "Default using org.apache.commons.lang.ToStringBuilder".

Logging

This plugin used log4j for logging. Logging can be enabled by editing the log4j.xml used by IDEA. The file is in the IDEA_HOME\bin folder. Add the category to this file:
    <category name="org.jetbrains.generate.tostring">
       <priority value="DEBUG"/>
       <appender-ref ref="FILE"/>
    </category>