views:

1430

answers:

5

I was writing a toString() for a class in Java the other day by manually writing out each element of the class to a String and it occurred to me that using reflection it might be possible to create a generic toString() method that could work on ALL classes. I.E. it would figure out the field names and values and send them out to a String.

Getting the field names is fairly simple, here is what a co-worker came up with:

public static List initFieldArray(String className) throws ClassNotFoundException {

    Class c = Class.forName(className);
    Field field[] = c.getFields();
    List<String> classFields = new ArrayList(field.length);

    for (int i = 0; i < field.length; i++) {
        String cf = field[i].toString();
        classFields.add(cf.substring(cf.lastIndexOf(".") + 1));
    }

    return classFields;
}

Using a factory I could reduce the performance overhead by storing the fields once, the first time the toString() is called. However finding the values could be a lot more expensive.

Due to the performance of reflection this may be more hypothetical then practical. But I am interested in the idea of reflection and how I can use it to improve my everyday programming.

+12  A: 

Apache commons-lang ToStringBuilder does this for you.

krosenvold
Yeah I actually saw that right after I posted this question. I am still interested in the details. I am going to dig through their code and how they implement it.
James McMahon
+1. When using this, understand that reflection is an order of magnitude slower than explicit field access. In some cases, particularly with objects that are still in development and subject to change, reflection is a good idea. Otherwise, it's probably better to use the explicit ToStringBuilder
kdgregory
+2  A: 

If you're using Eclipse, you may also have a look at JUtils toString generator, which does it statically (generating the method in your source code).

Olivier
That is interesting, I don't use eclipse personally, but I am sure some of my co-workers would interested in this.
James McMahon
+1  A: 

Not reflection, but I had a look at generating the toString method (along with equals/hashCode) as a post-compilation step using bytecode manipulation. Results were mixed.

McDowell
That looks pretty interesting, I will have to read through it when I get a chance. That seems like it might be a really good approach. Alittle much for my particular domain, business apps, but if some could get your approach working without a hitch it would make a good JSR.
James McMahon
+2  A: 

W/reflection, as I hadn't been aware of the apache library:

(be aware that if you do this you'll probably need to deal with subobjects and make sure they print properly - in particular, arrays won't show you anything useful)

@Override
public String toString()
{
 StringBuilder b = new StringBuilder("[");
 for (Field f : getClass().getFields())
 {
  if (!isStaticField(f))
  {
   try
   {
    b.append(f.getName() + "=" + f.get(this) + " ");
   } catch (IllegalAccessException e)
   {
    // pass, don't print
   }
  }
 }
 b.append(']');
 return b.toString();
}


private boolean isStaticField(Field f)
{
 return Modifier.isStatic(f.getModifiers());
}
Steve B.
A: 

Here is the Netbeans equivalent to Olivier's answer; smart-codegen plugin for Netbeans.

James McMahon