style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

toString()

Quizas alguien (como yo) tenga que inspeccionar las propiedades en algun punto de sus codigo sin tener que realizar un debug, puede ser cuando obtienes la iformacion de una DB a un pojo por ejemplo, cuando recibes la informacion de un Request, cuando recuperas la informacion de algun otro lugar, el chiste es que necesitas ver e estado de tus variables. Bueno en mi caso voy a trabajar con clases que tienen aprox 50 propiedades cada una (no voy a discutir si eso bueno o malo, las voy a usar y punto) pero por experiencia se que a veces puede aterarse la informacion, mas que nada en la transportacion de los datos cuand lees de un fichero, cuando encriptas y "desencriptas", cuando lo mandas por HTTP y mas qe nada hay broncas con la codificacion o que llego mocho el valor... etc

Bueno, ese es mi caso y coo yo no seré el unico que le mete mano al sistema quise sobreescribirle el toString() para que al invocarlo te muesre todas las propiedades que tiene la clase junto con su valor que almacena, de esa forma me evito hacerle el debug e inspeccionar una por una y e mi caso que son muchas propiedades pues me seria bien tedioso hacerlo

Este codigo usa reflexion y busca todas las propiedades de clase y las lista junto con e valor que tiene asignado, pero pues en mi caso tambien quise darle una alineacion paraqe el valor de las propiedades fuera mas legible

Yo defino por ejepo estas propiedades

        private String
                        aaaaaaaaa = "tengo valor",
                        bbbbbbb = "yo tabien tengo valor",
                        ccccccccccccccc,
                        ddddddddd,
                        eeeeeeee = "tienes el",
                        fffffff = "valor",
                        ggggg = "o",
                        hhhh = "te vale",
                        i,
                        jj = "ME VALE!!",
                        k;

        private double
                        qqq = 645.318,
                        www = 123.13,
                        eee = 654,
                        rrr = 7722177,
                        ttt = 666,
                        yyy = 69;

        private File
                        zzzqwe = new File("."),
                        xxxdgnf = new File("/"),
                        cccdsdfgvy = new File("c:/mi/carpeta"),
                        vvasdasvfdvkmg = new File("/tu/carpeta"),
                        bbasdasdbdhfrth = new File("/home/sweet/home"),
                        netewewwwnnert = new File("/asd/qwe.sh"),
                        mmmkjfrygsdfg = new File("/home/work/asd.waa");

Y esto se veria asi:

aaaaaaaaa..........tengo valor
bbbbbbb............yo tabien tengo valor
ccccccccccccccc....null
ddddddddd..........null
eeeeeeee...........tienes el
fffffff............valor
ggggg..............o
hhhh...............te vale
i..................null
jj.................ME VALE!!
k..................null
qqq................645.318
www................123.13
eee................654.0
rrr................7722177.0
ttt................666.0
yyy................69.0
zzzqwe..............
xxxdgnf............\
cccdsdfgvy.........c:\mi\carpeta
vvasdasvfdvkmg.....\tu\carpeta
bbasdasdbdhfrth....\home\sweet\home
netewewwwnnert.....\asd\qwe.sh
mmmkjfrygsdfg......\home\work\asd.waa

y el codigo es este:

        /**
         * Escribo mi propio metodo {@code toString()} porque quiero ver todas las propiedades
         * de mi case en la frma que yo quiero
         */

        @Override
        public String toString () {
                StringBuilder sb = new StringBuilder ();
                try {
                        Class c = Class.forName (this.getClass ().getName ());
                        Field[] f = c.getDeclaredFields ();
                        int l = getMaxLenght (f) + 4;
                        for(Field propiedad:f)
                                sb.
                                        append (rellenaEspacios (propiedad.getName (), l, '.')).
                                        append (propiedad.get (this)).
                                        append ("\n");

                } catch (Throwable e) { e.printStackTrace (); }
                return sb.toString ();
        }
       
       
       
        /**
         * Metodo que obtiene la longitud maxima de las propiedades de la clase
         *
         * @param f             Arreglo de tipo {@link Field} que encapsula lainformacion de
         *                              las propiedades de la clase
         *
         * @return      retorna el valor de la longitud maxima de un nombre de propiedad
         */

        private int getMaxLenght(Field[] f){
                int max = 0;
                for(Field field:f)
                        max = field.getName ().length () > max ? field.getName ().length ():max;
                return max;
        }
       
       
       
        /**
         * Este metodo se encarga de poner el relleno en para que en la visualizacion se vean
         * alineadas las propiedades de la clase
         *
         * @param s             Define la cadena a rellenar
         * @param l             Define la longitud final que debe tener la cadena de retorno
         * @param r             Define el caracter de relleno
         * @return
         */

        private String rellenaEspacios(String s, int l, char r){

                if(s == null || s.isEmpty () || l <= s.length ()) return s;
                StringBuilder sb = new StringBuilder (s);
                for(int indice = s.length (); indice < l; indice++) sb.append (r);
               
                return sb.toString ();
        }

Pues espro que a alguien le sirva y claro, recuerden que este lo hice a mis necesidades y si quieren que haga mas monerias pus' ahi tienen el codigo!

Por cierto, a mi me gustaria usarlo esto e varias clases, pero eso decopiar y pegar como qe no va muy bien. Si alguie ha utilizado http://projectlombok.org/ sabrá que por ejemplo le pone:

        @Setter (AccessLevel.PUBLIC)
        private String miCadena;

y por lo que lei que cuando compila ya le genero el suguiente codigo:

        public void setMiCadena(String miCadena){
                this.miCadena = miCadena;
        }

y asi con el @Getter y varias cosas mas... Bueno el punto es que si alguien sabe hacerlo y le interesa este codigo pues vamos!!

Comentarios

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

No me convence mucho

bueno, ya la revise eso de BeanUtils, no sabia que existía y bueno principalmente se trata de una librería para no manejar crudamente la reflexión. Su forma de describir las propiedades es en una cadena corridita que igual resultaría un poco tedioso de leer, por ejemplo, le puse esto a un bean

BeanUtils.describe(this).toString();

y lo que me pinta es algo asi:

{aa=null, bb=0, cc=1.0, class=class paquete.Clase}

Ahora habrá que tomar en cuenta que quiero vigilar aprox 50 propiedades y si tomamos en cuenta que la mayoria son Strings pues seguro que se nos pierden las propiedades entre los valores mostrados.

Acabo de darme cuenta que

Acabo de darme cuenta que BeanUtil solo detecta las propiedades que tengan los métodos de acceso, si no los tiene no aparecen en el describe()

Alguna vez hice algo así y la

+1 Alguna vez hice algo así y la verdad me fue medio mal con el performance.

Un "boost" es obtener todas los atributos y dejarlos en algún caché, no tiene caso buscarlos siempre si siempre van a ser los mismos:

    public String toString() {
        Field [] fields = this.getClass().getFields();
        for( f in fiedls ) { ....
     }

Puede ser:

    private Fields[] cache = this.getClass().getFields();// por decir algo  la verdad yo lo puse en algo como ReflectionObject
    public String toString() {
        for( f in fields ) etc. etc
     }

Aunque he de aclarar que esto fue por allá de Java 1.2 y desde entonces el performance ha mejorado muchísimo en la parte de reflection.

Oscar te dare una respuesta

Oscar te dare una respuesta valida (pero me la acabo de sacar de la manga) es que en una clase si la modificas por reflect pues ya no vale lo que tenias al cargar la clase por lo que te ves obligado a refrescar tu lista de metodos y propiedades (en caso de modificarla con reflect)... (fin de la respuesta sacada de la manga)

la verdadera razón por la que la metí en el método fue porque al hacer la impresión de mis propiedades me aparecian esas cosas de Fields[] y Class (cosa que no me gustaba y asi, simplemente por eso las meti (pfffffts)

Y justo por lo del rendimiento le metí StringBuilder para no afectar el rendimiento con Strings que son inmutables y bajo las cobijas hacen un despapaye cuando haces:

String cosa = "a" + "b" + "c" + "d";

Ahora con tipo de dato

Estuve moviendole a esto porque queria tambien mostrar los tipos de datos de mis propiedades. pero pues cando los metia sucedia se perdia el orden asi que decidi meterle tambien una mascara para seguir teniendo todo bie alineadito... ah, tambien agregue el nombre dela clase pues eso debe ser básico!

ahora se ve asi:

com.geb.pruebas.ListaPropiedades
String  aaaaaaaaa..........tengo valor
String  bbbbbbb............yo tabien tengo valor
String  ccccccccccccccc....null
String  ddddddddd..........null
String  eeeeeeee...........tienes el
String  fffffff............valor
String  ggggg..............o
String  hhhh...............te vale
String  i..................null
String  jj.................ME VALE!!
String  k..................null
double  qqq................645.318
double  <a href="http://www................123.13
double"
title="www................123.13
double"
>www................123.13
double</a>  eee................654.0
double  rrr................7722177.0
double  ttt................666.0
double  yyy................69.0
  File  zzzqwe..............
  File  xxxdgnf............\
  File  cccdsdfgvy.........c:\mi\carpeta
  File  vvasdasvfdvkmg.....\tu\carpeta
  File  bbasdasdbdhfrth....\home\sweet\home
  File  netewewwwnnert.....\asd\qwe.sh
  File  mmmkjfrygsdfg......\home\work\asd.waa

Este es el nuevo codigo agregand lo que ya mencione:

        /**
         * Escribo mi propio metodo {@code toString()} porque quiero ver todas las propiedades
         * de mi case en la frma que yo quiero
         */

        @Override
        public String toString () {
                StringBuilder sb = new StringBuilder (this.getClass ().getName ());
                try {
                        Field[] f = Class.forName (this.getClass ().getName ()).getDeclaredFields ();
                        int lt = getMaxLenght (f, 't');
                        int lp = getMaxLenght (f, 'p') + 4;
                        for(Field ff:f)
                                sb.
                                        append ("\n").
                                        append (rellenaEspacios (ff, lp, lt, '.')).
                                        append (ff.get (this));
                } catch (Throwable e) { e.printStackTrace (); }
                return sb.toString ();
        }
       
       
       
        /**
         * Metodo que obtiene la longitud maxima de las propiedades de la clase, verifica el tipo
         * de longitud que se desea obtener con el uso del parametro t
         *
         * @param f             Arreglo de tipo {@link Field} que encapsula lainformacion de
         *                              las propiedades de la clase
         * @param t             Define el tipo de longitud que se desea obtener. Actualmente se soporta
         *                              'p' para los nombres de las propiedades y 't' para los tipos
         *
         * @return      retorna el valor de la longitud maxima de un nombre de propiedad
         */

        private int getMaxLenght(Field[] f, char t){
                int max = 0;
                for(Field ff:f)
                        switch (t){
                                case 'p':
                                        if(ff.getName ().length () > max) max = ff.getName ().length ();
                                        break;
                                case 't':
                                        if(ff.getType ().getSimpleName ().length () > max)
                                                max = ff.getType ().getSimpleName ().length ();
                                        break;
                                default: return -1;
                        }
                       
                return max;
        }
       
       
       
        /**
         * Este metodo se encarga de poner el relleno en para que en la visualizacion se vean
         * alineadas las propiedades de la clase
         *
         * @param s             Define la cadena a rellenar
         * @param lp    Define la longitud final que debe tener la cadena de retorno
         * @param lp    Define la longitud del tipo mas largo
         * @param r             Define el caracter de relleno
         * @return
         */

        private String rellenaEspacios(Field f, int lp, int lt, char r) throws Exception{

                if(f.getName () == null || f.getName ().isEmpty () || lp <= f.getName ().length ())
                        return f.getName ();

                StringBuilder sb = new StringBuilder (
                                String.format (
                                                "%" + lt + "s  %s",
                                                f.getType ().getSimpleName (),
                                                f.getName ()));
               
                for(int i = f.getName ().length (); i < lp; i++) sb.append (r);

                return sb.toString ();
        }

No es mucho relajo

¿No creen que es mucho relajo para un toString()? En lo personal me gusta tener mis objetos con el toString(), es muy util, pero pues para ahorrarme unos ciclos del procesador lo hago a patin aun así sean n propiedades, simplemente uso un buen editor de texto y con un replace y en un par de minutos tengo mi toString() como lo quiero, ademas a veces en lo particular no quiero mostrar todas las propiedades, solo las mas representativas.

@java.daba.doo. No me refiero

@java.daba.doo.

No me refiero al valor, sino al los campos en si mismos. Es decir, cuando tienes declarado:

class A {
   int i ;
}

El atributo i ya no puede desaparecer de la clase en tiempo de ejecución ( al menos no de una forma "natural" de Java, por ahí se puede instrumentar la clase y quizá con un classloader customizado re-cargarla pero estamos hablando de casos normales )

Entonces, si ya no se puede quitar ( ni poner una nueva ) no le veo mucho caso pedirla siempre. Lo que definitivamente si es necesario es obtener el valor.

Ahora, lo que te decía es que de Java 1.2 para acá esas cosas mejoraron muchísimo su desempeño, es muy probable que ya se haga un cache interno.

@luiguisf:

Si es mucho relajo, pero no se propone que se haga así en toooodas las clases de todos los proyectos. Puede ser útil en ciertas ocasiones y está más como demo de reflection para ayudar a revisar los objetos.

Algo que se le podría hacer de forma adicional, es hacer que todo ese computo sea opcional ( dependiendo de una configuracion ) y encapsular la lógica en una sola clase para no tener que hacer ( tanto ) copy/paste:

Por ejemplo

class Empleado {
   String nombre;
   ...20 atributos más
   
   public String toString() {
       return ToString.isEnabled() ?  ToString.toString( this ) :  "Empleado.nombre = " + nombre;
   }
}
class Departamento {
   String nombre;
   ...
  public String toString() {
       return ToString.isEnabled() ?  ToString.toString( this ) :  "Departamento.nombre = " + nombre;
   }
}

Y definir la utilería "ToString" como:

class ToString {
     private static Logger logger = Logger.getLogger(ToString.class.getName() );
     public static boolean isEnabled() {
         return logger.isLoggable( Level.FINEST );
     }
     public static String toString( Object o ) {
           for( Field f : o.getClass().getFields() ) {
                 stringBuilder.append( ....
           }
      }
}

Que me es precisamente lo algo como lo que hace el BeanUtils, pero ya no revisé si era exactamente lo que quería Jdd.

Es que yo soy bie flojo y no

Es que yo soy bie flojo y no me gusta hacer la misma tarea manual muchas veces. Por es lo hice, de hecho lo que dices es justo lo que venia haciendo pero ya me aburrio eso...

Bueno, aqui esta e codigo para otros "flojos" como yo y para los muy "chambeadores" pueden seguir talacheando:

1.- (llenar de System.out.println() su codigo) copiar el texto

2.- Copiar la salida

3.- Pegarlo en el editor de texto (una ventana mas)

4.- Definir los criterios dereemplazo y darle reemplazar

5.- Seguir en lo qe estabas

Nah, yo si soy rete flojo y no o haria, por eso digo: que se canse la maquina ¿yo por que?

por cierto, si esto lo pones en un Logger y defines el nivel de "traza" o no se como venga pero que sea el de menos importancia, lo activas y desactivas cuando se te antoje xon solo reemplazar una cosita algo asi como:

logger.setLevel(Levels.TODO)

...

logger.setLevel(Levels.NOMAS_ERRORES)

...

logger.setLevel(Levels.NOMAS_ADVERTENCIAS)

pero eso de los loggers: es oootra histoooooria!

Regresando: si es mucho relajo, por eso menciono que me gustaria una anotacion para solo escribirla a la clase y solito te haga el override... aunque por ahora no se como hacerlo (ya o investigare)

Osea que quiero que se vea asi:

import doo.daba.java.util.ToString

@ToString
public class MiClase {

...

Eso si seria lo optimo, de hecho hasta se ve lindo... Saludos!

Estabatan aferrado a las

Estabatan aferrado a las anotaciones que olvide pensar en eso que dices Oscar

Pasa que estaba tan aferrado a que fosozamente hiciera override a su metodo toString() por eso lo definia asi con @ToString pero mientras esto que dices es muy adecuado

ah y a o que me eferia e java es que puedas agregarle Fields a la clase.. por eso decia que lo que cargues a inico de la clase despues de una manipulacion de Reflect (si afecta el nombre, elimina o agrega una propiedad de la clase)... bueno yo he visto que en tiempo de ejecucion se pueden crean una clase completita desde "{" hasta "}"

:p

Problemas

Oscar: pues tendra que ser dentro de la misma clase porque cuando lo ejcuto con metodos privados me sale una linda Excepcion

java.lang.IllegalAccessException: Class doo.daba.java.util.ToString can not access a member of class doo.daba.java.chacharas.reflect.pruebas.ListaPropiedades with modifiers "private"
doo.daba.java.chacharas.reflect.ListaPropiedades
String  aaaaaaaaa..........
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
        at java.lang.reflect.Field.doSecurityCheck(Field.java:960)
        at java.lang.reflect.Field.getFieldAccessor(Field.java:896)
        at java.lang.reflect.Field.get(Field.java:358)
        at doo.daba.java.util.ToString.toString(ToString.java:28)
        at doo.daba.java.chacharas.reflect.ListaPropiedades.toString(ListaPropiedades.java:54)
        at doo.daba.java.chacharas.reflect.ListaPropiedades.main(ListaPropiedades.java:60)

y si no lepongo modificador de acceso sale lo mismo:

java.lang.IllegalAccessException: Class doo.daba.java.util.ToString can not access a member of class doo.daba.java.chacharas.reflect.pruebas.ListaPropiedades with modifiers ""

bueno lo checo despues

Ahh si pero eso ya no es

Sobre los private... ahh pos si verdad? .. Creo que lo que yo hice entonces fue obtener los métodos que empezaran con get.

Ahh si pero eso ya no es reflection es instrumentación, es modificar el bytecode y demás pero incluso entonces solo lo puedes hacer una vez antes de que la clase se cargue. Usando algo como JavaRebel se puede volver a cargar y demás.

Lo que mencionas podría ser una anotación + AOP ( Enrique escribió sobre esto ) se podría modificar el toString como dices.

Ahora que pensandolo bien, si se va a modificar el bytecode y sabemos que atributos tiene la clase, mejor escribirlos para que se impriman estáticamente.

:) :) No te interesaría mejor ayudarme a esto: http://bit.ly/Ryz-language :)

Aunque la implementación que estoy haciendo es "contra-natura" jejeje

Imagen de greeneyed

Lombok ya lo hace

La librería que mencionas al final, Lombok, ya te crea un método que te muestra los campos en el toString:

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

Yo de un tiempo a esta parte uso la librería bastante y hasta he implementado una anotación propia, aunque de momento solo la versión javac por que generar código en tiempo de compilación para Eclipse es un lío de cuidado :).

@OscarRyz La verdad no le se

@OscarRyz La verdad no le se a esas cosas y si habia checado lo de AOP que habia implementado sobre jAlarms, de hecho es justo la entrada que voy a estudiarme (a fondo) en cuanto tenga el tiempito

@greeneyed si dehecho en eso me inspire pero pues lo muestra en una linea plana (cosa qe no me gusta) y fue por eso que hice esto

No es que sea chambeador

A los 5 pasos a que te refieres pues solo se hace cuando creas/modificas la clase y no veo el para que se use System.out.println() si lo que quiero es el nombre de la propiedad no el valor, ni siquiera hay que correr la clase. En lo personal prefiero los atajos de la IDE y listo lo hace en automatico, ademas de que podemos definir un template para que el toString() se genere a nuestro gusto. De esta forma bajamos algo el acoplamiento.

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">