Search code examples
javadesign-patternsjavabuilders

Changing from JavaBeans to Builder pattern


I am using Retrofit in my app, I have the POJO classes that I use to make the request and parse the response. Currently I am using JavaBeans pattern and have getters and setters for all the variables in the class for all POJO classes.

Here is my user class for instance

public class User {
    @SerializedName("user_name")
    private String userName;
    @SerializedName("password")
    private String userPassword;
    @SerializedName("address_info")
    private AddressInfo AddressInfo;
    @SerializedName("contact_info")
    private ContactInfo ContactInfo;

    /* 
      *@return The userName
    */
    public String getUserName() {
        return userName;
    }

    /**
     * @param userName The userName
     */

    public void setUserName(String userName) {
        this.userName = userName;
    }

    /**
     * @return The userPassword
     */

    public String getPassword() {
        return userPassword;
    }

    /**
     * @param userPassword The userPassword
     */

    public void setPassword(String userPassword) {
        this.userPassword = userPassword;
    }
    /// so on for the AddressInfo and ContactInfo
}

This works well.I am trying to make use of builder pattern instead of the JavaBeans pattern.

I changed my User class to :

public class User {
    @SerializedName("user_name")
    private String userName;
    @SerializedName("password")
    private String userPassword;
    @SerializedName("address_info")
    private AddressInfo AddressInfo;
    @SerializedName("contact_info")
    private ContactInfo ContactInfo;


    public static class UserBuilder {

        private String userName;
        private String userPassword;
        private AddressInfo AddressInfo;
        private ContactInfo ContactInfo;

        //builder methods for setting property
        public UserBuilder userName(String user_name) {
            this.userName = user_name;
            return this;
        }

        public UserBuilder userPassword(String user_password) {
            this.userPassword = user_password;
            return this;
        }

        public UserBuilder AddressInfo(AddressInfo addressInfo) {
            this.AddressInfo = addressInfo;
            return this;
        }

        public UserBuilder ContactInfo(ContactInfo contactInfo) {
            this.ContactInfo = contactInfo;
            return this;
        }

        //return fully build object
        public User build() {
            return new User(this);
        }
    }

    //private constructor to enforce object creation through builder

    private User(UserBuilder builder) {
        this.userName = builder.userName;
        this.userPassword = builder.userPassword;
        this.AddressInfo = builder.AddressInfo;
        this.ContactInfo = builder.ContactInfo;
    }

//Getters for userName,userPassword,AddressInfo and ContactInfo
}

AddressInfo class

public class AddressInfo {
    @SerializedName("address_1")
    private String address1;
    @SerializedName("city")
    private String city;
    @SerializedName("state")
    private String state;
    @SerializedName("zip_code")
    private String zipCode;

    /**
     * @return The address1
     */
    public String getAddress1() {
        return address1;
    }

    /**
     * @return The city
     */
    public String getCity() {
        return city;
    }

    /**
     * @return The state
     */
    public String getState() {
        return state;
    }

    /**
     * @return The zip code
     */
    public String getZipCode() {
        return zipCode;
    }
}

Question: 1. I removed setters from AddressInfo and ContactInfo POJO classes. Do I need to implement the builder pattern in AddressInfo and ContactInfo classes as well? Is that how the pattern works.

  1. How can I achieve this:

      User user = new User.UserBuilder().userName("test").userPassword("******").address("100 Townsend St").city("San Francisco").zip("94107").build();
    

Solution

  • With

    User user = new User.UserBuilder().userName("test")
        .userPassword("******").address("100 Townsend St")
        .city("San Francisco").zip("94107").build();
    

    you will be mixing stuff up. UserBuildr should be responsible for building a user using its address/contact info and not building the them as well. You should have getters and setters for instances of AddressInfo and ContactInfo in the User class and have also methods for setting them in UserBuilder. Create a builder for each of them and use them like this.

    User user = new User.UserBuilder().userName("test")
        .userPassword("******").addressInfo.(new AdressInfo.Builder()
            .address1("100 Townsend St")
            .city("San Francisco").zip("94107").build()).build();
    

    Do the same for ContactInfo.

    If you don't want setters of AddressInfo and ContactInfo to be accessible for outside you can make them protected, the builder will still be able to access them since it is inner class.