Printing collection size or existance of a certain field using lombok

Viewed 115

I have objects with circular references like so:

@Data
class ClassA{
    private int someInt;
    private List<ClassB> someCollection;
}

@Data
class ClassB{
    private int someInt;
    private ClassA someInstance;
}

So whenever I do a toString() on an object that has a circular reference the stack overflows as you would expect.

So far I was able to prevent this using @lombok.ToString.Exclude like so:

@Data
class ClassA{
    private int someInt;
    @ToString.Exclude
    private List<ClassB> someCollection;
}

Or also like this:

@Data
class ClassB{
    private int someInt;
    @ToString.Exclude
    private ClassA someInstance;
}

However, this leaves me with objects that hide some crucial debugging information.

Is there anyway to use an annotation to get information about the field, but not the field itself? Something like for example:

@Data
class ClassA{
    private int someInt;
    @ToString.CollectionSize //this could print someCollection.getSize()=n
    private List<ClassB> someCollection;
}

Or like:

@Data
class ClassB{
    private int someInt;
    @ToString.IsNull // this could be someInstance.isNull()=false
    private ClassA someInstance;
}

Either that or is there an easy way to append behaviour to lombok's toString() is just that lombok is really, really, really useful... and it would be a shame to have to override the whole toString() in these cases.

2 Answers

Yes, you can; make a method with the same name as the field, which returns a String. Then @ToString.Include that one, and it'll replace the field. For example:

@ToString.Include
private String someCollection() {
    return "Collection(" + someCollection.size() + ")";
}

you can name the method something else, and set the name via the @ToString.Include option to the field name as well, if you prefer to call this method someCollectionToString or what not.

It just ocurred to me that I could actually just add a new method that appends the required text, this is so obvious that I feel bad.

@Data
class ClassA{
    private int someInt;
    @ToString.Exclude
    private List<ClassB> someCollection;
    
    public String deepToString(){
        return toString() + "ClassB Collection size: " + someCollection.size();
    }
}

I'm gonna leave the question open just in case there's a better way, but this will do, since it's a realtively rare case.

Related