¡Amo esta pregunta! Principalmente porque casi nunca se responde o se responde mal. Es como si nadie lo hubiera descubierto todavía. Territorio virgen :)
En primer lugar, ni siquiera pienses en usarlo equals
. El contrato de equals
, como se define en el javadoc, es una relación de equivalencia (reflexiva, simétrica y transitiva), no una relación de igualdad. Para eso, también tendría que ser antisimétrico. La única implementación de equals
eso es (o podría ser) una verdadera relación de igualdad es la que se encuentra en java.lang.Object
. Incluso si solía equals
comparar todo en el gráfico, el riesgo de romper el contrato es bastante alto. Como señaló Josh Bloch en Effective Java , el contrato de iguales es muy fácil de romper:
"Simplemente no hay forma de extender una clase instanciable y agregar un aspecto mientras se preserva el contrato de igualdad"
Además, ¿de qué te sirve realmente un método booleano? Sería bueno encapsular todas las diferencias entre el original y el clon, ¿no crees? Además, asumiré aquí que no quiere preocuparse por escribir / mantener el código de comparación para cada objeto en el gráfico, sino que está buscando algo que se adapte a la fuente a medida que cambia con el tiempo.
Entonces, lo que realmente quieres es algún tipo de herramienta de comparación de estados. La forma en que se implementa esa herramienta depende realmente de la naturaleza de su modelo de dominio y sus restricciones de rendimiento. En mi experiencia, no existe una fórmula mágica genérica. Y será lento en una gran cantidad de iteraciones. Pero para probar la integridad de una operación de clonación, funcionará bastante bien. Sus dos mejores opciones son la serialización y la reflexión.
Algunos problemas que encontrará:
- Orden de colección: ¿Dos colecciones deben considerarse similares si contienen los mismos objetos, pero en un orden diferente?
- ¿Qué campos ignorar: transitorio? ¿Estático?
- Equivalencia de tipos: ¿Deberían los valores de campo ser exactamente del mismo tipo? ¿O está bien que uno extienda el otro?
- Hay más, pero me olvido ...
XStream es bastante rápido y combinado con XMLUnit hará el trabajo en solo unas pocas líneas de código. XMLUnit es bueno porque puede informar todas las diferencias, o simplemente detenerse en la primera que encuentre. Y su salida incluye el xpath a los diferentes nodos, lo cual es bueno. De forma predeterminada, no permite colecciones desordenadas, pero se puede configurar para que lo haga. La inyección de un controlador de diferencias especial (denominado a DifferenceListener
) le permite especificar la forma en que desea tratar las diferencias, incluido el ignorar el orden. Sin embargo, tan pronto como quiera hacer algo más allá de la personalización más simple, se vuelve difícil escribir y los detalles tienden a estar ligados a un objeto de dominio específico.
Mi preferencia personal es usar la reflexión para recorrer todos los campos declarados y profundizar en cada uno, rastreando las diferencias a medida que avanzo. Advertencia: no utilice la recursividad a menos que le gusten las excepciones de desbordamiento de pila. Mantenga las cosas dentro del alcance con una pila (use unLinkedList
o algo). Por lo general, ignoro los campos estáticos y transitorios, y omito pares de objetos que ya he comparado, por lo que no termino en bucles infinitos si alguien decide escribir código autorreferencial (sin embargo, siempre comparo envoltorios primitivos sin importar qué , ya que las mismas referencias de objeto a menudo se reutilizan). Puede configurar las cosas por adelantado para ignorar el orden de la colección y para ignorar tipos o campos especiales, pero me gusta definir mis políticas de comparación de estado en los campos mismos a través de anotaciones. Esto, en mi humilde opinión, es exactamente para lo que estaban destinadas las anotaciones, para hacer que los metadatos sobre la clase estén disponibles en tiempo de ejecución. Algo como:
@StatePolicy(unordered=true, ignore=false, exactTypesOnly=true)
private List<StringyThing> _mylist;
Creo que este es un problema realmente difícil, ¡pero totalmente solucionable! Y una vez que tenga algo que funcione para usted, es realmente muy útil :)
Buena suerte. Y si se te ocurre algo que es pura genialidad, ¡no olvides compartirlo!