क्या कोई जावा पुस्तकालय है जो दो वस्तुओं को "अलग" कर सकता है?


86

क्या एक जावा उपयोगिता पुस्तकालय है जो यूनिक्स कार्यक्रम के अनुरूप है, लेकिन वस्तुओं के लिए? मैं एक ऐसी चीज की तलाश कर रहा हूं जो एक ही प्रकार की दो वस्तुओं की तुलना कर सके और एक डेटा संरचना उत्पन्न कर सके जो उनके बीच अंतरों का प्रतिनिधित्व करती है (और उदाहरण के चर में अंतर की तुलना कर सकते हैं)। मैं एक पाठ अंतर के जावा कार्यान्वयन के लिए नहीं देख रहा हूँ । मैं यह करने के लिए परावर्तन का उपयोग करने में सहायता के लिए भी नहीं देख रहा हूँ ।

मेरे द्वारा बनाए जा रहे एप्लिकेशन में इस कार्यक्षमता का एक नाजुक कार्यान्वयन है जिसमें कुछ खराब डिजाइन विकल्प थे और जिन्हें फिर से लिखने की आवश्यकता है, लेकिन यह बेहतर होगा यदि हम शेल्फ से कुछ का उपयोग कर सकते हैं।

यहाँ मैं देख रहा हूँ कि किस तरह की चीज़ का एक उदाहरण है:

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

तुलना करने के बाद, उपयोगिता मुझे बताएगी कि "प्रोप 1" दो वस्तुओं के बीच अलग है और "प्रोप 2" समान है। मुझे लगता है कि यह एक पेड़ होने के लिए डिफ्डाटास्ट्रक्चर के लिए सबसे स्वाभाविक है, लेकिन अगर कोड विश्वसनीय है, तो मैं पिकी नहीं जाऊंगा।


8
इस की जांच code.google.com/p/jettison
denolk


13
यह "जटिल वस्तु रेखांकन की समानता के लिए परीक्षण करने के लिए कैसे" का एक डुप्लिकेट नहीं है? मैं एक पुस्तकालय की तलाश कर रहा हूं, इसे करने के तरीके के बारे में सलाह नहीं। इसके अलावा, मैं डेल्टा में दिलचस्पी रखता हूं, यह नहीं कि वे समान हैं या नहीं।
कायर्प्रो द्वितीय

1
को देखो github.com/jdereg/java-util जो एक GraphComparator उपयोगिताओं है। यह वर्ग वस्तु रेखांकन के बीच डेल्टा की सूची तैयार करेगा। इसके अलावा, इसमें एक डेल्टा को एक ग्राफ में विलय (लागू) किया जा सकता है। प्रभावी रूप से यह सूची है <Delta> = GraphComparator (rootA, rootB)। साथ ही साथ ग्राफकंपेरेटर.प्लाईडेल्टा (रूटबी, लिस्ट <डेल्टा>)।
19 De:59 पर जॉन DeRegnaucourt

मुझे पता है कि आप प्रतिबिंब का उपयोग नहीं करना चाहते हैं, लेकिन यह निश्चित रूप से इस तरह से लागू करने का सबसे आसान / सरल तरीका है
RobOhRob

जवाबों:


42

थोड़ी देर हो सकती है, लेकिन मैं आपकी जैसी ही स्थिति में था और आपके उपयोग-मामले के लिए अपनी खुद की लाइब्रेरी बनाना समाप्त कर दिया। चूंकि मुझे खुद एक समाधान के साथ आने के लिए मजबूर किया गया था, इसलिए मैंने दूसरों को कड़ी मेहनत करने के लिए इसे जीथब पर रिलीज करने का फैसला किया। आप इसे यहां पा सकते हैं: https://github.com/SQiShER/java-object-diff

--- संपादित करें ---

यहाँ ओपीएस कोड के आधार पर थोड़ा उपयोग उदाहरण दिया गया है:

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
क्या मैं आपको इस पोस्ट में जावा-ऑब्जेक्ट-डिफरेंस के उपयोग के मामले को इंगित कर सकता हूं? stackoverflow.com/questions/12104969/… इस सहायक पुस्तकालय के लिए बहुत बहुत धन्यवाद!
मथायस वॉटके

मैंने आपकी पोस्ट पर एक नज़र डालते हुए एक उत्तर लिखा, जो एक टिप्पणी के रूप में पोस्ट करने के लिए बहुत लंबा हो गया, इसलिए यहां इसका "सार" है: gist.github.com/3555555
SQiShER

2
साफ। मैंने अपना खुद का कार्यान्वयन भी लिखना समाप्त कर दिया। मुझे यकीन नहीं है कि मुझे वास्तव में आपके कार्यान्वयन का पता लगाने का मौका मिलेगा, लेकिन मैं उत्सुक हूं कि आप सूचियों को कैसे संभालते हैं। मैंने मानचित्र के अंतर के रूप में सभी संग्रह अंतरों को संभालना समाप्त कर दिया (यदि यह एक सूची, सेट या मानचित्र पर निर्भर करता है, तो कुंजी पर सेट संचालन का उपयोग करके निर्भर करता है)। हालाँकि, वह विधि सूची-सूचकांक परिवर्तनों के प्रति अति-संवेदनशील है। मैंने उस समस्या को हल नहीं किया क्योंकि मुझे अपने आवेदन की आवश्यकता नहीं थी, लेकिन मैं इस बारे में उत्सुक हूं कि आपने इसे कैसे संभाला (पाठ-रूपांतर की तरह, मैं मान लूंगा)।
कायर्प्रो II

2
आपने अच्छा मुद्दा उठाया। इससे निपटने के लिए संग्रह वास्तव में कठिन हैं। खासकर यदि आप विलय का समर्थन करते हैं, जैसे कि मैं करता हूं। मैंने यह पहचानने के लिए कि क्या कोई आइटम जोड़ा गया है, बदल दिया है या हटा दिया गया है (हैशकोड, बराबरी और समाहित) के माध्यम से वस्तु पहचान का उपयोग करके समस्या को हल किया। इसके बारे में अच्छी बात यह है, कि मैं सभी संग्रहों को एक ही मान सकता हूं। बुरी बात यह है, कि मैं ठीक से संभाल नहीं सकता (उदाहरण के लिए) ArrayLists जिसमें एक ही वस्तु कई बार होती है। मैं उस के लिए समर्थन जोड़ना पसंद करूंगा, लेकिन यह बहुत जटिल लगता है और सौभाग्य से किसी ने भी इसके लिए नहीं कहा, फिर भी। :-)
20

डैनियल, आपकी टिप्पणी के लिए धन्यवाद! आप सही हैं, भिन्न से मूल वस्तु का पुनर्निर्माण मुश्किल है, लेकिन यह मेरे मामले में बहुत महत्वपूर्ण नहीं है। मूल रूप से, मैंने डेटाबेस में अपनी वस्तु के पिछले संस्करणों को संग्रहीत किया है - जैसा कि आप सलाह देते हैं। समस्या यह थी कि बड़े दस्तावेज़ों के अधिकांश हिस्से नहीं बदले, बहुत अधिक डुप्लिकेट डेटा था। यही कारण है कि मैंने विकल्पों की खोज शुरू की और मुझे जावा-ऑब्जेक्ट-डिफरेंस मिला। मैंने संग्रह / मानचित्रों के साथ कठिनाइयों का भी अनुभव किया और डेटाबेस प्राथमिक (और संपूर्ण वस्तु नहीं) की समानता की जांच करने के लिए मेरे "बराबर" तरीकों को बदल दिया, इससे मदद मिली।
मथायस वॉटके

39

http://javers.org वह लाइब्रेरी है, जो आपके लिए जरूरी है: तुलना (ऑब्जेक्ट लेफ्टग्राफ, ऑब्जेक्ट राइटग्राफ) जैसे तरीके हैं जो डिफ ऑब्जेक्ट को लौटाते हैं। डिफ में परिवर्तन की एक सूची शामिल है (ReferenceChange, ValueChange, PropertyChange) उदा

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

यह ग्राफ़ में चक्रों को संभाल सकता है।

इसके अलावा आप किसी भी ग्राफ ऑब्जेक्ट का स्नैपशॉट प्राप्त कर सकते हैं। Javers में स्नैपशॉट के लिए JSON सीरियलएजर और डीसेरिएलाइज़र होते हैं, और परिवर्तन होते हैं ताकि आप उन्हें डेटाबेस में आसानी से बचा सकें। इस लाइब्रेरी के साथ आप ऑडिटिंग के लिए एक मॉड्यूल आसानी से लागू कर सकते हैं।


1
यह काम नहीं करता है। आप एक Javers आवृत्ति कैसे बनाते हैं?
रयान वेट्सर्स

2
Javers के पास उत्कृष्ट प्रलेखन है जो सब कुछ समझाता है: javers.org
Paweł Szymczyk

2
मैंने इसका उपयोग करने की कोशिश की लेकिन यह केवल जावा> = 7 के लिए है। दोस्तों, अभी भी जावा 6 पर परियोजनाओं पर काम कर रहे लोग हैं !!!
जसंताना

2
क्या होगा अगर मैं जिन दो वस्तुओं की तुलना करता हूं उनमें आंतरिक रूप से वस्तुओं की एक सूची है और क्या मैं उन अंतरों को भी देख रहा हूं? पदानुक्रम का वह स्तर क्या है जिसकी तुलना जावर कर सकते हैं?
दीपक

1
हां आपको आंतरिक वस्तुओं पर अंतर दिखाई देगा। फिलहाल पदानुक्रम स्तर के लिए कोई सीमा नहीं है। Javers जितना संभव हो उतना गहरा जाएगा, सीमा का आकार ढेर है।
Paweł Szymczyk

15

हां, जावा- यूज़ लाइब्रेरी में एक ग्राफ़कॉमपरेटर क्लास है जो दो जावा ऑब्जेक्ट ग्राफ़ की तुलना करेगा। यह डेल्टास की सूची के रूप में अंतर लौटाता है। GraphComparator आपको डेल्टास को भी मर्ज (लागू) करने की अनुमति देता है। इस कोड में केवल JDK पर निर्भरताएं हैं, कोई अन्य पुस्तकालय नहीं।


12
एक अच्छा पुस्तकालय लगता है, आपको उल्लेख करना चाहिए कि आप एक योगदानकर्ता हैं
क्राइस्टोस

3

सभी जेवर्स लाइब्रेरी का केवल जावा 7 को समर्थन है, मैं एक स्थिति में था क्योंकि मैं चाहता हूं कि इसका उपयोग जावा 6 परियोजना के लिए किया जाए इसलिए मैं स्रोत को लेने के लिए हुआ और एक तरह से बदल गया, जो नीचे जावा 6 के लिए काम करता है। ।

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

जार लिंक: https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar

मैंने केवल जावा 7 समर्थित '<>' के अंतर्निहित 6 रूपांतरणों को जावा 6 के समर्थन में बदल दिया है और न ही मैं उन सभी कार्यक्षमताओं पर काम करूंगा क्योंकि मैंने मेरे लिए कुछ अनावश्यक कोड टिप्पणी की है जो सभी कस्टम ऑब्जेक्ट्स के लिए काम करता है।



2

तुम भी Apache से समाधान पर एक नज़र डाल सकते हैं। अधिकांश परियोजनाएं पहले से ही कॉमन्स-लैंग के अपने हिस्से के बाद से उनके क्लासपाथ पर हैं।

विशिष्ट क्षेत्र के लिए अंतर की जाँच करें:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/DiffBuilder.html

प्रतिबिंब का उपयोग करके अंतर की जाँच करें:
http://commons.apache.org/proper/commons-lang/javadocs/api-3.9/org/apache/commons/lang3/builder/ReflectionDiffBuis.html


1

शायद यह मदद करेगा, जहां आप इस कोड का उपयोग करते हैं, उसके आधार पर यह उपयोगी या समस्याग्रस्त हो सकता है। इस कोड का परीक्षण किया।

    /**
 * @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
धन्यवाद, लेकिन हमारे पास पहले से ही कोड है जो प्रतिबिंब का उपयोग करके ऑब्जेक्ट ग्राफ को बदलता है। यह सवाल यह नहीं है कि इसे कैसे करना है, यह पहिया को फिर से आविष्कार करने से बचने की कोशिश करने के बारे में है।
काइप्रो II

यदि सुदृढीकरण पहले से ही हुआ है, तो पहिया को फिर से चालू करना बुरा नहीं है। (आईई: प्रबलित पहिया के लिए पहले से ही भुगतान किया गया था।)
थॉमस ईडिंग

1
मैं आपसे सहमत हूं, लेकिन इस मामले में पुनर्निवेशित कोड एक अजेय गड़बड़ है।
कायर्प्रो द्वितीय

3
मैं Fieldsतरीकों की जाँच नहीं करूँगा । तरीके कुछ भी हो सकते हैं, जैसे getRandomNumber()
बोहेमियन

-3

यदि दो वस्तुएं भिन्न हैं, तो अपाचे कॉमन्स लाइब्रेरी का उपयोग करना होगा

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

यह मेरे लिए काम नहीं करता है क्योंकि मुझे यह जानने की जरूरत है कि क्या बदला है, न कि सिर्फ यह कि कहीं बदलाव हुआ था।
काइप्रो II
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.