terça-feira, 7 de janeiro de 2014

Annotations e Reflection em um ORM

ORM é uma técnica de desenvolvimento utilizada para reduzir a impedância da programação orientada aos objetos utilizando bancos de dados relacionais. As tabelas do banco de dados são representadas através de classes e os registros de cada tabela são representados como instâncias das classes correspondentes.

Para que seja possível o desenvolvimento de uma ferramenta de ORM é necessário um conhecimento de Annotations e de Reflection.
As anotações neste caso são utilizadas para fazer a configuração dos atributos por parte de quem utiliza a ferramenta, fazendo com que a ferramenta interprete essa anotação e se comporte de acordo com a anotação utilizada. Para que seja mais simples entender vamos  ver um exemplo: Supondo que quem está utilizando a ferramenta tenha um objeto Pessoa e dentro dele tem um outro objeto Endereco, os dados desse objeto podem ser salvos tanto em uma tabela endereco ou na própria tabela pessoa,  então cria-se uma anotação para determinar se o endereço dever ser salvo na mesma tabela com os dados das pessoas ou não.
 public class Pessoa {
    @PrimaryKey
    public Integer id;
    public String nome;
    @Embutido
    public Endereco end;
   
                 .
                 .
                 .
}

Como o nosso colega de curso Bruno já fez uma post sobre anotações não irei me extender neste assunto.

Reflection permite um programa Java examinar ou fazer a introspecção nele mesmo, ou seja, olhar e examinar suas propriedades e estrutura. Com isso, você pode, por exemplo obter o nome de todos os membros de uma classe, como atributos e métodos, bem como executar um método usando a Introspection. É deste modo que os aplicativos de ambiente de desenvolvimento (as IDEs) conseguem examinar e exibir a estrutura e conteúdo das classes e beans.
É necessário a utilização desta tecnologia, pois a ferramenta de ORM deve ser genérica para funcionar com qualquer tipo de objeto, com este recurso a ferramenta recebe um objeto como parâmetro sem saber quem é ele e descobre seus atributos e suas configurações através da reflexão,   assim possibilitando o tratamento de cada atributo  de acordo com as suas configurações. Como exemplo vou mostrar uma função que recebe um objeto genérico como parâmetro e descobre qual  atributo é chave primária e o retorna. 

 private Field primaryKey(Object objeto){
  Field[] campos = objeto.getClass().getDeclaredFields();
  for (Field campo : campos) {
   if(campo.isAnnotationPresent(PrimaryKey.class))
   {
    return campo;
   }
  }
  return null;
 }
 
Era wilson pessoal... 

@Annotations "metadados" que não interferem diretamente no código anotado

Muito pensam que a anotação só serve para fazer com que a IDE pare de dar avisos sobre a falta das mesmas, pois são as mais comuns utilizadas por quem programa em java, um exemplo é a @Override que serve para informar ao compilador que o elemento esta sobrescrevendo um outro elemento declarado na superclasse. Mas existem vários tipos de anotações, como as que fornecem informações para o compilador ou as Compiler-time and deployment-time que servem para ser usadas em frameworks que geram códigos como o xml e para realizar validações em campos entre outras, existe também as de runtime que são lidas em tempo de execução.
Mas para que possamos usar as anotações de uma maneira mais abrangente podemos também criar nossas próprias anotações, a regra é a mesma da interface com o detalhe que devemos colocar o "@" antes da palavra "interface".

Exemplo:
public @interface MinhaInterface{

}

Ainda é possível declarar métodos que devem ser obrigatoriamente implementados na anotação, assim como nas interfaces, mas estes métodos não devem possuir quaisquer parâmetros, não devem lançar quaisquer exceções e o tipo de retorno deve ser do tipo primitivo, um String, um Class, um Enum ou ainda um array de um destes tipos.

Exemplo:

public @interface MinhaInterface{

String nome();
String valor();

}


Mas além das annotations existem também as Meta-annotations que servem para definir o comportamento da anotação, são elas: Target, Retention, Documented, Inherited

@Target Indica em qual elemento da classe a anotação pode ser aplicada

@Target(ElementType.TYPE) Pode ser aplicada a qualquer elemento da classe.
@Target(ElementType.FIELD) Pode ser aplicada a um campo ou propriedade.
@Target(ElementType.METHOD) Pode ser aplicada a um método.
@Target(ElementType.PARAMETER) Pode ser aplicada a parâmetros de um método
@Target(ElementType.CONSTRUCTOR) Pode ser aplicada a construtores.
@Target(ElementType.LOCAL_VARIABLE) Pode ser aplicada a variáveis locais.
@Target(ElementType.ANNOTATION_TYPE) Indica que o próprio tipo declarado é uma anotação de anotação.

@Retention Indica onde e quando as anotações deste tipo serão obtidas.

@Retention(RetentionPolicy.SOURCE) Serão obtidas somente em nível de fonte e serão ignoradas pelo compilador.
@Retention(RetentionPolicy.CLASS) Serão obtidas somente em nível de compilação e serão ignoradas pela VM.
@Retention(RetentionPolicy.RUNTIME) Obtidas pela VM e serão lidas apenas em runtime.

@Documented Indica se a anotação pertencerá ao javadoc ou algum outro gerador de documentação por padrão.

@Inherited Indica se a anotação sera herdada pelas subclasses automaticamente, sendo assim, caso haja uma consulta procurando por uma anotação qualquer, se a classe consultada não possuir a anotação a classe pai sera consultada por padrão.

Exemplo:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE
public @interface MinhaInterface{

String nome();
String valor();

}
Exemplo de uso:

@MinhaInterface(nome = "Bruno", valor = "R$ 0,00")
public class Pessoa {

private String nome;
private String telefone;

public Pessoa(){
}
}



Bom pessoal aqui fica um breve post de como usar annotation, qualquer duvida www.google.com

Internacionalização (I18N)


Internationalization ou I18N como é chamado (devido ao fato de desde a primeira letra até a última ter um total de 18 letras entre elas nessa palavra), é um processo de adaptação dinâmica de textos e mensagens em softwares de computadores para uma língua e cultura de um país.
A utilização desse processo é relativamente simples, sendo utilizado essencialmente a classe ResourceBundle para buscar os arquivos de texto de tradução (que é usado na extensão .properties) e a classe Locale para definir o idioma que será traduzido.

Nesse post, irei mostrar um pouco sobre o seu funcionamento utilizando a linguagem de programação Java.

Para começar, vamos ver como funciona o arquivo properties. Ele nada mais é do que um arquivo de texto que irá conter as palavras (ou chaves) e suas traduções correspondentes salvado com a extensão .properties. Considere um arquivo properties contendo as seguintes palavras, na exata forma escrita:

                                                nome = Name
                                                end = Address

nesse caso, quando buscarmos pela chave "nome" passando como parâmetro no método getString da classe ResourceBundle, vamos obter a palavra "Name" e quando buscarmos por "end", vamos obter "Address" de dentro do nosso arquivo properties.


Agora que já vimos como exatamente é o arquivo properties, vamos ver um exemplo simples de utilização do I18N traduzindo a palavra "cadastro" para o inglês.

O primeiro passo a ser dado é criar o arquivo properties com a palavra "cadastro" seguido de sua tradução em inglês, logo ficaria assim:

                                               cadastro = Register

depois, devemos criar objetos do tipo ResourceBundle e Locale.


 public class I18nExemplo{
  
  public static void main(String[] args){
   Locale locale;
   ResourceBundle palavra;
  }
 }
  

A seguir, temos que definir no objeto locale o idioma a ser usado, inserindo como parâmetro a identificação do país e idioma entre aspas. No nosso caso, "en" e "US" (já que queremos traduzir para o inglês).

  locale = new Locale("en", "US");
  

O próximo passo então é atribuir ao objeto "palavra" a localização do arquivo .properties que vamos utilizar para traduzi-la para o ingles, utilizando o método getBundle da classe ResourceBundle e recebendo como parâmetros o arquivo properties de tradução e a váriavel do tipo locale.

Vamos supor que temos um pacote chamado "properties", e nele colocamos nosso arquivo de tradução para o ingles que se chama "ingles_en_US.properties". Então nosso código ficaria assim:

     palavra = ResourceBundle.getBundle("properties.ingles_en_US", locale);
  

Agora, usamos o método getString da classe ResourceBundle no objeto "palavra", passando como parâmetro a chave do arquivo properties
que vamos traduzir, que é "cadastro" nesse caso.
Se colocarmos isso dentro de um System.out.println() ou de uma janela já vamos obter a palavra traduzida.

    System.out.println(palavra.getString(cadastro)); //Register
  

Como pode perceber, não é difícil utilizar o I18N.
I18N ainda tem várias outras formas de utilização para horário, unidade monetária e etc.
Se interessou? dê mais uma lida sobre o assunto nesse link da Oracle:

http://docs.oracle.com/javase/tutorial/i18n/TOC.html