İki Nesneyi "ayırabilen" bir Java kitaplığı var mı?


90

Unix program farkına benzer, ancak Nesneler için olan bir Java yardımcı programı kitaplığı var mı? Aynı türden iki nesneyi karşılaştırabilen ve aralarındaki farkları temsil eden (ve örnek değişkenlerindeki farklılıkları özyinelemeli olarak karşılaştırabilen) bir veri yapısı oluşturabilen bir şey arıyorum. Ben değilim değil bir metin fark bir Java uygulaması arıyorsanız. Bunu yapmak için yansımayı nasıl kullanacağım konusunda da yardım aramıyorum .

Sürdürdüğüm uygulama, bu işlevselliğin bazı zayıf tasarım seçeneklerine sahip ve yeniden yazılması gereken kırılgan bir uygulamasına sahip, ancak rafta bir şey kullansak daha da iyi olurdu.

İşte aradığım şeylerin bir örneği:

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

Karşılaştırmadan sonra, yardımcı program bana "prop1" in iki nesne arasında farklı olduğunu ve "prop2" nin aynı olduğunu söylerdi. DiffDataStructure'ın bir ağaç olması en doğal olduğunu düşünüyorum, ancak kod güvenilirse seçici olmayacağım.


9
bunu kontrol edin, code.google.com/p/jettison
denolk


14
Bu, "Karmaşık nesne grafiklerinin eşitliği nasıl test edilir?" Nasıl yapılacağına dair bir tavsiye değil, bir kütüphane arıyorum. Dahası, delta ile ilgileniyorum, eşit olup olmadıklarına değil.
Kaypro II

1
GraphComparator yardımcı programlarına sahip github.com/jdereg/java-util adresine bakın . Bu sınıf, nesne grafikleri arasındaki delta listesi oluşturacaktır. Ek olarak, bir deltayı bir grafiğe birleştirebilir (uygulayabilir). Etkili olarak List <Delta> = GraphComparator (rootA, rootB). Ayrıca GraphComparator.applyDelta (rootB, List <Delta>).
John DeRegnaucourt

Yanıtlar:


44

Biraz geç olabilir, ama ben de senin gibi aynı durumdaydım ve tam olarak sizin kullanım durumunuz için kendi kütüphanemi oluşturmaya başladım. Kendim bir çözüm bulmaya zorlandığım için, başkalarının zor işlerinden kaçınmak için onu Github'da yayınlamaya karar verdim. Burada bulabilirsiniz: https://github.com/SQiShER/java-object-diff

--- Düzenle ---

İşte OPs koduna dayalı küçük bir kullanım örneği:

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
Sizi java-object-diff'in kullanım örneğini gösteren bu gönderiye yönlendirebilir miyim? stackoverflow.com/questions/12104969/… Bu yardımcı kitaplık için çok teşekkürler!
Matthias Wuttke


2
Düzgün. Ben de kendi uygulamamı yazdım. Uygulamanızı gerçekten keşfetme şansı bulacağımdan emin değilim, ancak Listeleri nasıl ele aldığınızı merak ediyorum. Tüm koleksiyon farklılıklarını Haritalar'ın farklılıkları olarak ele aldım (anahtarları bir liste, küme veya harita olmasına bağlı olarak farklı şekillerde tanımlayarak; ardından keySet üzerinde ayar işlemlerini kullanarak). Ancak, bu yöntem liste dizini değişikliklerine aşırı duyarlıdır. Bu sorunu çözmedim çünkü başvurum için buna ihtiyacım yoktu, ancak nasıl ele aldığınızı merak ediyorum (daha çok bir metin farkı gibi, varsayıyorum).
Kaypro II

2
İyi bir noktaya parmak bastın. Koleksiyonlarla uğraşmak gerçekten zor. Özellikle benim gibi birleşmeyi destekliyorsan. Bir öğenin eklenip eklenmediğini, değiştirilip değiştirilmediğini (hashCode aracılığıyla, eşittir ve içerir) algılamak için nesne kimliklerini kullanarak sorunu çözdüm. Bununla ilgili iyi olan şey, tüm koleksiyonlara aynı şekilde davranabilmem. Kötü olan şey, aynı nesneyi birden çok kez içeren Dizi Listelerini (örneğin) düzgün bir şekilde işleyemememdir. Bunun için destek eklemeyi çok isterdim, ancak oldukça karmaşık görünüyor ve neyse ki henüz kimse bunu istemedi. :-)
SQiShER

Daniel, yorumun için teşekkürler! Haklısın, orijinal nesneyi farklılardan yeniden oluşturmak zor, ama benim durumumda bu çok önemli değil. Başlangıçta, sizin önerdiğiniz gibi nesnemin önceki sürümlerini veritabanında sakladım. Sorun, büyük belgelerin çoğu bölümünün değişmemesiydi, çok sayıda yinelenen veri vardı. Bu yüzden alternatifler aramaya başladım ve java-object-diff buldum. Ayrıca koleksiyonlar / haritalarda zorluklar yaşadım ve birincil veri tabanının (tüm nesnenin değil) eşitliğini kontrol etmek için "eşittir" yöntemlerimi değiştirdim, bu yardımcı oldu.
Matthias Wuttke

40

http://javers.org tam olarak ihtiyacınız olanı yapan kitaplıktır: Diff nesnesini döndüren karşılaştırma (Object leftGraph, Object rightGraph) gibi yöntemlere sahiptir. Diff, bir değişiklik listesi içerir (ReferenceChange, ValueChange, PropertyChange) örn.

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

Grafiklerdeki döngüleri idare edebilir.

Ayrıca herhangi bir grafik nesnesinin Snapshot'ını alabilirsiniz. Javers, anlık görüntü için JSON serileştiricilerine ve seriyi kaldırıcılara sahiptir ve bunları veritabanına kolayca kaydedebilmeniz için değişiklikler yapar. Bu kitaplık ile denetim için kolayca bir modül uygulayabilirsiniz.


1
bu çalışmıyor. nasıl bir Javers örneği oluşturursunuz?
Ryan Vettese

2
Javers, her şeyi açıklayan mükemmel belgelere sahiptir: javers.org
Paweł Szymczyk

2
Kullanmaya çalıştım ama sadece Java> = 7 için. Beyler, hala Java 6 üzerinde projeler üzerinde çalışan insanlar var !!!
jesantana

2
Ya karşılaştırdığım iki nesne dahili olarak nesnelerin bir listesine sahipse ve ben de bu farklılıkları görecek miyim? Javer'ların karşılaştırabileceği hiyerarşi düzeyi nedir?
Deepak

1
Evet, iç nesnelerde farklılıklar göreceksiniz. Şu anda hiyerarşi seviyesi için bir eşik yoktur. Javers mümkün olduğu kadar derine inecek, sınırlama yığın boyutudur.
Paweł Szymczyk

16

Evet, java-util kitaplığı iki Java Nesne Grafiğini karşılaştıran bir GraphComparator sınıfına sahiptir. Farkı delta listesi olarak döndürür. GraphComparator ayrıca deltaları birleştirmenize (uygulamanıza) izin verir. Bu kod yalnızca JDK'ya bağımlıdır, başka kitaplık yoktur.


13
Güzel bir kütüphane gibi görünüyor, katkıda bulunduğunuzu söylemelisiniz
Christos

4

Apache'nin çözümüne de göz atabilirsiniz. Ortak dil bölümünden bu yana çoğu projede zaten sınıf yolunda var.

Belirli alanlar için farkı kontrol edin:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/DiffBuilder.html

Yansımayı kullanarak farkı kontrol edin:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/ReflectionDiffBuilder.html


Kabul edilen cevap bu olmalı!
Janaka Bandara

3

Tüm Javers kütüphanesi sadece Java 7'yi destekliyor, bunun bir Java 6 projesi için kullanılmasını istediğim için bir durumdaydım, bu yüzden kaynağı aldım ve Java 6 için çalışma şeklini değiştirdim aşağıdaki github kodu .

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

Jar bağlantısı: https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar

Yalnızca Java 7 destekli '<>' doğasında olan dönüştürme dönüşümlerini Java 6 desteğine değiştirdim. Tüm işlevlerin çalışacağını garanti etmiyorum çünkü benim için birkaç gereksiz kodu yorumladım, tüm özel nesneler karşılaştırması için çalışıyor.



1

Belki bu, bu kodu nerede kullandığınıza bağlı olarak yardımcı olabilir, yararlı veya sorunlu olabilir. Bu kodu test etti.

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

2
Teşekkürler, ancak değişiklikleri yansıma listeleri kullanarak nesne grafiğinde yürüyen bir kodumuz var. Bu soru nasıl yapılacağıyla ilgili değil, tekerleği yeniden icat etmekten kaçınmaya çalışmakla ilgili.
Kaypro II

Yeniden icat zaten gerçekleştiyse, tekerleği yeniden icat etmek fena değil. (IE: Yeniden icat edilen tekerleğin ücreti zaten ödendi.)
Thomas Eding

1
Size katılıyorum, ancak bu durumda yeniden icat edilen kod, sürdürülemez bir karmaşa.
Kaypro II

3
FieldsYöntemleri değil kontrol ediyor olacağım . Yöntemler herhangi bir şey olabilir getRandomNumber().
Bohemian

-3

İki nesnenin farklı olup olmadığını hızlı bir şekilde anlamanın daha basit bir yolu, apache commons kitaplığını kullanmaktır.

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

Bu benim için işe yaramıyor çünkü sadece bir yerlerde bir değişiklik olduğunu değil neyin değiştiğini bilmem gerekiyor.
Kaypro II
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.