1

I have a POJO which has tens of fields, and I have to set all the fields' values.

How to avoid forgetting to set some field's value?

// POJO
public class Employee {
   private Date birthday;
   private String firstName;
   private String lastName;
   private String birthOfPlace;
   // ...

   // setters and getters
}


// Main class
public class MainClass {
   public static void main(String[] args) {
      Employee employee = new Employee();
      // Call all the setters of Class Employee
      employee.setFirstName("Jack");
      employee.setLastName("Reed");
      employee.setBirthOfPlace("Iceland");
      // Oops, forget to call setBirthday()
   }
}
Ori Marko
  • 56,308
  • 23
  • 131
  • 233
herseus
  • 51
  • 1
  • 7
  • 3
    use `constructor` rather? it will remind you of every argument you pass at once. – Mustahsan Jun 11 '19 at 09:35
  • you could use the step builder pattern. https://medium.com/@castigliego/step-builder-pattern-3bcac4eaf9e8 – Claudiu Guja Jun 11 '19 at 09:37
  • You can put final in all of them, so the constructor must be implemented with all of the attributes of the class, with this approach your setters can't be use, use builder pattern instead. – Nico Jun 11 '19 at 09:38

2 Answers2

1

Use inner Builder class inside your class with constructor with required parameter(s), e.g. firstName:

public static class Builder {


    private String firstName;
    private String lastName;

    public Builder(String firstName) {
        this.firstName= firstName;
    }

    public Builder lastName(String lastName) {
        lastName = lastName;
        return this;
    }

Make sure you can create an object only through the Builder

Ori Marko
  • 56,308
  • 23
  • 131
  • 233
  • 1
    I would rather put the `Builder` class inside of `Employee` and make the `Employee(Builder builder)` constructor private to prevent outside direct access. Recommend updating answer displaying this. – Austin Schaefer Jun 11 '19 at 09:45
  • 1
    @AustinSchäfer I wrote that builer is inner class, but I'll add more details – Ori Marko Jun 11 '19 at 09:48
  • Thanks! It's easy to miss such a detail as a newbie, which OP seemingly is. – Austin Schaefer Jun 11 '19 at 09:49
  • But it's still possible to forget to call one of the setters, still cannot solve my problem. – herseus Jun 11 '19 at 10:03
  • @herseus all the setters are mandatory? up to 7 I suggest to add it in Builder constructor and or create Object which include mandatory fields as `EmployeeBasic ` which will be the only parameter of the constructor – Ori Marko Jun 11 '19 at 10:05
  • @user7294900 you don't need setters if you use a constructor where all fields are necessary. Otherwise, you just have to remember, or fix your NPE/logical errors as you go – Austin Schaefer Jun 11 '19 at 11:31
  • @AustinSchäfer you are correct, but I'm not convinced from OP that all fields are mandatory – Ori Marko Jun 11 '19 at 11:45
  • Oops! I mispinged. I should have pinged OP. @herseus; at the end of the day, you can just write tests to cover any cases where you want to verify that you remembered to set your variables. The other solution would be to fix your exceptions as they arise – Austin Schaefer Jun 11 '19 at 11:48
1

As far as I know, there's no silver bullet solution to what you're asking for: at some point, you will have to either add a value to needed fields in your object, or write code that checks if you did it or not.

However, if you want to try anyway, there's a decent approache to making sure the most critical fields are present when needed: constructor parameters.

public Employee(String firstName, String lastName, Date birthday) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.birthday = birthday;
}

As long as you don't implement another constructor in this class, with this code, you'll be forced to provide a first name, last name, and date for each employee, meaning they'll never not be present (unless you pass null, but avoid doing that, it's arguably bad practice). If you need all your fields to be present, you'll need that many matching parameters in your constructor.

An alternative to this is to use an embedded Builder.

Austin Schaefer
  • 695
  • 5
  • 19