Tenho uma funcionalidade que deve comparar dois objetos e retornar uma lista com as propriedades que foram alteradas. Por exemplo, dado dois clientes:
Cliente c1 = new Cliente();
c1.setId(1L);
c1.setTelefone(“xxxxx-xxxx”);
c1.nome(“c1”);
Cliente c2 = new Cliente();
c1.setId(1L);
c1.setTelefone(“xsxxx-xxxx”);
c1.nome(“c1”);
Ao comparar c1 com c2, o resultado desejado é uma lista ou mapa contendo o atributo telefone, uma vez que este é o único atributo diferente entre os objetos comparados.
Existe alguma forma menos traumática de se fazer isso, levando em consideração que os dois objetos sempre serão do mesmo tipo direto?
Eu optaria por um map.
Forma menos traumática? Não me recordo de nenhuma API ou ferramenta que retorne os atributos alterados de um objeto em comparação a outro.
Então, só depois que eu respondi é que pensei que poderia usar algo assim.
Você pode pegar os métodos de uma das instâncias, invocar ambos e verificar se há diferença, havendo, faz um put no mapa inserindo o que foi alterado (talves um map de String (nome do atributo) e value como String[] (contendo o de e o para)).
Há algum tempo atrás eu tive uma necessidade parecida.
Utilizei o padrão Memento para isso, basicamente criei um método saveState() que retornava uma instância correspondente ao estado do objeto naquele momento, como se fosse uma “fotografia”.
Depois que o objeto era alterado, eu conseguia comparar ele com esse objeto “fotografado”.
Utilizei reflection para percorrer a hierarquia da classe e seus atributos.
A abordagem que comecei a fazer está muito próximo dessa sua. Não conhecia o padrão Memento. Vou dar uma lida a respeito.
Meu cenário consiste em ter uma entidade “original” do tipo Peticao persistida no BD e suas alterações gravadas num XML, onde, por regra de negócio, toda a alteração que eu faço numa petição que já foi homologada deve gerar um XML cópia completo (espelho). Na minha comparação eu converto esse XML numa entidade Peticao e entro no processo de verificação dos atributos alterados.
A diferença é que numa estrutura mais complexa onde Peticao HAS-A outra entidade válida, não preciso percorrer tooooda a árvore aninhada de entidades, somente o que de fato me importa. Para isso, criei uma anotação de marcação pra os campos que devem ser verificados nesse processo, deixando o que não estiver anotado num estado transiente de validação.
@staroski, vc chegou a enfrentar propriedades que geram a mesma chave de alteração? Por exemplo, uma petição tem uma lista de apresentações, onde cada apresentação possui um atributo de concentração, por exemplo. Se duas ou mais apresentações tiverem esse atributo modificado, será mantido somente o último valor inserido no mapa de alteração. Chegou a lidar com esse problema?
No meu caso eu não tinha esse tipo de problema pois minha necessidade era somente restaurar o estado do objeto tal qual era antes da alteração. Tipo um Ctrl+Z.
De repente tu pode usar orientação à aspecto e antes de cada setter executado em seu objeto, empilhar um snapshot do estado dele naquele momento.
É só uma ideia, não sei se é viável pra ti incluir um framework tipo Aspect J pra fazer isso.
De repente é mais fácil você fazer um decorator para tua classe e esse decorator se encarregar de empilhar o estado do objeto antes de cada setter ser invocado.
static List comparar(c1, c2) {
List resultado;
if (c1.getId() != c2.getId()) {
resultado.add("id")
}
/* ... os outros atributos ... */
return resultado;
}
ou então usando atributos que verificam se foi atualizado:
Se precisar de todos os valores, troque o atributo atualizado por um List funcionando como um decorador que o @staroski sugeriu ou se só precisa saber a qtd de vezes que foi atualizado, por um int.
Não se aplica, pois faço o parser do XML para uma entidade com estrutura complexa válida. No mais, eu preciso comparar o objeto “parseado” com a entidade original.
Estou fazendo com reflection mesmo. Não teve jeito de fugir…rs