tabla generica

es posible crear una tabla generica normalmente asi creo la tabla, pero me gustaria no se que este codigo fuera generico y no estar creando uno nuevo para cada tabla

public class NominaEmergenteTableModel extends AbstractTableModel  {
     private static final int  COL_CEDULA = 0;
     private static final int  COL_NOMBRES=1;
     private static final int  COL_TOTALPAGAR=2;
     private static final int  COL_CONSECUTIVO=3;
     private static final int  COL_FECHA_HABILITA_PAGO=4;
     private static final int  COL_FECHA_PAGAR=5;
     private static final int  COL_ESTADOPAGO=6;
 
     private List<IPagoNominaDTO> listaNomina;
     public NominaEmergenteTableModel(List<IPagoNominaDTO> listaNomina) {
        this.listaNomina = listaNomina;}
    @Override
    public int getRowCount()
    {
        if(listaNomina!=null)
            return listaNomina.size();
        else return 0;
    }
    @Override
    public int getColumnCount() {
        return 7;}
    @Override
    public Object getValueAt(int rowIndex, int columnIndex)
    {
        if(listaNomina!=null)
        {
        IPagoNominaDTO nomina = listaNomina.get(rowIndex);
     
        if (columnIndex == COL_CEDULA) {
            return nomina.getCedula();}
        else if (columnIndex == COL_NOMBRES)
        {  return nomina.getNombreCompleto();}
        else if (columnIndex == COL_TOTALPAGAR)
        {  return nomina.getTotalPagar();}
         else if (columnIndex == COL_CONSECUTIVO)
        {  return nomina.getConcecutivo();}
          else if (columnIndex == COL_FECHA_HABILITA_PAGO)
        {  return nomina.getFechaPagar();}
        else if (columnIndex == COL_FECHA_PAGAR)
        {  return nomina.getFechaPagoNomina();}
        else if (columnIndex == COL_ESTADOPAGO)
        {  return nomina.getIsPagado();}
        return null;}
        else{return null;}}
    @Override
     
    public String getColumnName(int column) {
        String columns = "";
        switch (column) {
            case COL_CEDULA:
                columns = "CEDULA";
                break;
            case COL_NOMBRES:  
                columns = "NOMBRES";
                break;
            case COL_TOTALPAGAR:  
                columns = "TOTALPAGAR";
                break;
            case COL_CONSECUTIVO:  
                columns = "CONS";
                break;
               
             case COL_FECHA_HABILITA_PAGO:  
                columns = "FECHA HAB. PAGO";
                break;    
               
            case COL_FECHA_PAGAR:  
                columns = "FECHA PAGO";
                break;
            case COL_ESTADOPAGO:  
                columns = "PAGADO";
                break; }
        return columns; }
    @Override
    public Class<?> getColumnClass(int columnIndex) {
     
        if (columnIndex ==  COL_CEDULA) {
            return Long.class; }
        else if (columnIndex ==   COL_NOMBRES) {
            return String.class;}
        else if (columnIndex ==   COL_TOTALPAGAR) {
            return Double.class;}
         else if (columnIndex ==   COL_CONSECUTIVO) {
            return Integer.class;}
          else if (columnIndex ==   COL_FECHA_HABILITA_PAGO) {
            return Date.class;}
        else if (columnIndex ==   COL_FECHA_PAGAR) {
            return Date.class; }
        else if (columnIndex ==   COL_ESTADOPAGO) {
            return String.class; }
        return null;
     }
     public IPagoNominaDTO get(int row) {
        if(listaNomina!=null)
        {return listaNomina.get(row);}
        else
            return null;}}

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.

Si. Utilizando reflection,

Si. Utilizando reflection, as'i puedes saber cuantos campos tiene una clase y su tipo de dato. Lo mas recomendable es hacer esta introspección solamente una vez y luego acceder a los campos directamente para que no se tarde tanto.

Ser'ia algo como lo siguiente ( pseudo java - lease, no lo compile siquiera, le faltan @Overrides y asi)

class BeanTableModel extends AbstractTableModel {
     private List<Method> methods;
     private List elements;
     static BeanTableModel  createModelFor( List elements)  {
          if ( elements.isEmpty() ) {
               return EmtpyTableModel(); // return somethien that does nothing  
         }
         List<Method> getters = ...
        for ( Method m : elements.get(0).getClass()getMethods() ) {
              if (m.getName().startWith("get") {
                      getters.add( m );
             }
         }
         return new BeanTableModel( elements, getters );        
     }
     private BeanTableModel(List elements, List<Method>methods ) {
        this.elements = elements;
         this.methods = methods;
     }
     int rowCount() {
         return elements.size();
     }
     Object valueAt( int i, intj ) {
          Object o  = elements.get(i);
          return methods.get(j).invoke( o );
     }
    int columnCount() {
        return  methods.size();
   }
   String columnName( int i ) {
         /// aqui se puede quitar le el "get" al metodo
        return methods.get(i).substring(3); /// regresar el nombre a partir del indice 3
     }
    Class columnClass( int i ) {
         return methods.get(i).getReturnType();
     }
}

Aqui estan los docs relevantes:

http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#getDeclaredField(java.lang.String)

http://docs.oracle.com/javase/tutorial/reflect/member/methodInvocation.html

Es mucho muy probable que se pueda usar una anotación propia o quizá una existente y en vez de obtener los métodos y filtrarlos por get, se puedan solamente leer los métodos con cierta anotación y sacar también de ahí el nombre de la columna a presentar, porque lo que se muestra aqui regresaria el nombre del método sin el get. De esa forma spodríaia poner algo como

///por cierto, en vez de tener  IPagoNominaDTO  como nombre de la clase podrias simplemente tener PagoNomina,  no necesitas ni el I y el DTO. Mejor aun, porque no simplem,ente Nomina

@Tableable
class Nomina {
   @Column(name="Fecha de pago")
   public Date getFechaPagar() {
      return this.fechaPagar;
    }
    .... etc.

}

Definitivamente es posible hacer eso y combinarlo con el codigo de introspección mostrado antes.

Cuando lo tengas pon un blog post de como lo hiciste y asi aprendemos todos.

Suerte!

Imagen de ezamudio

anotaciones

Lo que dice Oscar de las anotaciones me parece más eficiente. Incluso para no tener que inventar tus propias anotaciones, podrías usar las de Validation (JSR303) o las de JPA (JSR220).

ok estoy leyendo sobre reflexion...

al hacer esto me debe traer una lista con todas los atributos de mi clase si los trae todos pero me trae uno extra no se porque
se llama class no se por que ese atributo extra llamado class que no existe en la clase?????

 List<PropertyDescriptor> columns = new ArrayList<PropertyDescriptor>();
 BeanInfo info =Introspector.getBeanInfo(miClase.class);
  PropertyDescriptor[] pds = info.getPropertyDescriptors();
columns.addAll(Arrays.asList(pds));

 System.out.println(columns.get(1).getDisplayName());

Porque todos los objetos

Porque todos los objetos heredan de la clase Object que define una propiedad llamada class

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#getClass()

ok

como hago para no tener en cuente ese atributo??

ya solucionado...

para no tener en cuenta el atributo que genera la clase Object de la cual hereda todas las clase solo hago:

 BeanInfo info =Introspector.getBeanInfo(ProductoDTO.class,Object.class );

El beaninfo es un tanto viejo

El beaninfo es un tanto viejo y tiene el inconveniente de que necesitaras una clase extra donde esta la información misma del bean.

Esto lo puedes hacer con anotaciones y como dice ezamudio, lo mejor será reutilizar alguna existente.

No puse el ejemplo antes porque no sabia como hacerlo , pero resultó no ser tan difícil.

Aqui va un ejemplo de una clase usando la anotación "Column" que tuviera un metodo "name"

// Ejemplo.java
import java.lang.reflect.Method;
import java.util.Arrays;
public class Ejemplo {
    private String name;
    private String lastName;
    @Column(name="Nombre")  
    public String getName() {
        return name;
    }
    @Column(name="Apellido")
    public String getLastName() {
        return lastName;
    }
}
//Consumiendo la anotacion.
class Main {
    public static void main( String ... args ) {
        for( Method m : Ejemplo.class.getMethods() ) {
            if (m.isAnnotationPresent(Column.class) ) {
                System.out.printf("Metodo %s, nombre: %s%n", m.getName(), m.getAnnotation(Column.class).name());
            }
        }
    }
}

La anotacion seria:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String name();
}

Pero de nuevo, busca una existente, va a ser mas facil.

ok

voy a probarlo con Hibernate Validator

ok oscar ya tengo esto

con hibarnate jpa uso la anotacion @column
y hago:

public class ProductoDTO implements IProductoDTO {
   
    private Integer prod_id;
    private String  prod_desc;
    private Double  prod_precio;
    private Integer prod_stock_d;
    private Integer prod_stock_a;
    private Date    prod_fecha;
    private ICategoriaDTO categoria;

    public ProductoCensBodegaDTO() {
    }

    public ProductoDTO(Integer prod_id, String prod_desc, Double prod_precio, Integer prod_stock_d, Integer prod_stock_a, Date prod_fecha, ICategoriaDTO categoria) {
        this.prod_id = prod_id;
        this.prod_desc = prod_desc;
        this.prod_precio = prod_precio;
        this.prod_stock_d = prod_stock_d;
        this.prod_stock_a = prod_stock_a;
        this.prod_fecha = prod_fecha;
        this.categoria = categoria;
    }

    @Override
    @Column(name="Prod_id")  
    public Integer getProd_id() {
        return prod_id;
    }

    @Override
    public void setProd_id(Integer prod_id) {
        this.prod_id = prod_id;
    }
   
    @Override
    @Column(name="Prod_desc")
    public String getProd_desc() {
        return prod_desc;
    }

    @Override
   
    public void setProd_desc(String prod_desc) {
        this.prod_desc = prod_desc;
    }

    @Override
    @Column(name="Prod_precio")
    public Double getProd_precio() {
        return prod_precio;
    }

    @Override
    public void setProd_precio(Double prod_precio) {
        this.prod_precio = prod_precio;
    }

    @Override
    @Column(name="Prod_stock_d")
    public Integer getProd_stock_d() {
        return prod_stock_d;
    }

    @Override
   
    public void setProd_stock_d(Integer prod_stock_d) {
        this.prod_stock_d = prod_stock_d;
    }

    @Override
    @Column(name="Prod_stock_a")
    public Integer getProd_stock_a() {
        return prod_stock_a;
    }

    @Override
    public void setProd_stock_a(Integer prod_stock_a) {
        this.prod_stock_a = prod_stock_a;
    }

    @Override
    @Column(name="Prod_fecha")
    public Date getProd_fecha() {
        return prod_fecha;
    }

    @Override
    public void setProd_fecha(Date prod_fecha) {
        this.prod_fecha = prod_fecha;
    }

    @Override
    @Column(name="Categoria")
    public ICategoriaDTO getCategoria() {
        return categoria;
    }

    @Override
    public void setCategoria(ICategoriaDTO categoria) {
        this.categoria = categoria;
    }
    @Override
    public int compareTo(IProductoDTO o) {
        return this.getProd_id().compareTo(o.getProd_id());
    }

    @Override
    public int hashCode() {
        return this.getProd_id().hashCode()*31;
    }

    @Override
    public boolean equals(Object obj) {
        boolean r = false;
        if(obj instanceof IProductoDTO)
        {
           IProductoDTO iproductocens = (IProductoDTO)obj;
           r=this.getProd_id().equals(iproductocens.getProd_id());
        }
        return r;
    }

    @Override
    public String toString() {
        return "ProductoDTO{" + "prod_id=" + prod_id + ", prod_desc=" + prod_desc + ", prod_precio=" + prod_precio + ", prod_stock_d=" + prod_stock_d + ", prod_stock_a=" + prod_stock_a + ", prod_fecha=" + prod_fecha + ", categoria=" + categoria + '}';
    }

   
   
   
   
}

    for( Method m : ProductoDTO.class.getMethods() ) {
                 
                if (m.isAnnotationPresent(Column.class) ) {
                if (m.getName().startsWith("get")) {
                 
             
                System.out.printf("Metodo %s, nombre: %s%n", m.getName(), m.getAnnotation(Column.class).name());
               
                }
                }
        }
           
           

Super! No mas copy/paste! No

Super! No mas copy/paste!

No necesitas validar si empieza con get, si lo anotaste con @Column deberia de bastar. La clase sera un parametro:

public TableModel  createTableModel( Class clazz ) {
    for( Method m : clazz.getMethods() ) {
          if ( m.isAnnotationPresent(Column.class)) {
               ...
         }
    }
}

ok vale

si la validacion del get se me fue por el testing y seguimiento que hago a tu codigo, en un principio comentas "es recomendable es hacer esta introspección solamente una vez" eso como se logra??

Almacenas la lista de creas

TLDR; la pones en una variable.

Es decir, almacenas la información en una clase / estructura de datos y la guardas como variable para no preguntarla cada vez que ejecutas el metodo de tu tablemodel que puede ser cientos de veces.

Ejemplo en vez de escribir algo como:

// NO HACER ESTO
class BeanTableModel extends TableAdapter {
....
    @Override
    String getColumnName( int index ) {
          // introspectar cada vez que este metodo es invocado
         for ( Method m : listOfObjects.get(0).getClass().getMethods() ) {
                if is annotated blabalablab
         }
...
}

Lo almacenas en tu nueva clase:

// Esto si
class BeanTableModel extends TableAdapter {
     private BeanMetaData beanMetaDataByIntrospectingAnnotationsBablabla = createWith..... ;
     @Override
     String getColumnName( int index ) {
         return beanMetaDataByIntrospectingAnnotationsBablabla.getColumnName(index);
     }
}

Y tu clase la inicializas cuando construyas el modelo al recibir la lista de objetos solamente.

ok perfecto

solo me queda una duda ya obtengo los metodos, pero si quisiera invocarlos?
ya voy y se que metodos y atributos tiene mi clase ahora para usarlos?? no se me ocurre para generar un excel

 for( Method m : ProductoDTO.class.getMethods() ) {
                 
                if (m.isAnnotationPresent(Column.class) )
                {
           
                 
                  Row row = sheet.createRow(rownum++);
                  int cellnum = 0;
                  Cell cell = row.createCell(cellnum++);
                  cell.setCellValue( m.getName());
       
           
               
               
                }
        }

Excel? No era un

Excel? No era un tablemodel?

Lo que tienes que hacer es llamar el método invoke

m.invoke( object );

Buscar los métodos cada vez impacta el desempeño, pero invocarlos es casi lo mismo que codificarlos directamente.

En el primer post esta un link donde viene mas información sobre la invocacion de metodos.

si e sun table model

solo que estaba armando un excel aqui que necesito y dejarlo generico para cualquier clase

List de diferente tipo dato

como hago para que mi funcion pueda recibir como parametro una lista que puede ser de diferente tipo dato List o list????

funcion para genenerar excel

lo que intente aqui es que sin importar de que tipo sea mi arrayList lo pudiera exportar a un excel:
problemas que tengo:
*la lista contiene una clase que tienen tipo de dato creado por mi, el me genera el excel pero no se decirle
de forma generica que si hay un tipo de dato compuesto me lo instancie y pueda usar sus metodos

private void tableToExcel() throws IllegalAccessException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException
        {
               HSSFWorkbook workbook = new HSSFWorkbook();
              HSSFSheet sheet = workbook.createSheet(""+listaDatosForTable.get(0).getClass().getSimpleName());
     
              int rownum = 1;
             
             
             
              int cellnum;  
              for(int i=0; i<listaDatosForTable.size();i++)
              {
              cellnum = 0;  
              Row row = sheet.createRow(rownum++);
              for( Method m : listaDatosForTable.get(i).getClass().getMethods())
              {
                 
                if (m.isAnnotationPresent(Column.class) )
                {
                    System.out.println("metodos:"+m.getName());
                   
                    Method me = listaDatosForTable.get(i).getClass().getMethod(m.getName());
                    Object value = m.invoke(listaDatosForTable.get(i), new Object[0]);
                    Cell cell = row.createCell(cellnum++);
                    System.out.println("aja:"+value);
                     if (value != null) {
                             //aunque puedo obtener que que tipo de dato son las funciones  me toco a mano, y si mi value tipo un tipo de dato compuesto no se como castiarlo para que quede de forma generica.
                                        if (value instanceof String) {
                                                cell.setCellValue((String) value);
                                        } else if (value instanceof Long) {
                                                cell.setCellValue((Long) value);
                                        } else if (value instanceof Integer) {
                                                cell.setCellValue((Integer) value);
                                        } else if (value instanceof Double) {
                                                cell.setCellValue((Double) value);
                                        }

                                       

                                       
                                       
                                         else if (value instanceof Date) {
                                                HSSFCellStyle cellStyle = workbook.createCellStyle();
                                                HSSFDataFormat df =  workbook.createDataFormat();
                                                cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy"));
                                                cell.setCellValue((Date) value);
                                                cell.setCellStyle(cellStyle);
                                        }
                                     
                                }
                 
             
                    }
                   
                 }
       
              }
           
           
           
           
           
       
 
try {
    FileOutputStream out =
            new FileOutputStream(new File("C:\\new.xls"));
    workbook.write(out);
    out.close();
   
     
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}