March 25, 2015

Custom accessors with IntelliJ's new code generation features

The problem with getters

If you know your Java history, you will also be familiar with the naming conventions for accessors and mutators that was introduced, and defined, by the JavaBeans specification. (i.e. the good ol' getters and setters) This naming convention became more or less a de facto convention for accessor and mutator methods in Java. Even for objects that had no intentions whatsoever to be a java bean.
And because it was such a widespread naming convention many frameworks and libraries started to rely on that convention in order to provide useful features. Luckily, many of the popular frameworks and libraries that are used today no longer require these naming conventions in order to function.

That means that today it is perfectly fine to write code like person.name() if it makes more sense to you and you will not be forced to write person.getName() just in order to get your tooling to work. Personally, I nowadays very rarely use the JavaBeans style of naming and I do that without having any problems with popular libraries. When I do use it it is strictly because I am forced to do so because of some framework that has not yet moved away from the old naming conventions. And that seems to mostly occur at the infrastructure level of the code base (very often in the form of DTOs) rather than in the actual domain code, and that, in turn, makes the ugly code a little bit more acceptable.

However, one issue that has remained around this is the limitation in our IDEs and the ability to generate accessors and mutators. IntelliJ is the IDE of choice for me and if I would create, for example, a class Person with a couple of fields and then choose to generate getters and setters for them, then the generated methods would all follow the JavaBeans naming conventions (see example code below).
Leaving me to either manually have to rename all of the generated methods, or simply just write them all by hand. Both alternatives are tedious but apart from resorting to compiler based solutions like Lombok there really haven't been any good alternatives.
public class Person {

    private final String firstName;

    ...

    public String getFirstName() {
        return firstName;
    }

}

New code generation to the rescue

No good alternatives up until now that is. The 14.1 release of IntelliJ IDEA brings a couple of nice new features. One of them being the ability to define you own templates for code generation for getters and setters, as well as for equal and hashcode. That means that the accessors that IntelliJ generates for you no longer are limited to the JavaBeans naming convention.

JetBrains has a blog post that explains how to access the templates used when generating code and once you found it you can simply choose to create your own Velocity templates. This feature is something that I have been waiting for so I was very pleased to see that it has finally been implemented and of course I immediately went off to define a template that will allow me to generate the type of accessors that I want. So now my Person class will end up looking like this with generated accessors:
public class Person {

    private final String firstName;

    ...

    public String firstName() {
        return firstName;
    }

}

This might seem like a small feature but if you are writing a lot of code then this reduction of manual typing will add up to quite some time savings.

And below is the template used to achieve this. The template is simply a tweak of the standard one supplied by IntelliJ. Please also note that it is only the "get" methods that are generated differently. So if you would prefer a setter to be firstName("Jane") instead of setFirstName("Jane) then you can of course tweak the template accordingly.
The template also seems to be quite sensitive to the number of spaces used for indentation so if you are getting strange error messages when using your custom template then you might want to check those against the default template.
public ##
#if($field.modifierStatic)
  static ##
#end
$field.type ##
#set($name = $StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($helper.getPropertyName($field, $project))))
#if ($field.boolean)
  #if ($StringUtil.startsWithIgnoreCase($name, 'is'))
    #set($name = $StringUtil.decapitalize($name))
  #else
    is##
#end
#else
  #set($name = $StringUtil.decapitalize($name))
  ##
#end
${name}() {
  return $field.name;
}

If you prefer not to name your accessors and mutators following the JavaBeans conventions then you will find these new features quite valuable.

No comments:

Post a Comment