A word on toString()

A word on toString()



Can you spot the problem?

AccountHolder.java



package com.example.toString;

import java.util.ArrayList;
import java.util.List;

public class AccountHolder {
   
   private String name;
   private List<Account> accList=new ArrayList<Account>();
   
   public void addAccount(Account acc){
      accList.add(acc);
   }

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   @Override
   public String toString() {
      return "AccountHolder [name=" + name + ", accList=" + accList + "]";
   }

}


Account.java
   
   
package com.example.toString;

public class Account {
   
   private String accNumber;
   private String accType;
   private AccountHolder holder;
   public String getAccNumber() {
      return accNumber;
   }
   public void setAccNumber(String accNumber) {
      this.accNumber = accNumber;
   }
   public String getAccType() {
      return accType;
   }
   public void setAccType(String accType) {
      this.accType = accType;
   }
   public AccountHolder getHolder() {
      return holder;
   }
   public void setHolder(AccountHolder holder) {
      this.holder = holder;
   }
   @Override
   public String toString() {
      return "Account [accNumber=" + accNumber + ", accType=" + accType
              + ", holder=" + holder + "]";
   }
   
   
   

}



Testing above

Main.java

package com.example.toString;

public class Main {
   
   public static void main(String[] args) {
      AccountHolder ach = new AccountHolder();
      ach.setName("Shamik Mitra");
      Account acc = new Account();
      acc.setAccNumber("100sm");
      acc.setAccType("Savings");
      acc.setHolder(ach);
      ach.addAccount(acc);
      System.out.println(ach);
   }

}



I believe you guess the problem. If you do not spot the problem please stop here and again go through the code to spot the problem.



What is the Problem?

The above code snippet, unfortunately, gives you a StackOverflowError.

While reviewing a juniors code I spotted the problem, Actually, his program runs well in the Development environment and he came to me to review his code.


To explain the essence of the problem I replicate the same here, I have an AccountHolder Object which holds the list of Account and on another hand In Account Object, we have a reference to AccountHolder.

This is a normal scenario when we design JPA entity, But the problem is we blindly populate the toString method using the editor and which create a circular call and eventually it blows up the code with StackOverflow Error.

As AccountHolder toString it tries to print the list of Account so it calls  Account toString() and in Account toString() it again tries to prints  AccountHolder so the cycle continues until StackOverFlowError occurs.
My Junior can’t spot the problem as in his program he never prints the Account or AccountHolder object so it deployed and works fine in Development server.


So what is the Point?

The point I want to convey here is that maybe this type of problem always can't be seen in naked eyes as may be there is transitive dependencies like A class has B, B has C and C has A.

So ,

  1. Try use tools which can point out your circular dependencies.(Though I am not using any due to some constraints).
  2. In a class, only prints variable which are belongs to that class. For safety purpose not print any HAS-A relation.