Apr 22, 2018

I recently wrote a post about Code Generation in IntelliJ for data objects (i.e. Plain Old Java Objects). With just a few private fields and some basic code it is extremely easy to generate getters as well as an internal Builder class and a static factory method to instantiate that internal builder. As it turns out, there is an even easier and more robust way to generate this sort of code using the InnerBuilder plugin for IntelliJ. It is a 3rd party plugin and makes it take only two shortcuts to go from a class with private fields to a fully generated data object with an internal builder and getter methods. One of the shortcuts is internal to IntelliJ and the other shortcut is using the InnerBuilder to generate the builder and static factory methods all at once.

Installing the Plugin

Go ahead and download the plugin from this JetBrains’ website. Then open up preferences by typing Cmd , and navigating to the Plugins section. There you will notice a button at the bottom of the screen that says Install plugin from disk…, click that and install the jar file you downloaded. You are ready to go now!

The Basic Data Fields

Let’s go ahead and write some of the basic code again for our Pizza object, just like last time but with some slightly different fields just for fun:

import java.util.List;

public class Pizza {
    private String cheese;
    private List<String> vegetablesList;
    private String sauce;
    private boolean cooked;
    private boolean extraEverything;
}

Generating Getters

Now that we have our Pizza data object, let’s just generate some getters just like in the last post. Go ahead and type Cmd N you will be greeted with this nice code generation menu:

Notice that there is also a Builder option there that didn’t used to exist. We’ll get to that soon. Go ahead and choose all of the fields that we just created:

And now we have the following code generated:

import java.util.List;

public class Pizza {
    private String cheese;
    private List<String> vegetablesList;
    private String sauce;
    private boolean cooked;
    private boolean extraEverything;


    public String getCheese() {
        return cheese;
    }

    public List<String> getVegetablesList() {
        return vegetablesList;
    }

    public String getSauce() {
        return sauce;
    }

    public boolean isCooked() {
        return cooked;
    }

    public boolean isExtraEverything() {
        return extraEverything;
    }
}

Note the way that the booleans are defined with the notation isCooked but we want to actually standardize this and instead use get for all types, so getCooked instead of isCooked. You will see why once we create the internal Builder.

Internal Builder

Now there is just a very small amount of work to do. Go ahead and type Cmd N again and we will be greeted with the same menu as before, now select Builder. Choose all of the properties we have (not all pictured below) and I would highly suggest choosing the below 3 options which are 1) Generate static newBuilder method, 2) Generate builder copy constructor, and 3) Use set notation. This will create some nice static methods for us that we can use later and some consistent terms.

Hit OK and now we have a lot of nicely generated code! The only problem you may notice is that the newBuilder static method is using the Pizza methods getCooked and getExtraEverything instead of isCooked and isExtraEverything. My preferred way to fix this would be to just update the getters to start with get rather than is, which is only needed on the booleans. Now you have the following generated code ready to go:

import java.util.List;

public class Pizza {
    private String cheese;
    private List<String> vegetablesList;
    private String sauce;
    private boolean cooked;
    private boolean extraEverything;

    private Pizza(Builder builder) {
        cheese = builder.cheese;
        vegetablesList = builder.vegetablesList;
        sauce = builder.sauce;
        cooked = builder.cooked;
        extraEverything = builder.extraEverything;
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public static Builder newBuilder(Pizza copy) {
        Builder builder = new Builder();
        builder.cheese = copy.getCheese();
        builder.vegetablesList = copy.getVegetablesList();
        builder.sauce = copy.getSauce();
        builder.cooked = copy.getCooked();
        builder.extraEverything = copy.getExtraEverything();
        return builder;
    }


    public String getCheese() {
        return cheese;
    }

    public List<String> getVegetablesList() {
        return vegetablesList;
    }

    public String getSauce() {
        return sauce;
    }

    public boolean getCooked() {
        return cooked;
    }

    public boolean getExtraEverything() {
        return extraEverything;
    }


    public static final class Builder {
        private String cheese;
        private List<String> vegetablesList;
        private String sauce;
        private boolean cooked;
        private boolean extraEverything;

        private Builder() {
        }

        public Builder setCheese(String val) {
            cheese = val;
            return this;
        }

        public Builder setVegetablesList(List<String> val) {
            vegetablesList = val;
            return this;
        }

        public Builder setSauce(String val) {
            sauce = val;
            return this;
        }

        public Builder setCooked(boolean val) {
            cooked = val;
            return this;
        }

        public Builder setExtraEverything(boolean val) {
            extraEverything = val;
            return this;
        }

        public Pizza build() {
            return new Pizza(this);
        }
    }
}

Building some Pizza

Now let’s build some Pizza! Here are a few examples of what you can do with the code that we generated:

Pizza cheesePizza = Pizza.newBuilder()
        .setCheese("Mozzarella")
        .setSauce("Tomato")
        .setCooked(true)
        .setVegetablesList(Arrays.asList("onion","green pepper"))
        .build();

System.out.println(cheesePizza.getVegetablesList());

Pizza extraCheesePizza = Pizza.newBuilder(cheesePizza)
        .setExtraEverything(true)
        .build();