Gibt es eine Java-Dienstprogrammbibliothek, die dem Unix-Programm diff entspricht, jedoch für Objekte? Ich suche nach etwas, das zwei Objekte desselben Typs vergleichen und eine Datenstruktur generieren kann, die die Unterschiede zwischen ihnen darstellt (und Unterschiede in Instanzvariablen rekursiv vergleichen kann). Ich suche keine Java-Implementierung eines Textdiff. Ich suche auch keine Hilfe bei der Verwendung von Reflexion, um dies zu tun.
Die Anwendung, die ich pflege, hat eine fragile Implementierung dieser Funktionalität, die einige schlechte Designentscheidungen hatte und die neu geschrieben werden muss, aber es wäre noch besser, wenn wir etwas von der Stange verwenden könnten.
Hier ist ein Beispiel für die Art von Dingen, nach denen ich suche:
SomeClass a = new SomeClass();
SomeClass b = new SomeClass();
a.setProp1("A");
a.setProp2("X");
b.setProp1("B");
b.setProp2("X");
DiffDataStructure diff = OffTheShelfUtility.diff(a, b); // magical recursive comparison happens here
Nach dem Vergleich würde mir das Dienstprogramm sagen, dass "prop1" zwischen den beiden Objekten unterschiedlich ist und "prop2" gleich ist. Ich denke, es ist für DiffDataStructure am natürlichsten, ein Baum zu sein, aber ich werde nicht wählerisch sein, wenn der Code zuverlässig ist.
Antworten:
Könnte etwas spät sein, aber ich war in der gleichen Situation wie Sie und habe am Ende meine eigene Bibliothek für genau Ihren Anwendungsfall erstellt. Da ich gezwungen war, selbst eine Lösung zu finden, beschloss ich, sie auf Github zu veröffentlichen, um anderen die harte Arbeit zu ersparen. Sie finden es hier: https://github.com/SQiShER/java-object-diff
--- Bearbeiten ---
Hier ist ein kleines Anwendungsbeispiel basierend auf dem OP-Code:
SomeClass a = new SomeClass(); SomeClass b = new SomeClass(); a.setProp1("A"); a.setProp2("X"); b.setProp1("B"); b.setProp2("X"); DiffNode diff = ObjectDifferBuilder.buildDefault().compare(a, b); assert diff.hasChanges(); assert diff.childCount() == 1; assert diff.getChild('prop1').getState() == DiffNode.State.CHANGED;
quelle
http://javers.org ist eine Bibliothek, die genau das tut, was Sie brauchen: Methoden wie compare (Object leftGraph, Object rightGraph) geben das Diff-Objekt zurück. Diff enthält eine Liste von Änderungen (ReferenceChange, ValueChange, PropertyChange), z
given: DummyUser user = dummyUser("id").withSex(FEMALE).build(); DummyUser user2 = dummyUser("id").withSex(MALE).build(); Javers javers = JaversTestBuilder.newInstance() when: Diff diff = javers.compare(user, user2) then: diff.changes.size() == 1 ValueChange change = diff.changes[0] change.leftValue == FEMALE change.rightValue == MALE
Es kann Zyklen in Diagrammen verarbeiten.
Außerdem können Sie einen Schnappschuss von jedem Diagrammobjekt erhalten. Javers verfügt über JSON-Serializer und Deserializer für Snapshots und Änderungen, sodass Sie diese problemlos in der Datenbank speichern können. Mit dieser Bibliothek können Sie einfach ein Modul für die Überwachung implementieren.
quelle
Ja, die Java-Util- Bibliothek verfügt über eine GraphComparator-Klasse, die zwei Java-Objektdiagramme vergleicht. Die Differenz wird als Liste der Deltas zurückgegeben. Mit dem GraphComparator können Sie auch die Deltas zusammenführen (anwenden). Dieser Code hat nur Abhängigkeiten vom JDK, keine anderen Bibliotheken.
quelle
Die gesamte Javers-Bibliothek unterstützt nur Java 7, ich war in einer Situation, da ich möchte, dass dies für ein Java 6-Projekt verwendet wird, also habe ich zufällig die Quelle genommen und geändert, so wie es für Java 6 funktioniert. Unten ist der Github-Code .
https://github.com/sand3sh/javers-forJava6
Jar Link: https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar
Ich habe nur die von Java 7 unterstützten '<>' inhärenten Cast-Konvertierungen in Java 6-Unterstützung geändert. Ich kann nicht garantieren, dass alle Funktionen funktionieren, da ich nur wenige unnötige Codes für mich kommentiert habe, die für den Vergleich aller benutzerdefinierten Objekte funktionieren.
quelle
Sie können sich auch die Lösung von Apache ansehen. Die meisten Projekte haben es bereits auf ihrem Klassenpfad, da es Teil von commons-lang ist.
Überprüfen Sie den Unterschied für bestimmte Felder:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/DiffBuilder.html
Überprüfen Sie den Unterschied mithilfe von Reflection:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/ReflectionDiffBuilder.html
quelle
Je nachdem, wo Sie diesen Code verwenden, kann dies möglicherweise hilfreich oder problematisch sein. Testete diesen Code.
/** * @param firstInstance * @param secondInstance */ protected static void findMatchingValues(SomeClass firstInstance, SomeClass secondInstance) { try { Class firstClass = firstInstance.getClass(); Method[] firstClassMethodsArr = firstClass.getMethods(); Class secondClass = firstInstance.getClass(); Method[] secondClassMethodsArr = secondClass.getMethods(); for (int i = 0; i < firstClassMethodsArr.length; i++) { Method firstClassMethod = firstClassMethodsArr[i]; // target getter methods. if(firstClassMethod.getName().startsWith("get") && ((firstClassMethod.getParameterTypes()).length == 0) && (!(firstClassMethod.getName().equals("getClass"))) ){ Object firstValue; firstValue = firstClassMethod.invoke(firstInstance, null); logger.info(" Value "+firstValue+" Method "+firstClassMethod.getName()); for (int j = 0; j < secondClassMethodsArr.length; j++) { Method secondClassMethod = secondClassMethodsArr[j]; if(secondClassMethod.getName().equals(firstClassMethod.getName())){ Object secondValue = secondClassMethod.invoke(secondInstance, null); if(firstValue.equals(secondValue)){ logger.info(" Values do match! "); } } } } } } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } }
quelle
Fields
keine Methoden überprüfen . Methoden können alles sein, wiegetRandomNumber()
.Ein einfacherer Ansatz, um schnell festzustellen, ob zwei Objekte unterschiedlich sind, ist die Verwendung der Apache Commons-Bibliothek
BeanComparator lastNameComparator = new BeanComparator("lname"); logger.info(" Match "+bc.compare(firstInstance, secondInstance));
quelle