Using Lombok's toString for circular relationships (e.g. bidirectional entity relationships)

8,075 views
Skip to first unread message

Tuukka Mustonen

unread,
Apr 12, 2010, 3:30:31 AM4/12/10
to Project Lombok
Hi,

I just wanted to post a note about using Lombok generated toString()
with circular relationships (in my case, I was implementing
bidirectional JPA relationship). If an object with circular
relationship is printed, or as in my case, inspected in debugger
(causing toString() to be called), it throws StackOverflowError, as
the toString() methods between the two objects result in an endless
loop. Telling Lombok to ignore either of the fields causing the
circular relationship removes this problem. Try it out like this:

@Data
class Address {
Municipality municipality;
}

@Data
@ToString(exclude = "addresses") // Without this we get
StackOverflowError
class Municipality {
Set<Address> addresses = new HashSet<Address>();
public void addAddress(Address a) {
addresses.add(a);
}
}

public class JavaTest {

public static void main(String[] args) {
Address address = new Address();
Municipality municipality = new Municipality();
municipality.addAddress(address);
address.setMunicipality(municipality);
System.out.println(municipality);
System.out.println("Done.");
}
}

Of course this is not a bug or anything. I just failed to see this
beforehand and wanted to post a note if anyone else ever happens to
try google this...

Tuukka

Reinier Zwitserloot

unread,
Apr 12, 2010, 4:47:22 AM4/12/10
to Project Lombok
Yup. We realized this could happen but then we noticed that in other
java core classes this can happen too. For example, if you create a
new Arraylist<Object> and you stick the arraylist itself into itself,
toString(), hashCode, and even equals() will all StackOverflow.

Good point about putting it up so its googlable. Thanks, Tuukka!

v6ak

unread,
Apr 12, 2010, 9:49:35 AM4/12/10
to Project Lombok
I think that this it can be solved by checking stacktrace and using a
global storage, but it is really horrible.

Maaartin

unread,
Apr 13, 2010, 6:35:35 PM4/13/10
to Project Lombok
> On 12 dub, 09:47, Reinier Zwitserloot <reini...@gmail.com> wrote:
>
> Yup. We realized this could happen but then we noticed that in other
> java core classes this can happen too. For example, if you create a
> new Arraylist<Object> and you stick the arraylist itself into itself,
> toString(), hashCode, and even equals() will all StackOverflow.

But not all of them, Arrays.deepToString(Object[]) works fine.

On Apr 12, 3:49 pm, v6ak <v...@volny.cz> wrote:
> I think that this it can be solved by checking stacktrace and using a
> global storage, but it is really horrible.

No, that's quite easy, you need only a local Set passed as parameter,
see "dejaVu" in java.util.Arrays.

For hashCode it could be done in a very similar way, e.g., by using
x.getClass().hashCode() instead of x.hashCode() for each repeated x.

For equals it requires some thinking, but I'm sure the implementation
will be as easy as in the above cases.

--
You received this message because you are subscribed to the Google
Groups group for http://projectlombok.org/

To post to this group, send email to project...@googlegroups.com
To unsubscribe from this group, send email to
project-lombo...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/project-lombok?hl=en

Dilapidus

unread,
Sep 15, 2017, 7:41:34 PM9/15/17
to Project Lombok
Exactly the problem I have (and forced by JPA)

I don't want to exclude the fields either!   Not entirely and certainly not in HashCode or Equals.   What I want do to is declare the method to use, which better not reference me out of memory ;-)

So it would look something like :

@ToString(use = "addresses.id")  

This means, when you see the addresses field, only use the id field.   Sure it would be hard/impossible to check at compile time but that might make JPA users at least, very very happy.


Reply all
Reply to author
Forward
0 new messages