Java toString () usando reflexión?


Estaba escribiendo un toString() para una clase en Java el otro día escribiendo manualmente cada elemento de la clase en una cadena y se me ocurrió que usando reflexión podría ser posible crear un método toString() genérico que podría funcionar en TODAS las clases. Es decir, averiguaría los nombres y valores de los campos y los enviaría a una cadena.

Obtener los nombres de los campos es bastante simple, esto es lo que se le ocurrió a un compañero de trabajo:

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;
}

Usando una fábrica podría reducir el sobrecarga de rendimiento almacenando los campos una vez, la primera vez que se llama a toString (). Sin embargo, encontrar los valores podría ser mucho más caro.

Debido a la realización de la reflexión esto puede ser más hipotético que práctico. Pero me interesa la idea de la reflexión y cómo puedo usarla para mejorar mi programación diaria.

Author: James McMahon, 2009-01-14

7 answers

Apache commons-lang ReflectionToStringBuilder hace esto por usted.

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

// your code goes here

public String toString() {
   return ReflectionToStringBuilder.toString(this);
}
 78
Author: krosenvold,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-25 09:03:31

Otra opción, si está de acuerdo con JSON, es la biblioteca GSON de Google.

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

Va a hacer la reflexión por ti. Esto produce un archivo JSON agradable y fácil de leer. Fácil de leer siendo relativa, la gente no tecnología podría encontrar el JSON intimidante.

También puede hacer que GsonBuilder sea una variable miembro, si no desea que se vuelva a crear cada vez.

Si tiene datos que no se pueden imprimir (como una secuencia) o datos que simplemente no desea imprimir, simplemente puede agregar @Expose etiquetas a los atributos que desea imprimir y, a continuación, utilice la siguiente línea.

 new GsonBuilder()
.setPrettyPrinting()
.excludeFieldsWithoutExposeAnnotation()
.create()
.toJson(this);
 7
Author: Daniel Schmidt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-04 18:50:54

W/reflexión, como yo no había sido consciente de la biblioteca apache:

(tenga en cuenta que si hace esto, probablemente necesitará tratar con subobjetos y asegurarse de que se impriman correctamente , en particular, los arrays no le mostrarán nada útil)

@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());
}
 6
Author: Steve B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-14 18:23:17

Si está utilizando Eclipse, también puede echar un vistazo a JUtils toString generator, que lo hace de forma estática (generando el método en su código fuente).

 5
Author: Olivier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-14 17:00:42

No es reflexión, pero eché un vistazo a generar el método toString (junto con equals/hashCode) como un paso posterior a la compilación utilizando la manipulación de bytecode. Los resultados fueron mixtos.

 4
Author: McDowell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-01-14 18:17:35

Puede usar bibliotecas ya implementadas, como ReflectionToStringBuilder de Apache commons-lang. Como se mencionó.

O escribe smt similar por ti mismo con API de REFLEXIÓN.

Aquí está algunos ejemplos:

class UniversalAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}
 3
Author: nazar_art,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-20 22:27:39

Aquí está el Netbeans equivalente a la respuesta de Olivier; complemento smart-codegen para Netbeans.

 2
Author: James McMahon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-03-17 21:59:44