terça-feira, 7 de janeiro de 2014

GenericTableModel com Reflection e Annotation


GenericTableModel com Reflection e Annotations

Vou falar um pouco sobre TableModel, Reflection e Annotation.

O que é o TableModel? 
A maioria dos componentes swing possuem uma arquitetura que separa model e view, de forma que é definida uma interface para cada model. Dentro deste contexto, TableModel é a interface que representa o model da JTable. Se não informarmos qual será o model, a JTable usará por padrão uma instância de DefaultTableModel.

Ai que muitas discussões ocorrem. A quem diga para nunca usar DefaultTableModel, alguns já garantiram a sua morte, mas como poucos tirariam tempo para desenvolver o seu TableModel muitos o utilizam e não veem problema nisso. Mas uma coisa é certa, a complexidade de manter um DefaultTableModel é grande. 

Segundo VinnyGodoy, moderador do maior forum java do Brasil(www.guj.com.br), esses seriam os argumentos para não usar esse modelo.

Não use DefaultTableModel!!!!
Motivos:
1. É mais difícil que escrever seu próprio TableModel;
2. É mais lento (usa classes sincronizadas);
3. Ocupa mais espaço em memória (duplica seus dados);
4. Deixa o código mais confuso e difícil de manter;
5. Usa casts inseguros;
6. Força que você tenha que exibir informações desnecessárias (como o ID) na tabela, ou controlar o ID numa lista separada;
7. Faz a sua mulher te deixar, o leite da sua geladeira azedar, e pessoas apontarem o dedo para você na rua;


Por que a JTable precisa de um TableModel?
A JTable chama os métodos do TableModel para obter informações sobre o conteúdo da tabela, como número de linhas e colunas, conteúdo de cada célula, etc.

Qual o papel da classe AbstractTableModel? 
AbstractTableModel é uma classe abstrata que oferece a implementação de alguns métodos da interface TableModel, além de um conjunto de métodos úteis. Portanto o usual é estender esta classe ao invés de implementar TableModel diretamente.

Ok, entendi. Tenho que Criar meu próprio TableModel extendendo a classe AbstractTableModel e cumprindo o contrato sobrescrevendo seus métodos. Mas a onde entra Reflection nisso?

Bom, se você assim como eu, também não tinha ideia de o que era Reflection e como ela funciona, posso garantir, e mais fácil do que parece.

Por que Reflection? 
Java permite que, enquanto escrevemos nosso código, tenhamos total controle sobre exatamente o que vai ser executado, o que faz parte do nosso sistema.
Em tempo de desenvolvimento, olhando nosso código, sabemos quantos atributos uma classe tem, quais métodos ela tem, qual chamada de método está sendo feita e assim por diante.
O que a reflection faz é isso. Olhar para dentro de nossa classe e descobrir seu conteúdo.

O ponto de partida de reflection é a classe "Class".
Através dela conseguimos obter informações como os atributos dela, os métodos, os construtores etc.

Reflection é um pacote do Java que permite chamadas dinâmicas em tempo de execução sem precisar conhecer as classes e objetos envolvidos quando escrevemos nosso código (tempo de compilação).

É ideal para resolvermos determinadas coisas que nosso programa só descobre quando realmente estiver o rodando.

Neste caso, ao criar uma GenericTableModel, ela deve estar pronta a receber qualquer list("Genérico, não?") como parâmetro e mostrar a partir de uma jTable seus dados contidos.
O TableModel não sabe que atributos tem esse list, mas através de reflection, ela consegue "descobrir" esses campos e gerar a jTable.

É possível fazer muitas coisas usando reflection. Apenas para citar algumas possibilidades:
* Listar todos os atributos de uma classe e pegar seus valores em um objeto específico;
* Instanciar classes cujo nome só vamos conhecer em tempo de execução;
* Invocar métodos dinamicamente baseado no nome do método como String;
* Descobrir se determinados pedaços do código foram anotados com as anotações do Java 5.

Ex:
public class Pessoa {
 private String nome;
 private String email;
 private int idade;
 // Getters, setters, métodos de pessoa...
}

Class classe = Pessoa.class;
for (Field field : classe.getDeclaredFields()) {
System.out.println(field.getName());
}

A saída Será:
nome
email
idade

Dessa maneira, posso deixar o TableModel Genérico.
A cada execução, a cada classe distinta, ele descobre seus atributos e age sobre eles da mesma forma. 

Ok. Funcional. Mas e se eu quiser que meu GenericTabelModel não atue sobre todos os atributos, como eu faço para "marcar" um atributo ignorado? Como eu Faço para marcar apenas o Atributo que quero que apareça na jTable?

Bom, e ai que entra as Annotations. 
Não vou explicar o funcionamento de annotation, ja que o colega Bruno Lima, fez um post sobre o seu funcionamento. (@Annotations "metadados" que não interferem diretamente no código anotado) 

Posso criar anotações e usar na minha classe, onde em tempo de execução e de acordo com a annotation criada o programa age da maneira que eu especificar. 

No casso do GenericTableModel trabalhei com as Seguintes Annotations: 
@TableModel - Anotação de classe, atua sobre todos os seus atributos, coloca todos na jTable.
@ColumnIgnore - Anotação de campo. o Atributo que possuir essa anotação, não irá aparecer na jTable.
@Column - Anotação de Campo e Metodos. O atributo que possuir essa anotação vai aparecer na jTable.     * colName() = Pode-se alterar o nome da coluna, 
    * colPosition() = Posição de coluna na jTable 
    * formatt() = formatar um campo, sendo sua saida uma String. 


Funcionamento:
         GenericTableModel tableModel = new GenericTableModel(getData(), 
            Pessoa.class);
 JTable table = new JTable(tableModel);
 JFrame frame = new JFrame("GenericTableModel");
 table.setModel(tableModel);



private List getData() {
List list = new ArrayList();
list.add(new Pessoa("Marcos", "viny_scholl@hotmail.com", 21, "xxxxx", 1000.5));
list.add(new Pessoa("Marco", "tony_scholl@hotmail.com", 21, "bbbbbb", 21.75 ));
list.add(new Pessoa("Felipe", "felipe_scholl@hotmail.com", 27, "qwert", 75.40));
return list;
}

Exemplos de Execução da GenericTableModel com diferentes Annotations.
Ex1:
  
@TableModel(includeAll=true)
public class CopyOfPessoa {
 private String nome;
 private String email;
 @ColumnIgnore
 private int idade;
 private String senha;
 private double saldo;
}
Saída: 

 ----------------------------------------
Ex2:
 
@TableModel(includeAll=true)
public class CopyOfPessoa {
 @ColumnIgnore
 private String nome;
 @ColumnIgnore
 private String email;
 @ColumnIgnore
 private int idade;
 @ColumnIgnore
 private String senha;
 private double saldo;
}
Saída: 

----------------------------------------
Ex3:
 
@TableModel(includeAll=false)
public class CopyOfPessoa {

 private String nome;
 @Column
 private String email;
 private int idade;
 @Column
 private String senha;
 @Column
 private double saldo;
}
Saída: 

---------------------------------------- 
Ex4:
Com a Formatação possivel Pelo @Column
 
@TableModel(includeAll=false)
public class CopyOfPessoa {

 @Column(colName = "Nome", colPosition = 0)
 private String nome;
 @Column(colName = "Email", colPosition = 1)
 private String email;
 @Column(colName = "Idade", colPosition = 4)
 private int idade;
 @Column(colName = "Pass", colPosition = 3)
 private String senha;
 @Column(colName = "Saldo", colPosition = 2, formatter="R$ %,#.2f")
 private double saldo;
}
Saída: 



Assim, posso trabalhar de diferentes formas e com diferentes resultados de saída, a partir de uma unica classe usando Reflection e Annotations. 

Temos uma tabela Dinâmica. Uma GenerictableModel.

Referencias:
http://www.guj.com.br/java/199067-redimensionar-jtable---pra-variar--resolvido-/2#1001295
http://www.guj.com.br/java/149861-recuperar-id-de-jtable/2#813171
http://devsv.wordpress.com/2012/07/08/como-implementar-um-tablemodel/
http://markytechs.wordpress.com/2009/05/29/objecttablemodel/
http://www.guj.com.br/java/231928-morte-definitiva-ao-default-table-model#1399642
Caelum FJ-16 -Laboratório Java com Testes, XML e Design Patterns


Marcos Vinicius Scholl:
Graduando em Tecnologia em Análise e Desenvolvimento de Sistemas - TADS 
Universidade Federal do Rio Grande - FURG 
Instituto Federal de Educação, Ciência e Tecnologia do Rio Grande do Sul IFRS - Campus Rio Grande 
Rua Eng. Alfredo Huch, 475 - Rio Grande, RS - Brasil - 96201-460 

Sobre o autor:
Marcos Vinicius Scholl estuda na área de Tecnologia de Informação. É entusiasta na área de tecnologia. Gremista de paixão e anticolorado por prazer!

Post Sobre armazenamento de objetos em um Cache

o que é um cache?

Nos dias atuais cada vez mais acessamos sites, usamos banco de dados, e nossos proprios

computadores tem grande capacidade de armazenamento de processamento.Com a finalidade

de agilizar essas consultas e processamentos que existe a memoria cache, sendo uma

memoria de acesso muito rapido, que guarda pequenas quantidades de informações, as mais

acessadas por nós, seja em sites, no nosso HD ou ate mesmo um banco de dados.


Tipos mais típicos de cache

Como falado anteriormente, alguns tipos mais tipicos de caches sao:

1-Cache de sites: são caches guardados pelo navegador que usamos, guardam informaçoes

de uma pagina que visitamos na web, para que ao acessa-las novamente nao precisamos

carregar a pagina completamente, e sim informaçoes que foram atualizadas nela, assim

agilzando o processo de carregamento.

2-Cache no processador: uma memoria de alto desenpenho que fica embutida dentro do

processador, é utilizada para que o processador acesse dados mais rapidos, evitando a

busca na memoria ram que é mais lenta.Normalmente utilizada em 3 niveis no processador.
Nivel L1, L2 e alguns processadores chegam a ter o nivel L3.

3- Cache do disco : fica localizada junto ao disco rigido do nosso computador, ela

armazena as ultimas trilhas feita pelo HD assim evitando que a cabeça de leitura e

gravação passe varias vezes pelo mesmo lugar.


Características de um cache:
E uma memoria de velocidade de leitura e escrita muito mais rapido, por isso é

utilizado para armazenar dados que são lidos ou gravados varias vezes.
Possui um tempo de vida, assim nada fica sempre armazenado no cache para sempre.

Sobre meu projeto:

Bom, tendo explicado um pouco sobre memoria cache, vou mostrar um pouco do meu projeto

de cache, mostrando os codigos em java, o projeto tem como finalidade criar um toolkit

que atraves de anotaçoes feitas por quem desenvolve uma classe seja colocado na memoria

ram utilizada pela maquina virtual do java, assim evitando por exemplo o acesso a um

banco de dados utilizado por um sistema.



Alguns Métodos da minha classe cache :

Essa classe manipula o cache, ela possui um objeto cache estatico que só pode ser

instancia dentro dela mesmo, e todos os metodos necessario para adicionar, remover,ou

até mesmo limpar todo o cache.

verifica se uma chave existe :
   
      public  boolean hasKey(String chave){
 boolean chaveExisteNoCache = true;
 if(chaveEhValida(chave)&&temEssaChaveNaListaDeObjetos(chave)) return chaveExisteNoCache;
 return  chaveExisteNoCache=false;
      }


retorna um objeto do cache :
     
 public Object get(String chave){
  
  if(chaveEhValida(chave)==false){
   System.out.println("chave invalida");
   return chave;
  }
  if(temEssaChaveNaListaDeObjetos(chave)==false){
   System.out.println("objeto inexistente na lista");
   return chave;
  }
  
  
  Object objeto = listaObjetosNoCache.get(chave);
  return objeto;
 }

metodo que adiciona um objeto no cache :
/**
    
 public  void add(String chave,Object objeto,int tempo){
  
  if(chaveEhValida(chave) && validaObjeto(objeto)){
   addChaveObjetoNoCache(chave,objeto);
   addChaveParaMonitorar(chave,tempo);
  }
  
  
 }


metodo altera o tempo de um objeto no cache :
public void alteraTempoDoObjeto(String chave,int tempoEmMinutos){
    if(chaveEhValida(chave)&&(temEssaChaveNaListaDeObjetos(chave))){
       long novoTempo = calculaTempoDeDuracaoNoCache(tempoEmMinutos);
       atualizaTempoDaChave(chave, novoTempo);
       System.out.println("tempo alterado da chave para : "+tempoEmMinutos +" minutos");
    }
    else System.out.println("chave invalida ou objeto inexistente no cache ");
}



Devido ao tamanho da classe deixo os outros métodos para outra hora : )

Abaixo sobre a classe da anotação:

Anotação que inclui um objeto no cache feita em cima de um metodo, por meio de uma

interface, é uma anotaçao que deve ser inserida em um metodo de uma interface, que sera

reconhecida pelo metodo proxy utilizado na classe cache.

package cache;

/**
 *Classe utilitaria para anotar metodos que serao inseridos no cache da JVM
 *@author Andrei Garcia (andrei_garcia2@hotmail.com)
 *@since JDK.7
*/


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *Anotação para ser utilizada sobre uma interface ,sendo anotada
 * em cima de um método,metodo o qual sera inserido no cache da JVM seu objeto de 

retorno
 *
 *@author Andrei Garcia
 *@category anotação
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ColocarNoCache {

 int tempo() default 60;


}




Bom era isso, espero que tenham curtido o posto : )





Referencias

http://www.tecmundo.com.br/tira-duvidas/21555
http://pt.wikipedia.org/wiki/Cache

API Google Gson [JAVA SE7] Serializer and Deserializer Object

Neste post vou falar sobre a API Google Gson, desenvolvida pela google e disponibilizada gratuitamente neste link.
Esta API não tem muitos recursos, porém, é de grande importância ressaltar sua utilidade e rápida adaptação.

A Api do google gson, interpreta códigos enviados por arquivos Json ao software desenvolvido em JAVA e deserializa esses códigos para Classes java, instanciando assim: Objetos, classes, etc. Além disso, faz a engenharia reversa, onde recebe um objeto java e retorna um objeto JSON. Enfim, o uso dessa ferramente abre um leque de possibilidades dentro do java ao desenvolvedor, que pode usá-la para o que tiver necessidade em seu software.

Uma dica de uso é combinar esta biblioteca a uma já existente no Java SE7. A biblioteca java.lang.reflect.* na
qual você pode ler mais sobre clicando acima no link destacado.

Aqui irei demonstrar o uso da API para simples atribuição de Objetos, das duas formas.

lembrando que para usar o google Gson é necessário fazer o download da lib no site, e importá-lo no projeto corrente como biblioteca.

Exemplo1: 
    Neste caso, iremos serializar um Objeto Java, para transformá-lo num objeto Json.

Temos a classe Teste()
public class Teste {
    private String teste;
    private int numero;
    
    //+getters
    //+setter
    
    @Override
    public String toString() {
        return "teste = "+teste+" numero = "+numero;        
    }   
}

E temos a classe Principal TesteGson()
public class TesteGson {
    public static void main(String argumentos[]){
        Gson gson = new Gson();  //Instanciamos o uso do Gson
       
        Teste obj = new Teste("Gson", 1); // Criamos um obj do tipo Teste
        String s = gson.toJson(obj); //serializamos o obj
        System.out.println(s); //mostramos a string transformada em Json.
       
    }
   
}

Com este código temos a seguinte saída:
{"teste":"Gson","numero":1}

Exemplo 2:
  Neste exemplo iremos ver como Transformar um objeto Json em um Objeto Java. Vamos instanciar a mesma classe Teste() declarada acima.

Na janela Principal executaremos:
public class TesteGson {
    public static void main(String argumentos[]){
        Gson gson = new Gson();  //Instanciamos o uso do Gson
        
        String s = "{\"teste\":\"objectName\",\"numero\":2}";
        Teste obj = gson.fromJson(s, Teste.class);
        System.out.println(obj.toString());
    }
    
}

Com este código temos a seguinte saída:
teste = objectName numero = 2

Esta foi uma pequena introdução a API Google Gson, para saber mais sobre ela, consulte:
Google Gson 2.2.4 API.

Referências:
Google Gson User Guide.

Autor: Vinicius Montenegro.
    Graduando do Curso de Tecnologia em Análise e Desenvolvimento de Sistemas.
    FURG/IFRS - RIO GRANDE/RS.