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:

  • Writing concurrent code is quite easy because we need not worry about getting locks on the object as we are never going to modify the object, we can just read the object data and cannot modify due to the use of final.
  • Immutable objects leads to having lot of short lived objects which helps in reducing the GC overhead involved in managing long lived objects and objects with lot of live references.

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.

20 thoughts on “Getting rid of Getters and Setters in your POJO”

  1. “if we have to update the field we have to create a new object with the updated value of the field”
    This is a huge thing, In a context with persistence (let’s say Hibernate) which is almost every projects, if you want to change the value of a field, you’ll create another object, but you’ll have to handle the identity of the obejct itself, maybe defining cloning strategies, I don’t know, but it seems to me that removing these gettters/setters will in this case produces way more work.

    I think the approach you just described in this post can be very useful in certain situations (like you said, objects that don’t change often and the need for synchronization), but this approach actually doesn’t only get rid of the getters/setters. Which is why for this particular goal I love Lombock.

    Did you use this approach ? If you did, in which context, and how was it useful ?

    Reply
    • Agree that this approach will break when used with frameworks which create and poppulate objects. In my opinion such frameworks should have an option to configure/annotate some method as a constructor or a factory and it should make use of that method.

      Generally I use this approach when ever there is no framework which makes use of these classes or no framework which does updates on these objects. I found this approach really handy, though it would not work in all the cases.

      Reply
  2. But what will happen if this class is part of a library with a number of external clients and after beeing in production for an year you reach the conclussion that the notes should be actaully reppresented by an array of strings instead of a single string.

    The idea would be that setters/getters are not only about exposing state they are also about hiding implementation details, like how you choose to save the state.

    Or is it?

    Best,
    duclad

    Reply
  3. In case of high concurentiality 2 threads in order to update the resource will create 2 different copies of the same object which will exist in the same time.

    So from now on there will be 2 instantiated Objects with the same identity. How will you solve that?

    Reply
    • To reply my own question,

      Domain driven design states that Value Objects should always be immutable. These are POJO’s which don’t have an identity. For the rest of the objects (entities) which have a role in the domain and have an identity, keeping them mutable as business rules dictate is a must, meaning that you still have to use getters and setters.

      Also there are classes which require marshalling / unmarshalling when sent over the network (Yoda Time,java.sql.Date). Or maybe you have some requirements yourself to marshall something.

      Reply
      • Agree that this will break where there is marshalling/unmarshalling of data and breaks were Object mappers are used. And its apt on my part to update the post with the feedback I have received both here and on DZone. I will take some time to understand the places where this will fail and update!

        I was expecting a lot of feedback on the approach and this has helped me to learn a bit more.

  4. I find this approach very useful in data transfer objects or serializable types, let’s say JSON, yaml or XML. For other uses, I find this kind of unfit due to the mutability nature of domain objects.

    Reply
  5. In Scala it would look like this, which I quite like. Scala makes safe defaults.

    import java.time.LocalDateTime

    class Task(final val title: String, final val notes: String, final val addedOn: LocalDateTime, final val deadline: LocalDateTime, final val assignedTo: String)

    Reply
  6. Avoiding getter/setter in this way makes extension more difficult. 1) Adding parameters to the ctor, to add fields, is a breaking change. 2) High count of actual parameters is more awkward to work with than getter/setters. No thanks.

    Reply
    • Your two remarks are problems only on the surface and boil down to good use of single responsibility design and domain modeling semantics respectively.

      1. Refactoring a constructor is a non problem because if your responsibility architecture is correct You will only use the constructor once or twice or not at all when we are talking about a marshaling/unmarshaling workflow.
      2. Most well designed domain models have much less fields than expected. Eg: You don’t inline an address into a fulfillment model, you encapsulate it in a dedicated fulfillment address model and inline that (1 field instead of 4+). Usually most models in a sane design are the combination of two to six other model components and that is quite workable.

      Reply
  7. This is a horrible design idiom and an abuse of final. It completely obliterates information hiding, orthe line between interface, implementation, an representation. In other words it distroys you ability to change the internals of this class without affecting all of the downstream client code.
    As for the indiscriminate use of final, Our world is not immutable and nor are most of our data structures. Get over it! Further more, copy on write is a programming idiom that is very hard on the hardware. 40% of all the performance problems that I run into in the field are memory efficiency related. Copy on write is a contributor to this problem.

    An object needs to have complete control over its internal state. It is the only reliable way to ensure consistency. For example, you do not see ConcurrentHashmap release its internal data structures to the world and say, have it them. In fact I would be willing to bet that you don’t know what the internal data structures look like nor even if any bits of them are final or not. And that is the way it should be. Knowing these details should only be an achidemic exercise. Consider making String final was a significant design mistake that has cost this industry billions (no, I am not exaggerating… Just think of the useful extensions that have been prevented and the hacks to get around String being final)

    Better to make the fields private but not final by default. The domain model should tell you when you need to relax visibility and/or use final. You should not provide public get/set methods by default. Instead your objects, if you’ve modeled thing well, will most often have a business need that will expose its self in the form of a method. All mutations to internal state should happen via one of these business methods. Never, ever, ever, expose internal details to you clients unless there is a strong need to do so.

    Reply
    • I think You are overgeneralizing. There is a big distinction between data constructs and processing constructs. Mostly things that are part of a framework or have an infrastructural role in a code base are processing constructs. The other stuff (domain models, representations etc.) are not. They are just value holders. Light objects.
      You give ConcurrentHashmap as an example, to point out what everybody knows in the jvm there are good reasons for such an infrastructure construct to be stateful. But most of the things the vast majority of enterprise software devs create is not that. I would even argue that if You are recreating stuff from java.util You probably are a bit misguided. Granted there are edge cases to this but they are very sparse.

      But everybody can have his opinion on this.

      Reply
    • > Our world is not immutable and nor are most of our data structures.

      This is a non-argument. To take your idea further, the world is not 0s and 1s, so do we throw out computing?

      > copy on write is a programming idiom that is very hard on the hardware.

      Immutability does not necessarily mean copy-on-write, at least in the sense that you’re talking about. In this case, his Task class has three String references and two LocalDateTime references. A new Task based on another Task could share the fields that are the same between them and it will be totally safe to share with other consumers, threads, etc. The only copy-on-write things would be references to the concrete objects, which are essentially free.

      > making String final was a significant design mistake that has cost this industry billions

      Strongly disagree. CVEs due to buffer-bumping arrays in C are announced constantly. I’ve never seen headlines stating “we’ve run out of computing resources due to String’s overhead”. When you run out of computational resources, you get another box, which is far cheaper and more reliable than fixing bugs, if you actually find those bugs before someone else takes advantage of them.

      > Better to make the fields private but not final by default. The domain model should tell you when you need to relax visibility and/or use final. You should not provide public get/set methods by default.

      I think the author’s primary mistake is advocating direct field access as the default. There’s a place for it, but getters that have access to private final fields seems much more flexible default.

      Reply
  8. The getters and setters made the code much more complicated without affording proper encapsulation. Many thanks for sharing this article. Keep blogging.

    Reply

Leave a Reply

Discover more from Experiences Unlimited

Subscribe now to keep reading and get access to the full archive.

Continue reading