segunda-feira, 27 de outubro de 2014

Primeiros passinhos - Reflection em Java

A proposta hoje aqui será mostrar um exemplo básico com reflection. Quem espera encontrar algo super complexo, irá se decepcionar. Como o nome do post já diz "Primeiros passinhos - Reflection em Java" e não "Últimos passos - Domine o Reflection".

É importante ressaltar que para um entendimento pleno do post é necessário que você, caro leitor, tenha conhecimentos básicos de java e OO.

Adianto para os desesperados de plantão que é possível baixar o projeto pronto, clicando aqui.

Vamos começar então !!!

O que é reflection ? Para que serve ? Como uso ?

Todas essas perguntas serão respondidas. Reflection, em português reflexão, consiste na técnica de através de uma representação compilada de sua classe (.class), ter total acesso à ela. Quando digo total acesso, quero dizer que com o .class em mãos, é possível invocar métodos, acessar atributos e annotations, inspecionar classes e interfaces, entre outras coisas e, tudo isso em tempo de execução.

Agora você pensa: "Mas cara, ninguém usa isso !!!!"

Então eu respondo: "Você está enganado, caro leitor. Isto é usado sim e é usado por diversos frameworks. Dentre alguns, posso citar: Hibernate, Struts e Spring MVC"

Nesse momento, você abre os olhos e se pergunta: "Como ????"

Então eu, mais uma vez, respondo: "Quando você usa o Struts ou o Spring MVC e suas tags na JSP, você escreve no atributo name delas algo parecido com isso?

objeto.atributo

É, então meu amigo, não queria te enganar mas, você usa reflection sim e o pior é que você se beneficia dela. Ouso dizer que com a reflection, você atinge o backstage da classe.

Então, agora só falta responder a última pergunta: "Como uso?" Logo, vamos aos nossos exemplos.

1 - Crie a classe Pessoa


1:  package br.com.pkg;  
2:  public class Pessoa {  
3:       private String codigo;  
4:       private String nome;  
5:       private String email;  
6:       public String empresa;  
7:       public String sobrenome;  
8:       public Integer idade;  
9:       public String getNome() {  
10:            return nome;  
11:       }  
12:       public void setNome(String nome) {  
13:            this.nome = nome;  
14:       }  
15:       public String getEmail() {  
16:            return email;  
17:       }  
18:       public void setEmail(String email) {  
19:            this.email = email;  
20:       }  
21:       public String getCodigo() {  
22:            return codigo;  
23:       }  
24:       public void setCodigo(String codigo) {  
25:            this.codigo = codigo;  
26:       }  
27:       public String getSobrenome() {  
28:            return sobrenome;  
29:       }  
30:       public void setSobrenome(String sobrenome) {  
31:            this.sobrenome = sobrenome;  
32:       }  
33:       public String getEmpresa() {  
34:            return empresa;  
35:       }  
36:       public void setEmpresa(String empresa) {  
37:            this.empresa = empresa;  
38:       }  
39:       public void classificar(Integer idade){  
40:            if(idade <= 5){  
41:                 System.out.println("Bebê");  
42:            } else if(idade > 5 && idade <= 11){  
43:                 System.out.println("Criança");  
44:            } else if(idade > 11 && idade <= 14){  
45:                 System.out.println("Pré adolescente");  
46:            } else if(idade > 14 && idade < 18){  
47:                 System.out.println("Adolescente");  
48:            } else if(idade >= 18 ){  
49:                 System.out.println("Adulto");  
50:            }  
51:       }  
52:       public Integer getIdade() {  
53:            return idade;  
54:       }  
55:       public void setIdade(Integer idade) {  
56:            this.idade = idade;  
57:       }  
58:  }  

2 - Crie a classe Principal


1:  package br.com.pkg;  
2:  import java.lang.reflect.Field;  
3:  import java.lang.reflect.InvocationTargetException;  
4:  import java.lang.reflect.Method;  
5:  import java.util.Scanner;  
6:  public class Principal {  
7:       public static void main(String[] args) {  
8:            Principal principal = new Principal();  
9:            Class clazz = Pessoa.class;  
10:            principal.exibirPackage(clazz);  
11:            principal.exibirMetodos(clazz);  
12:            principal.exibirAtributos(clazz);  
13:            Pessoa pessoa = principal.criarPessoa(clazz);  
14:            principal.invocarMetodo(pessoa);  
15:       }  
16:       private void exibirMetodos(Class clazz){  
17:            System.out.println("==== Métodos ====");  
18:            Method[] methods = clazz.getMethods();  
19:            for(Method method : methods){  
20:              System.out.println("Método: " + method.getName());  
21:            }  
22:            System.out.println("\n");  
23:       }  
24:       private void exibirAtributos(Class clazz){  
25:            System.out.println("==== Atributos ====");  
26:            /*só funciona para atributos públicos*/  
27:            Field[] fields = clazz.getFields();  
28:            for(Field f : fields){  
29:                 System.out.println("Atributo: " + f.getName() + " - Tipo: " + f.getType());  
30:            }  
31:            System.out.println("\n");  
32:       }  
33:       private void exibirPackage(Class clazz){  
34:            System.out.println("==== Package ====");  
35:            System.out.println("Package: " + clazz.getPackage().getName() + "\n\n");  
36:       }  
37:       private Pessoa criarPessoa(Class clazz){  
38:            System.out.println("==== Criação de objeto ====");  
39:            Scanner entrada = null;  
40:            Pessoa pessoa = new Pessoa();  
41:            try{  
42:                 entrada = new Scanner(System.in);  
43:                 Field fieldEmpresa= null;  
44:                 Field fieldSobrenome = null;  
45:                 Field fieldIdade = null;  
46:                 try {  
47:                      fieldEmpresa = clazz.getField("empresa");  
48:                      fieldSobrenome = clazz.getField("sobrenome");  
49:                      fieldIdade = clazz.getField("idade");  
50:                 } catch (NoSuchFieldException e) {  
51:                      e.printStackTrace();  
52:                 } catch (SecurityException e) {  
53:                      e.printStackTrace();  
54:                 }  
55:                 System.out.println("Digite o nome da empresa: ");  
56:                 pessoa.setEmpresa(entrada.nextLine());  
57:                 System.out.println("Digite o sobrenome: ");  
58:                 pessoa.setSobrenome(entrada.nextLine());  
59:                 System.out.println("Digite a idade: ");  
60:                 pessoa.setIdade(Integer.valueOf(entrada.nextLine()));  
61:                 try {  
62:                      System.out.println("Exibição dos dados: " + fieldEmpresa.get(pessoa) + ", " + fieldSobrenome.get(pessoa) + ", " + fieldIdade.get(pessoa));  
63:                 } catch (IllegalArgumentException e) {  
64:                      e.printStackTrace();  
65:                 } catch (IllegalAccessException e) {  
66:                      e.printStackTrace();  
67:                 }  
68:            } finally {  
69:                 entrada.close();  
70:            }  
71:            return pessoa;  
72:       }  
73:       private void invocarMetodo(Pessoa pessoa){  
74:            System.out.println("==== Invocação de método ====");  
75:            try {  
76:                 Method metodo = pessoa.getClass().getMethod("classificar", new Class[]{Integer.class});  
77:                 System.out.println("Tipo de retorno do método: " + metodo.getReturnType());  
78:                 System.out.println("Tipo de parâmetros: " + metodo.getParameterTypes());  
79:                 try {  
80:                      metodo.invoke(pessoa, pessoa.getIdade());  
81:                 } catch (IllegalAccessException e) {  
82:                      e.printStackTrace();  
83:                 } catch (IllegalArgumentException e) {  
84:                      e.printStackTrace();  
85:                 } catch (InvocationTargetException e) {  
86:                      e.printStackTrace();  
87:                 }  
88:            } catch (NoSuchMethodException e) {  
89:                 e.printStackTrace();  
90:            } catch (SecurityException e) {  
91:                 e.printStackTrace();  
92:            }  
93:       }  
94:  }  

IMPORTANTE

Acredito que o código está auto-explicativo mas, caso você tenha alguma dúvida, deixe-a nos comentários.

O método getMethods() e o getFields() só recuperam, respectivamente, métodos e atributos públicos. Para acesso a métodos e atributos privados, recomendo que acesse o link abaixo.

http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html

Também é importante notar que caso o método que se esteja tentando acessar é estático, é necessário passar null como primeiro argumento do método invoke. Isto acontece porque como sabemos recursos estáticos não pertencem a instância e sim a própria classe. Esta regra também é aplicada ao acesso a atributos de estáticos.

Abaixo deixo um site, o qual usei como guia para este post. Recomendo-o pois, o material escrito nele está muito bom.

http://tutorials.jenkov.com/java-reflection/index.html

Dúvidas, sugestões ou assuntos ? Deixe-os aí embaixo.

Nenhum comentário: