Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

A Word on toString()

DZone's Guide to

A Word on toString()

If you aren't careful, careless use of toString methods and your transitive properties might lead to circular dependencies and the dreaded StackOverflowError.

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.

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);
   }

}


You've probably found the problem by now, but if you haven't, look it over one more time.

What Is the Problem?

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

I spotted this problem while I was reviewing a junior's code. Actually, his program runs well in Dev, so he came to me to review his code.

To explain the essence of the problem, I replicated the same thing here. I have an AccountHolder Object that holds the list of Account, and on the other hand, in the Account object, we have a reference to AccountHolder.

This is a normal scenario when we design a JPA entity, but the problem is that we've blindly populated the toString method using the editor. That will create a circular call and eventually blow up the code with the StackOverflowError.

Root of StackOverflow

As in the AccountHolder toString method, it tries to print the list of Account, so it calls Account toString(). In Account toString(), it again tries to print AccountHolder, so the cycle continues until the StackOverFlowError occurs.

My junior couldn't spot the problem, as in his program, he never prints the Account or AccountHolder object, so it deployed and worked fine on the Development server.

So What Is the Point?

The point I want to convey here is that maybe this type of problem can't always be seen by the naked eye. Maybe there are transitive dependencies at a very deep level, like A class has B, B has C, and C has D, and D has A.

So:

  1. Try use tools that can point out your circular dependencies. (Though I am not using any due to some constraints).
  2. In a class, only print variables that belong to that class. For safety purposes, don't print any HAS-A relations.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.

Topics:
java ,tostring ,stackoverflowerror ,circular dependencies ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}