Site icon Experiences Unlimited

Getting rid of Getters and Setters in your POJO

We all have read in Java books about encapsulation of fields in Java class and also when ever you code you are asked to take special care in encapsulating the fields and providing explicit Getters and Setters. And these are very strict instructions. Lets step back a bit and find out the reason behind encapsulating the fields. Its all done to have a control over the access and modification of the fields. One might want to allow the user of the class to access data from only few fields or control the update of data of the fields in the class and so on. And on other occassions the frameworks would need these getters and setters to populate your POJOs(Plain Old Java Objects).

Now the pain involved in adding these getters and setters is quite a bit and this pain has been reduced by the IDEs which allow you to generate the getters and setters for the fields. But these generated code make your class definition very verbose and hide the actual business logic, if any, which you might have it inside the class definition. There have been lot of ways by which you can get away with defining the getters and setters explicitly and I have even blogged about using Project Lombok to use annotations to declare the getters and setters. I have come across another approach to avoid defining the getters and setters and this approach doesn’t even auto generate the code or use annotations to define them. I am sure I have read this approach somewhere but unable to recall, so its something which has been used and I am trying to create an awareness among my readers about this approach via this blog post.

Let me first define the class with the getters and setters and then show how to get rid of them

class TaskWithGettersSetters {
  public TaskWithGettersSetters(String title, String notes,
      LocalDateTime deadline, String assignedTo) {
    this.title = title;
    this.notes = notes;
    this.addedOn = LocalDateTime.now();
    this.deadline = deadline;
    this.assignedTo = assignedTo;
  }

  public TaskWithGettersSetters() {
  }

  private String        title;
  private String        notes;
  private LocalDateTime addedOn;
  private LocalDateTime deadline;
  private String        assignedTo;

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getNotes() {
    return notes;
  }

  public void setNotes(String notes) {
    this.notes = notes;
  }

  public LocalDateTime getAddedOn() {
    return addedOn;
  }

  public void setAddedOn(LocalDateTime addedOn) {
    this.addedOn = addedOn;
  }

  public LocalDateTime getDeadline() {
    return deadline;
  }

  public void setDeadline(LocalDateTime deadline) {
    this.deadline = deadline;
  }

  public String getAssignedTo() {
    return assignedTo;
  }

  public void setAssignedTo(String assignedTo) {
    this.assignedTo = assignedTo;
  }

}

There is nothing to explain in the above code, pretty clear with fields being private and public getters and setters. The class definition is about 60 lines. Let see how we can define class without providing getters and setters:

class Task {

  public Task(String title, String notes, LocalDateTime deadline,
      String assignedTo) {
    this.title = title;
    this.notes = notes;
    this.addedOn = LocalDateTime.now();
    this.deadline = deadline;
    this.assignedTo = assignedTo;
  }

  public final String        title;
  public final String        notes;
  public final LocalDateTime addedOn;
  public final LocalDateTime deadline;
  public final String        assignedTo;

}

The above is what I call class definition on diet 🙂 It is less verbose and is just 18 lines. You must be scared looking at the public modifiers for the fields and also confused looking at the final modifiers to the field. Let me explain the ideology behind this approach:

  1. As the fields are final they cannot be modified after initialized so we need not worry about the scare of data in the field getting modified. And we have to provide a constructor which will initialize these fields, otherwise compiler will shout at you for not understanding what final modifier is.
  2. The data in the fields can be accessed by using the fields directly and not via the getter methods.
  3. This approach enforces immutability of objects i.e if we have to update the field we have to create a new object with the updated value of the field.

Now having Immutable objects provides lots of advantages few of them being:

We can even provide a factory method for creating instances of Task. Lets see the above class in action:

import java.time.LocalDateTime;

public class GettingRidOfGettersSettersDemo {
  public static void main(String[] args) {
    //One can make use of Factory method to initialize the data
    Task task1 = new Task("Task 1", "some notes", LocalDateTime.now().plusDays(5), "sana");
    //Very clean approach to access the field data - no getYYY() noise 
    System.out.println(task1.title + " assigned to " + task1.assignedTo);
    Task task2  = new Task("Task 2", "some notes", LocalDateTime.now().plusDays(6), "raj");
    System.out.println(task2.title + " assigned to " + task2.assignedTo);
  }
}

Update:
Thanks a lot for the comments and your thoughts both here and on DZone. I spent some time in identifying how one can work without the need for getters and setters in scenarios mentioned where without getters and setters its not possible. One such scenario is marsalling and unmarshalling of JSON and another scenario is where we have a List of some values as property and we need to give an read only access to the users of the object. The below are examples of using POJOs without getters and setters in JSON marshalling and unmarshalling using GSON and Jackson JSON libraries:

The below is the code for using GSON JSON Library:

public class GsonParserDemo {

  public static void main(String[] args) {
    HashMap<String, Object> jsonData = new HashMap<String, Object>();
    jsonData.put("name", "sanaulla");
    jsonData.put("place", "bangalore");
    jsonData.put("interests", Arrays.asList("blogging", "coding"));
    Gson gson = new Gson();

    String jsonString = gson.toJson(jsonData);
    System.out.println("From Map: " + jsonString);
    

    Person person = gson.fromJson(jsonString, Person.class);
    
    System.out.println("From Person.class: " + gson.toJson(person));
  }

  class Person {
    public final String name;
    public final String place;
    private final List<String> interests;

    public Person(String name, String place, List<String> interests) {
      this.name = name;
      this.place = place;
      this.interests = interests;
    }
 
    public List<String> interests(){
      return Collections.unmodifiableList(interests);
    }
  }
}

The output of above code is:

From Map: {"name":"sanaulla","place":"bangalore","interests":["blogging","coding"]}
From Person.class: {"name":"sanaulla","place":"bangalore","interests":["blogging","coding"]}

To note : GSON doesn’t use constructor nor getters and setters to map JSON to Java class.

The below is the code for using Jackson JSON Library:

public class JacksonParserDemo {
  public static void main(String[] args) throws JsonGenerationException,
      JsonMappingException, IOException {
    HashMap<String, String> jsonData = new HashMap<String, String>();
    jsonData.put("name", "sanaulla");
    jsonData.put("place", "bangalore");

    ObjectMapper objectMapper = new ObjectMapper();

    String jsonString = objectMapper.writeValueAsString(jsonData);
    System.out.println("Json from map : " + jsonString);

    Person person = objectMapper.readValue(jsonString, Person.class);
    System.out.println("Json from Person : "
        + objectMapper.writeValueAsString(person));
  }

}
class Person {
  
  public final String name;
  
  public final String place;

  @JsonCreator
  public Person(@JsonProperty("name") String name,
      @JsonProperty("place") String place) {
    this.name = name;
    this.place = place;
  }

}

The output of the above code is:

Json from map : {"name":"sanaulla","place":"bangalore"}
Json from Person : {"name":"sanaulla","place":"bangalore"}

I am investigating some concerns raised about Object Relational Mappers and the Joda Time.

Exit mobile version