Tempo de leitura: menos de 1 minuto
Fala galera, tudo certo por aí?
Vocês já usaram proxy em suas aplicações?
Proxy é um recurso muito útil contido no pacote Javassist (javassist.util.proxy). A definição para Javassist no Wikipédia é a seguinte:
Javassist (Java programming assistant) é uma biblioteca Java que fornece um meio para manipular o bytecode Java de um aplicativo. Nesse sentido, o Javassist fornece o suporte para a reflexão estrutural, isto é, a capacidade de mudar a implementação de uma classe em tempo de execução.
….
Mas por que usar Proxy em minha aplicação?
No projeto que trabalho temos o seguinte cenário:
Um tela (formulário) qualquer, quando submetida, sempre retorna um mapa, onde a chave é o nome do campo e o valor é valor digitado pelo usuário. Para persistir, usamos o Hibernate, por tanto, precisamos transformar este mapa em um objeto. No entanto quando o registro é enviado para deleção, para usar as facilidades do Hibernate, é necessário enviar o objeto, não apenas o id do objeto (session.delete(Object)).
Para a operação de delete, usamos um proxy do objeto, ou seja, não precisamos transformar o mapa em objeto, simplesmente “vestimos” o mapa para ele se parecer com o objeto.
Mas como criamos este proxy?
Basicamente é necessário implementar a interface javassist.util.proxy.MethodHandler. Esta interface possui o método invoke, que é responsável por responder qualquer chamada a métodos públicos do seu objeto fake (proxy). Vejamos a implementação abaixo:
https://gist.github.com/edermfl/255078145e1c8686ba9e199775d02a4d
Note que o construtor da classe ProxyMapHandler (linha 5) recebe por parâmetro o mapa que contém os dados da tela, e quando qualquer método “get” do objeto é chamado, o proxy retornará um do valor deste mapa.
Já método invoke (linha 9) recebe 4 parâmetros, sendo:
- self – objeto proxy ;
- thisMethod – metadado do método da classe “proxyada” (refere-se ao método da classe que criamos o proxy)
- proceed – metadado do método do proxy (não é o metadado do objeto de verdade);
- args – parâmetros que o método está recebendo.
Neste método é possível manipular o objeto, respondendo o valor que quisermos. No exemplo, descobrimos na linha 11 o nome da propriedade, através do metadado do método chamado (thisMethod), ou seja, se o método chamado no objeto for o “getNomeEmpresa”, o nome da propriedade será “nomeEmpresa”.
Já na linha 12, usamos o nome da propriedade para retornar ao solicitante a informação que está no mapa.
Neste exemplo, os parâmetros self, proceed e args não são usados, pois não fazem sentido ao propósito, que é apena responder as chamada do métodos “get”. Mas vejamos outro exemplo de método invoke:
https://gist.github.com/edermfl/3c0129ed7d11a27b65e1531e8c2c84ad
Neste exemplo, foi criado um proxy, para “mokar” alguns atributos do FacesContext e/ou HttpSession.
Alguns método como addMessage, getMessages e getExternalContext do FaceContext não são sobrescritas no proxy, o mesmo acontece se o objeto for do tipo HttpSession, neste caso os métodos sobrescritos são: getAttribute e setAttribute.
Repare que neste exemplo, estamos usando também os parâmetros self e args além do thisMethod.
Mas apenas o handler não é suficiente para criarmos um proxy, para isso usamos a classe javassist.util.proxy.ProxyFactory. Vejamos um exemplo:
https://gist.github.com/edermfl/d00b53c911ad16d7897bbf06c9de9575
Este método recebe a classe do objeto e o mapa que será usado para responder aos “gets”. Na linha 2, o ProxyFactory é instanciado. Entre as linhas 3 e 7, a factory é configurada com o tipo de objeto que do proxy (o retorno do este método propriamente dito), se a classe for uma Interface, a mesma é adicionada no método setInterfaces, se não será adicionada no método setSuperclass.
Na linha 10, o método create() da factory é acionado, é aí que o handle é registrado. Se tudo der certo, o proxy para a classe informada, é retornado na linha 14.
Pronto, basta agora usar o proxy:
https://gist.github.com/edermfl/537900006ce0806a9d0c827b574899e9
É isso aí pessoal!