6

I want to have all of my classes implement toString() the same way using Java reflection. There are two ways I came up with.

  1. Create a base class such as MyObject overriding toString() and all my classes would extend it, but I'm not sure if it'd be an overkill.

  2. Use Eclipse to generate the overridden toString() for each class. The downside of it is that there'd be a lot of code redundancy.

Which is the preferred method? If you go with Eclipse templates, is there a way to auto-generate it when you do New > Class, instead of having to do Source > Generate toString() every time?

Tom Tucker
  • 11,676
  • 22
  • 89
  • 130
  • Such a `toString()` method would be very generic if it works with all classes. I can't see that it would be much more useful than the default `toString()` that gives the class and an identifier for the object. What are you trying to achieve / what problem are you trying to solve by doing this? – Gyan aka Gary Buyn Oct 17 '11 at 23:28
  • It's just for debugging purposes. I find it really helpful that eclipse displays a reference variable's value using toString() when you hover your mouse over it. – Tom Tucker Oct 17 '11 at 23:32
  • See also [Auto-generating toString Method](http://stackoverflow.com/questions/2653268/auto-generating-tostring-method) – Vadzim Dec 06 '13 at 18:39

4 Answers4

5

As Harkness says, use commons-lang ReflectionToStringBuilder.

Rather than have a base class, I'd use AOP such as aspectj to inject this implementation into all of your classes at compile time.

Another option is to use a tool like ASM to transform your classes at compile time to inject toString methods. Both approaches use the same basic concepts, ASM being a more 'raw' version of class file modification.

MeBigFatGuy
  • 28,272
  • 7
  • 61
  • 66
  • +1 I don't think that violating the "is-a" relationship is a big deal. The fact is that all of his classes share common functionality (the exact same implementation of toString) so making them derive from a base class is acceptable. However, he mentioned that this is for debugging purposes so using AOP will be easier to remove when he's finished. Nice answer. – jeff Oct 18 '11 at 00:29
  • Thanks guys. Could you elaborate on AOP? Can I do it without using annotations? – Tom Tucker Oct 18 '11 at 01:44
  • 1
    the nice thing about AOP is the source code has absolutely no modifications, and is completely unaware of it. See http://eclipse.org/aspectj/ and the thousands of tutorials on aspectj – MeBigFatGuy Oct 18 '11 at 05:31
3

See ToStringBuilder and its subclass ReflectionToStringBuilder from Apache Commons Lang. The latter would allow you to implement toString() generically in your base class or add it to the template:

public String toString() {
    return ReflectionToStringBuilder.toString(this);
}
David Harkness
  • 35,992
  • 10
  • 112
  • 134
  • I agree with this response. But we can complement explaining that Java only support simple inheritance and use it for just reuse toString() is a bad idea from OO paradigm perspective. – Ernesto Campohermoso Oct 17 '11 at 23:29
  • @Ernesto Campohermoso: I think you're seriously confused ; ) *Hermeso extends MyObject* and *MyObject extends Object* <-- There are exactly zero issues here, I didn't "lost" my ability to extend *MyObject* by having *MyObject extends Object* I think "simple inheritance" doesn't mean what you think it means ; ) – Cedric Martin Oct 17 '11 at 23:46
  • @CedricMartin Assume that later you really need to inheret Hermeso from other class GenericHermeso which contain really similar behavior and/or attributes. You will need extends GenericHermeso to MyObject and then extends Hermeso to GenericHermeso. I think this is the correct way to use the OO paradigm. Other case, if you are using a framework that doesn't have POJO development you sure will need to inherit form Servlet, Thread, Action, and son on ;) – Ernesto Campohermoso Oct 17 '11 at 23:59
3

Option 1 is a really bad idea, because it imposes an "is a" constraint to your implementations for no good reason, and every one of your classes must inherit from the same base class. This is unlikely to even be possible.

Option 2 is also a bad idea - you'd have the same code repeated in every class - a maintenance nightmare and adding no value.

A better option is to use a utility class:

public class MyUtils {

    public static String toString(Object object) {
        // your reflection impl here
    }

}

public class MyClass {

    ...

    public String toString() {
        return MyUtils.toString(this);
    }
}
Bohemian
  • 412,405
  • 93
  • 575
  • 722
2

You could use lombok to do this as well, see:

http://www.projectlombok.org/features/ToString.html

If you are interested in additionally generating all getters, setters, toString, hashCode, and equals, you can use the @Data annotation, see:

http://www.projectlombok.org/features/Data.html

Kevin
  • 24,871
  • 19
  • 102
  • 158