Eu amo essa pergunta! Principalmente porque quase nunca é respondida ou mal respondida. É como se ninguém ainda tivesse descoberto. Território virgem :)
Primeiro, nem pense em usar equals
. O contrato deequals
, conforme definido no javadoc, é uma relação de equivalência (reflexiva, simétrica e transitiva), não uma relação de igualdade. Para isso, também teria que ser anti-simétrico. A única implementação equals
disso é (ou poderia ser) uma verdadeira relação de igualdade em java.lang.Object
. Mesmo que você use equals
para comparar tudo no gráfico, o risco de quebra do contrato é bem alto. Como Josh Bloch apontou em Effective Java , o contrato de iguais é muito fácil de quebrar:
"Simplesmente não há maneira de estender uma classe instanciável e adicionar um aspecto preservando o contrato de igual"
Além do mais, de que serve um método booleano? Seria bom encapsular todas as diferenças entre o original e o clone, você não acha? Além disso, assumirei aqui que você não quer se incomodar em escrever / manter código de comparação para cada objeto no gráfico, mas em vez disso, está procurando por algo que será escalado com a origem à medida que ela muda com o tempo.
Entããão, o que você realmente quer é algum tipo de ferramenta de comparação de estado. A forma como essa ferramenta é implementada realmente depende da natureza de seu modelo de domínio e de suas restrições de desempenho. Na minha experiência, não existe uma fórmula mágica genérica. E será lento em um grande número de iterações. Mas para testar a integridade de uma operação de clone, ele fará o trabalho muito bem. Suas duas melhores opções são serialização e reflexão.
Alguns problemas que você encontrará:
- Ordem da coleção: duas coleções devem ser consideradas semelhantes se contiverem os mesmos objetos, mas em uma ordem diferente?
- Quais campos devem ser ignorados: Transitório? Estático?
- Equivalência de tipo: os valores dos campos devem ser exatamente do mesmo tipo? Ou será que um pode estender o outro?
- Tem mais, mas eu esqueço ...
XStream é muito rápido e combinado com XMLUnit fará o trabalho em apenas algumas linhas de código. XMLUnit é bom porque pode relatar todas as diferenças, ou apenas parar na primeira que encontrar. E sua saída inclui o xpath para os nós diferentes, o que é bom. Por padrão, ele não permite coleções não ordenadas, mas pode ser configurado para isso. Injetando um manipulador de diferença especial (chamado deDifferenceListener
) permite que você especifique a maneira como deseja lidar com as diferenças, incluindo ignorar a ordem. No entanto, assim que você deseja fazer algo além da personalização mais simples, torna-se difícil escrever e os detalhes tendem a ser vinculados a um objeto de domínio específico.
Minha preferência pessoal é usar reflexão para percorrer todos os campos declarados e detalhar cada um, rastreando as diferenças conforme eu prossigo. Aviso: não use recursão, a menos que goste de exceções de estouro de pilha. Mantenha as coisas dentro do escopo com uma pilha (use umLinkedList
ou alguma coisa). Eu geralmente ignoro os campos transientes e estáticos, e pulo os pares de objetos que já comparei, então não acabo em loops infinitos se alguém decidir escrever código auto-referencial (No entanto, eu sempre comparo wrappers primitivos, não importa o que , uma vez que os mesmos refs de objeto são frequentemente reutilizados). Você pode configurar as coisas com antecedência para ignorar a ordem da coleção e para ignorar tipos ou campos especiais, mas eu gosto de definir minhas políticas de comparação de estado nos próprios campos por meio de anotações. Isso, IMHO, é exatamente para o que as anotações foram feitas, para disponibilizar metadados sobre a classe em tempo de execução. Algo como:
@StatePolicy(unordered=true, ignore=false, exactTypesOnly=true)
private List<StringyThing> _mylist;
Acho que esse é um problema realmente difícil, mas totalmente solucionável! E quando você tem algo que funciona para você, é muito, muito útil :)
Então boa sorte. E se você vier com algo que é pura genialidade, não se esqueça de compartilhar!