Usando Proxy

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.

….

Fonte: https://en.wikipedia.org/wiki/Javassist

javassistMas 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!

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *