Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java toString() using reflection?

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.

like image 213
James McMahon Avatar asked Jan 14 '09 16:01

James McMahon


3 Answers

Apache commons-lang ReflectionToStringBuilder does this for you.

import org.apache.commons.lang3.builder.ReflectionToStringBuilder

// your code goes here

public String toString() {
   return ReflectionToStringBuilder.toString(this);
}
like image 190
krosenvold Avatar answered Oct 18 '22 16:10

krosenvold


Another option, if you are ok with JSON, is Google's GSON library.

public String toString() {
    return new GsonBuilder().setPrettyPrinting().create().toJson(this);
}

It's going to do the reflection for you. This produces a nice, easy to read JSON file. Easy-to-read being relative, non tech folks might find the JSON intimidating.

You could make the GSONBuilder a member variable too, if you don't want to new it up every time.

If you have data that can't be printed (like a stream) or data you just don't want to print, you can just add @Expose tags to the attributes you want to print and then use the following line.

 new GsonBuilder()
.setPrettyPrinting()
.excludeFieldsWithoutExposeAnnotation()
.create()
.toJson(this);
like image 29
Daniel Schmidt Avatar answered Oct 18 '22 16:10

Daniel Schmidt


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());
}
like image 6
Steve B. Avatar answered Oct 18 '22 18:10

Steve B.