2011-11-03 14 views
55

Czy istnieje biblioteka narzędziowa Java, która jest analogiczna do różnicy w systemie Unix, ale w przypadku obiektów? Szukam czegoś, co może porównać dwa obiekty tego samego typu i wygenerować strukturę danych, która reprezentuje różnice między nimi (i może rekurencyjnie porównać różnice w zmiennych instancji). Jestem nie szukają implementacji Java różnicy tekstowej. Jestem również nie szuka pomocy w używaniu refleksji, aby to zrobić.Czy istnieje biblioteka Java, która może "zmienić" dwa obiekty?

Aplikacja, którą utrzymuję, ma delikatną implementację tej funkcjonalności, która miała kiepskie wybory w zakresie projektowania i która musi zostać przepisana, ale byłoby jeszcze lepiej, gdybyśmy mogli użyć czegoś z półki.

Oto przykład tego rodzaju rzeczy szukam:

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 

Po porównaniu, narzędzie powie mi, że „prop1” różni się pomiędzy dwoma obiektami i „prop2” jest taka sama . Myślę, że to naturalne, że DiffDataStructure jest drzewem, ale nie będę wybredny, jeśli kod będzie niezawodny.

+7

Sprawdź to, http://code.google.com/p/jettison/ – denolk

+0

możliwy duplikat [Jak przetestować pod kątem równości złożonych wykresów obiektów?] (Http://stackoverflow.com/questions/1411612/how -to-test-dla-równości-złożonych-obiektów-wykresów) – skaffman

+7

To nie jest duplikat "Jak przetestować równość złożonych grafów obiektów?" Szukam biblioteki, a nie porady, jak to zrobić. Co więcej, interesuję się deltą, nie jeśli są one równe lub nie. –

Odpowiedz

1

Może to pomoże, w zależności od tego, gdzie używasz tego kodu, może być przydatne lub problematyczne. Przetestowałem ten kod.

/** 
* @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(); 
     } 
} 
+1

Dzięki, ale mamy już kod, który przechadza się po wykresie obiektu za pomocą refleksji i wyświetla listę zmian. To pytanie nie dotyczy tego, jak to zrobić, chodzi o to, aby uniknąć ponownego wynalezienia koła. –

+0

Ponowne wymyślanie koła nie jest złe, jeśli ponowne zajęcie już nastąpiło. (IE: Odnowione koło było już opłacone.) –

+1

Zgadzam się z tobą, ale w tym przypadku nowo sformułowany kod jest niepojętym bałaganem. –

-2

Prostsze podejście do szybko powiedzieć, czy dwa obiekty są różne byłyby jest użycie biblioteki Commons Apache

BeanComparator lastNameComparator = new BeanComparator("lname"); 
    logger.info(" Match "+bc.compare(firstInstance, secondInstance)); 
+0

To nie działa dla mnie, ponieważ muszę wiedzieć, co się zmieniło, nie tylko to, że gdzieś tam była zmiana. –

32

Może być trochę późno, ale byłem w takiej samej sytuacji jak ty i skończyło się na stworzeniu własnej biblioteki dokładnie dla twojego przypadku użycia. Ponieważ sam zostałem zmuszony do znalezienia rozwiązania, postanowiłem wydać go na Github, aby oszczędzić innym ciężkiej pracy. Można go znaleźć tutaj: https://github.com/SQiShER/java-object-diff

--- Edit ---

Oto mały przykład użycia na podstawie kodu Ops:

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; 
+1

Czy mogę skierować cię do tego posta pokazującego przypadek użycia obiektu java-object-diff? http://stackoverflow.com/questions/12104969/java-mongodb-object-versioning Wielkie dzięki za pomocną bibliotekę! –

+0

Spojrzałem na twój wpis i napisałem odpowiedź, która okazała się zbyt długa, aby zamieścić ją jako komentarz, więc tutaj jest "sedno" tego: https://gist.github.com/3555555 – SQiShER

+2

Schludny. Skończyłem też na pisaniu własnej implementacji. Nie jestem pewien, czy uda mi się naprawdę zbadać twoją implementację, ale jestem ciekawy jak sobie radzisz z Listami. Skończyło się na tym, że zajmowałem się wszystkimi różnicami w zbieraniu danych jako różnicami w Mapach (poprzez definiowanie kluczy na różne sposoby w zależności od tego, czy jest to lista, zestaw, czy mapa, a następnie za pomocą operacji ustawiania na keySet). Jednak ta metoda jest zbyt wrażliwa na zmiany w indeksie listy. Nie rozwiązałem tego problemu, ponieważ nie musiałem go stosować, ale jestem ciekawy, jak sobie z nim poradziłeś (bardziej przypomina to różnicę tekstową, jak przypuszczam). –

20

http://javers.org jest biblioteka, która robi co exacly potrzebujesz: ma metody takie jak compare (Object leftGraph, Object rightGraph) zwracające obiekt Diff. Diff zawiera listę zmian (ReferenceChange, ValueChange, PropertyChange) np.

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 

Obsługuje cykle na wykresach.

Dodatkowo można uzyskać migawkę dowolnego obiektu graficznego. Javers posiada szeregery JSON i deserializatory do migawek i zmiany, dzięki czemu można je łatwo zapisać w bazie danych. Dzięki tej bibliotece możesz łatwo zaimplementować moduł do audytu.

+1

to nie działa. Jak utworzyć instancję Javers? –

+0

Nie mogę też utworzyć instancji Javers. Podaj nam kilka wskazówek. – marcel

+0

Javers posiada doskonałą dokumentację, która wyjaśnia wszystko: [javers.org] (http://javers.org/documentation/getting-started/#create-javers-instance) –

2

Wszystkie biblioteki Javers obsługuje tylko Java 7, byłem w sytuacji, ponieważ chcę, aby to było używane dla projektu Java 6, więc zdarzyło mi się wziąć źródło i zmienić w sposób, który działa dla Java 6 poniżej jest kod github.

https://github.com/sand3sh/javers-forJava6

Link Jar: https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar

Mam tylko zmienił Java 7 obsługiwana '<>' nieodłączne konwersje oddanych do Java 6 wsparcia dont Gwarantujemy wszystkie funkcje będą działać, ponieważ mam skomentował mało niepotrzebny kod dla mnie działa dla wszystkich porównań obiektów niestandardowych.

+0

Link do słownika - https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar – Sandesh

6

Tak, biblioteka java-util ma klasę GraphComparator, która porówna dwa wykresy obiektów Java. Zwraca różnicę jako listę delt. Program GraphComparator umożliwia również scalanie (stosowanie) również delt. Ten kod ma tylko zależności od JDK, żadnych innych bibliotek.

+1

Wydaje się, że jest to ładna biblioteka, powinieneś wspomnieć, że jesteś kontrybutorem – Christos

Powiązane problemy