Apr 14, 2018

I’ve been programming in Java 8 now every day of the work week and I am really enjoying it. I’ve seen a lot of people online giving Java crap but honestly it is a real pleasure to work with. Sometimes you may have to be a bit more verbose, but I honestly am a big fan of readable code. After all you write code once but read it many more times than that. With that in mind, I don’t really like the idea that less lines of code is better, unless you are optimizing for some sort of embedded platform where small file sizes really matter.

In the past I have done 90% of my APIs using Python (i.e. API with Python Flask-RESTful and Docker with nginx and Airing TV Show API with Python, PostgreSQL, nginx, and Docker)  and I had a great time doing it. However, at this point after using Java so much I am realizing some of the amazing benefits you get from a language that both doesn’t have such a fractured ecosystem, doesn’t depend on whitespace for syntax, has static typing, and ultimately has an amazing IDE that makes your life easier (see IntelliJ).

Because of that, the next few APIs I develop I will be using Java 8 with the Spark Framework just to show how easy that can truly be. In cases where a lot of data science or machine learning are required, Python can still be pulled into the mix as a microservice that interacts with the Java API easily but is only scoped for those types of tasks.

For this post I want to show some of the fun you can have with an IDE as powerful as IntelliJ, notably around creating a data container object that holds your data and converting that constructor-based object into a Builder almost automatically.

Data container object

What I mean by “data container object” is simply an object that does one thing and does it well: wraps multiple properties and gives access to those properties. In traditional object oriented programming you would typically have data-centric methods that you call on the data objects directly. For instance if you are storing a Pizza recipe in the database, rather than having a store to perform the actions you may call commands more akin to Pizza.store() or Pizza.retrieve(id) to grab a Pizza object directly from the database. I am not a huge fan of storing the database logic directly in the class of the data object, and instead advocate for just using the data object as a means to move the data around your service or other parts of the program and instead using a store implementation that handles all database-centric operations.

Let’s build some Pizza

Going off of my previous example, let’s just keep going and build a Pizza data object that contains properties you may expect a pizza to have, which can then be used in your service. Similarly, you can then allow your store implementations to directly interact with a Pizza object and parse the properties and persist them into the database. Let’s start by opening up IntelliJ and creating a Pizza class and defining some simple properties:

public class Pizza {
    private String cheese;
    private String meat;
    private String sauce;
    private boolean extraSauce;
    private boolean extraCheese;
    private boolean extraMeat;
}

Pretty simple, but now we need a way to actually access all of these properties. You may think you should just make all these fields public and you are good to go, but I strongly suggest not doing that as then the state of this object will be unknown in many circumstances and can be in a weird intermediate state. Instead, let’s only define getters and a default constructor which requires all of the properties above. What is amazing about IntelliJ is you can generate all this code extremely fast. Just type Cmd+N and you will get the options to create Getter, Setter, Getter and Setter, Constructor, etc. Go ahead and choose Getter and select choose all of the properties we have defined so far and they will be automatically generated:

public class Pizza {
    private String cheese;
    private String meat;
    private String sauce;
    private boolean extraSauce;
    private boolean extraCheese;
    private boolean extraMeat;

    public String getCheese() {
        return cheese;
    }

    public String getMeat() {
        return meat;
    }

    public String getSauce() {
        return sauce;
    }

    public boolean isExtraSauce() {
        return extraSauce;
    }

    public boolean isExtraCheese() {
        return extraCheese;
    }

    public boolean isExtraMeat() {
        return extraMeat;
    }
}

Now you can hit Cmd+N once again and define a constructor automatically with all of the same properties:

public class Pizza {
    private String cheese;
    private String meat;
    private String sauce;
    private boolean extraSauce;
    private boolean extraCheese;
    private boolean extraMeat;

    public Pizza(String cheese, String meat, String sauce, boolean extraSauce, boolean extraCheese, boolean extraMeat) {
        this.cheese = cheese;
        this.meat = meat;
        this.sauce = sauce;
        this.extraSauce = extraSauce;
        this.extraCheese = extraCheese;
        this.extraMeat = extraMeat;
    }

    public String getCheese() {
        return cheese;
    }

    public String getMeat() {
        return meat;
    }

    public String getSauce() {
        return sauce;
    }

    public boolean isExtraSauce() {
        return extraSauce;
    }

    public boolean isExtraCheese() {
        return extraCheese;
    }

    public boolean isExtraMeat() {
        return extraMeat;
    }
}

You may notice that this constructor would be a bit annoying to use in that there are six different parameters that must come in the correct order. That’s where a Builder can come really in handy. Let’s go ahead and make an internally scoped builder by adding the following line within the class:

public static final class Builder { }

Now we can place our cursor in the Pizza constructor and hit Ctrl+T to refactor the constructor, selecting Replace Constructor with Builder  and then choose Use existing, typing in Pizza.Builder as our existing builder. Then you will see we get the following code generated:

public static final class Builder {

        private String cheese;
        private String meat;
        private String sauce;
        private boolean extraSauce;
        private boolean extraCheese;
        private boolean extraMeat;

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

        public Builder setMeat(String meat) {
            this.meat = meat;
            return this;
        }

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

        public Builder setExtraSauce(boolean extraSauce) {
            this.extraSauce = extraSauce;
            return this;
        }

        public Builder setExtraCheese(boolean extraCheese) {
            this.extraCheese = extraCheese;
            return this;
        }

        public Builder setExtraMeat(boolean extraMeat) {
            this.extraMeat = extraMeat;
            return this;
        }

        public Pizza createPizza() {
            return new Pizza(cheese, meat, sauce, extraSauce, extraCheese, extraMeat);
        }
    }

Now we can easily build a Pizza using this new builder with the following code:

Pizza pizza = new Pizza.Builder()
                .setCheese("Mozerella")
                .setMeat("Chicken")
                .setSauce("White Sauce")
                .createPizza();

Note that I haven’t set the booleans, because they are by default false. Similarly if I didn’t set sauce or meat then they would both be null by default.

Static factory methods

Now that we have a builder for Pizza, we can literally make any sort of pizza we want with a pretty nice and readable few lines of code. But what if we want to have a few default Pizzas? We can easily create those using static factory methods, let’s see:

public static Pizza getCheesePizza() {
       return new Builder()
               .setCheese("Cheddar")
               .setSauce("Red sauce")
               .createPizza();
}

public static Pizza getPepperoniPizza() {
       return new Builder()
               .setCheese("Cheddar")
               .setSauce("Red sauce")
               .setMeat("Pepperoni")
               .createPizza();
}

Now we can easily create these default Pizza with even less code:

Pizza cheesePizza = Pizza.getCheesePizza();
Pizza pepperoniPizza = Pizza.getPepperoniPizza();

Of course, if we want to build a custom one all we need to do is use the Builder to create whatever style we want. Note: the static factory method is not to be confused with the general design pattern “factory method” which is more about designating the implementation of an interface to a factory class, such that any change in implementation will be reflected with only changing the factory itself. I won’t get into the general factory method design pattern here, but an example could be you could instead define a Pizza interface which can have various implementations, and then allow the PizzaFactory to return the implementation that implements the Pizza interface, rather than directly initializing it in your code in multiple locations.

The full code that we created can be seen below for reference, most of which we didn’t even have to create ourselves because of our powerful IDE:

public class Pizza {
    private String cheese;
    private String meat;
    private String sauce;
    private boolean extraSauce = false;
    private boolean extraCheese = false;
    private boolean extraMeat = false;

    public Pizza(String cheese, String meat, String sauce, boolean extraSauce, boolean extraCheese, boolean extraMeat) {
        this.cheese = cheese;
        this.meat = meat;
        this.sauce = sauce;
        this.extraSauce = extraSauce;
        this.extraCheese = extraCheese;
        this.extraMeat = extraMeat;
    }

    public String getCheese() {
        return cheese;
    }

    public String getMeat() {
        return meat;
    }

    public String getSauce() {
        return sauce;
    }

    public boolean isExtraSauce() {
        return extraSauce;
    }

    public boolean isExtraCheese() {
        return extraCheese;
    }

    public boolean isExtraMeat() {
        return extraMeat;
    }

    public static Pizza getCheesePizza() {
        return new Builder()
                .setCheese("Cheddar")
                .setSauce("Red sauce")
                .createPizza();
    }

    public static Pizza getPepperoniPizza() {
        return new Builder()
                .setCheese("Cheddar")
                .setSauce("Red sauce")
                .setMeat("Pepperoni")
                .createPizza();
    }
    public static final class Builder {

        private String cheese;
        private String meat;
        private String sauce;
        private boolean extraSauce;
        private boolean extraCheese;
        private boolean extraMeat;

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

        public Builder setMeat(String meat) {
            this.meat = meat;
            return this;
        }

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

        public Builder setExtraSauce(boolean extraSauce) {
            this.extraSauce = extraSauce;
            return this;
        }

        public Builder setExtraCheese(boolean extraCheese) {
            this.extraCheese = extraCheese;
            return this;
        }

        public Builder setExtraMeat(boolean extraMeat) {
            this.extraMeat = extraMeat;
            return this;
        }

        public Pizza createPizza() {
            return new Pizza(cheese, meat, sauce, extraSauce, extraCheese, extraMeat);
        }
    }
}