16 kwietnia 2007

Implementacja metody toString() z użyciem Reflection API

Zapewne każdy przedefiniowywał kiedyś metodę toString() klas dziedziny aplikacji, aby ułatwić sobie testowanie czy wykrywanie błędów. Jest to zajęcie o tyleż proste, co jeśli wykonywane w najprostszy z możliwych sposobów a więc dla każdej z klas z osobna, nudne i nużące. Tym bardziej, że nie ma uzasadnienia dla wykonywania tej pracy. Z pomocą przychodzi Reflection API. Dla tych, którzy posiadają największą z cnót programisty, lenistwo, załączam gotowy do użycia kod. Wymaga on Javy 5, ale łatwo przerobić go tak by działał także na starszych wersjach.

import java.lang.reflect.Field;

public class SelfDescribingObject {
public String toString() {
StringBuffer objDescBuffer = new StringBuffer(this.getClass().getSimpleName());

Class currentClass = this.getClass();
while (currentClass != null) {
Field fields[] = currentClass.getDeclaredFields();

try {
objDescBuffer.append(fieldsToString(fields));
} catch (Exception exc) {
return exc.toString();
}

currentClass = currentClass.getSuperclass();
}

return objDescBuffer.toString();
}

private StringBuffer fieldsToString(Field[] fields) throws IllegalAccessException {
StringBuffer objDescBuffer = new StringBuffer();

for (int i = 0; i < fields.length; i++) {
fields[i].setAccessible(true);

objDescBuffer.append(" ");
objDescBuffer.append(fields[i].getName());
objDescBuffer.append(": ");
objDescBuffer.append(fields[i].get(this));
}

return objDescBuffer;
}
}

3 komentarze:

Michał Jonik pisze...

A dla tych jeszcze bardziej leniwych polecam ReflectionToStringBuilder :)

smiesznie pisze...

Cześć

Właśnie chciałem zrobić tutaj wpis o ReflectionToStringBuilder, ale widzę, że michał mnie ubiegł :)

btw:
W Java 5 i wyższych lepiej nie używać StringBuffer. Tak jak stoi w JavaDoc tutaj:
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html

... napisane jest, że:
This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.

Pozdrowienia,
Adam

Mariusz Lipiński pisze...

Dzięki za uwagę ad. StringBuilder vs. StringBuffer. Co do ReflectionToStringBuilder i mojej implementacji - moja implementacja nie jest odporna na zapętlenia, ReflectionToStringBuilder jest. Inną alternatywą jest serializacja do XML'a, jedną z możliwości, z użyciem biblioteki XStream opisałem tutaj: Serializacja do XML i deserializacja przy użyciu XStream