2015-11-17 11 views
6

मैं कक्षाओं, अच्छी तरह से, अपरिवर्तनीय बनाने के लिए एक आसान तरीका के रूप में ग्रोवी के @Immutable एएसटी परिवर्तन की सलाह देता हूं। यह हमेशा अन्य ग्रोवी कक्षाओं के साथ ठीक काम करता है, लेकिन किसी ने हाल ही में मुझसे पूछा कि क्या मैं उन वर्गों को जावा कोड में मिला सकता हूं। मैंने हमेशा सोचा कि जवाब हाँ था, लेकिन मैं एक झगड़ा मार रहा हूँ। सब कुछ काम करता है के रूप में उम्मीदजावा में ग्रोवी @ इमटेबल वर्ग

import groovy.transform.Immutable 

@Immutable 
class User { 
    int id 
    String name 
} 

अगर मैं एक JUnit परीक्षण ग्रूवी में लिखा का उपयोग कर यह परीक्षण,:

import org.junit.Test 

class UserGroovyTest { 

    @Test 
    void testMapConstructor() { 
     assert new User(name: 'name', id: 3) 
    } 

    @Test 
    void testTupleConstructor() { 
     assert new User(3, 'name') 
    } 

    @Test 
    void testDefaultConstructor() { 
     assert new User() 
    } 

    @Test(expected = ReadOnlyPropertyException) 
    void testImmutableName() { 
     User u = new User(id: 3, name: 'name') 
     u.name = 'other' 
    } 
} 

मैं एक साथ भी ऐसा ही कर सकते हैं

मैं अपरिवर्तनीय User वर्ग है कहो जावा में लिखित जुनीट टेस्ट:

आयात स्थिर org.junit.Assert। *;

import org.junit.Test; 

public class UserJavaTest { 

    @Test 
    public void testDefaultCtor() { 
     assertNotNull(new User()); 
    } 

    @Test 
    public void testTupleCtor() { 
     assertNotNull(new User(3, "name")); 
    } 

    @Test 
    public void testImmutableName() { 
     User u = new User(3, "name"); 
     // u.setName("other") // Method not found; doesn't compile 
    } 
} 

यह काम करता है, हालांकि क्षितिज पर परेशानी होती है। IntelliJ 15 को new User() पर कॉल पसंद नहीं है, दावा करते हुए कि निर्माता नहीं मिला है। इसका मतलब यह भी है कि आईडीई लाल रंग को लाल रंग में रेखांकित करता है, जिसका अर्थ है कि इसमें संकलन त्रुटि है। परीक्षण वैसे भी गुजरता है, जो थोड़ा अजीब है, लेकिन ऐसा ही हो।

यदि मैं सीधे जावा कोड में User कक्षा का उपयोग करने का प्रयास करता हूं, तो चीजें अजीब लगती हैं।

public class UserDemo { 
    public static void main(String[] args) { 
     User user = new User(); 
     System.out.println(user); 
    } 
} 

फिर इंटेलिजे खुश नहीं है, लेकिन संकलित और चलाता है। उत्पादन सब बातों की, है:

User(0) 

कि अजीब है, क्योंकि हालांकि @Immutable बदलना एक toString विधि उत्पन्न करता है, मैं नहीं बल्कि यह उत्पादन की उम्मीद दोनों गुण दिखाने के लिए। फिर भी, ऐसा इसलिए हो सकता है क्योंकि name संपत्ति शून्य है, इसलिए यह आउटपुट में शामिल नहीं है।

अगर मैं टपल निर्माता इस्तेमाल करने की कोशिश:

public class UserDemo { 
    public static void main(String[] args) { 
     User user = new User(3, "name"); 
     System.out.println(user); 
    } 
} 

मैं आउटपुट के रूप में

User(0, name) 

मिलता है, कम से कम इस बार (कभी कभी यह बिल्कुल काम नहीं करता है)।

फिर मैंने एक ग्रैडल बिल्ड फ़ाइल जोड़ा।

> gradle test 
error: cannot find symbol 
User user = new User(...) 
^ 

मैं आमतौर पर इस तरह पार संकलन मुद्दों को ठीक: यदि मैं src\main\java (परीक्षण के लिए एक ही लेकिन इसके बजाय test फ़ोल्डर का उपयोग) के तहत src\main\groovy तहत ग्रूवी वर्गों और जावा वर्गों डाल, मैं तुरंत एक संकलन मुद्दा मिल सब कुछ के लिए ग्रोवी कंपाइलर का उपयोग करने की कोशिश कर। अगर मैं src\main\java के तहत दोनों कक्षाएं डालता हूं, तो कुछ भी नहीं बदलता है, जो एक बड़ा आश्चर्य नहीं है। लेकिन अगर मैं src\main\groovy के तहत दोनों वर्गों में कहें, तो मैं इस compileGroovy चरण के दौरान मिलता है:

> gradle clean test 
error: constructor in class User cannot be applied to the given types; 
User user = new User(3, "name"); 

required: no arguments 
found: int,String 
reason: actual and formal arguments differ in length 

हुह। इस बार यह ट्यूपल कन्स्ट्रक्टर पर ऑब्जेक्ट कर रहा है, क्योंकि ऐसा लगता है कि इसमें केवल एक डिफ़ॉल्ट कन्स्ट्रक्टर है। मुझे पता है कि ट्रांसफॉर्म एक डिफ़ॉल्ट, नक्शा-आधारित, और एक ट्यूपल कन्स्ट्रक्टर जोड़ता है, लेकिन शायद वे जावा कोड के लिए उन्हें देखने के लिए समय में उत्पन्न नहीं हो रहे हैं।

संयोग से, अगर मैं फिर से जावा और ग्रूवी वर्गों को अलग, और मेरे Gradle के लिए निम्न जोड़ने का निर्माण:

sourceSets { 
    main { 
     java { srcDirs = []} 
     groovy { srcDir 'src/main/java' } 
    } 
} 

मैं एक ही त्रुटि मिलती है। अगर मैं sourceSets ब्लॉक नहीं जोड़ता, तो मुझे User कक्षा पहले से त्रुटि नहीं मिली है।

तो नीचे की रेखा यह है कि @Immutable ग्रोवी क्लास को मौजूदा जावा सिस्टम में जोड़ने का सही तरीका क्या है? क्या जावा को देखने के लिए समय पर रचनाकारों को उत्पन्न करने का कोई तरीका है?

मैं वर्षों से जावा डेवलपर्स को ग्रोवी प्रस्तुतिकरण कर रहा हूं और कह रहा हूं कि आप यह कर सकते हैं, केवल समस्याओं में भाग लेने के लिए। किसी भी तरह से चेहरे को बचाने में मेरी मदद करें। :)

+0

विशेष रूप से एएसटी रूपांतरणों के साथ ग्रोवी की बात आती है तो आईडीई झूठी-नकारात्मकता देते हैं। क्रॉस-संकलन मुद्दे के लिए आप दो अलग-अलग परियोजनाओं, एक जावा और एक ग्रोवी होने का प्रयास कर सकते हैं। यदि यह अभी भी एक अनसुलझा सवाल है, तो मैं इसे सुबह में एक भंवर दे दूंगा। यह वास्तव में ऐसा लगता है जैसे इसे काम करना चाहिए। – cjstehno

+0

क्या व्यवहार '@ CompileStatic' के साथ समान है? – dmahapatro

+0

'@ कंपाइलस्टैटिक 'कुछ भी नहीं बदलता – kousen

उत्तर

4

मैंने आपके परिदृश्य को भी आजमाया है, जहां आपके पास src/main/java और src/main/groovy निर्देशिका वाला एक एकल प्रोजेक्ट है और आपने जो देखा है उसके समान संकलन त्रुटियों के साथ समाप्त हुआ।

जब मैं जावा कोड से एक अलग परियोजना में ग्रोवी अपरिवर्तक डालता हूं तो मैं जावा में ग्रोवी अपरिवर्तनीय वस्तुओं का उपयोग करने में सक्षम था। मैंने एक साधारण उदाहरण बनाया है और इसे गिटहब (https://github.com/cjstehno/immut) पर धक्का दिया है।

असल में यह immut-groovy सब-प्रोजेक्ट में सभी ग्रोवी कोड (अपरिवर्तनीय ऑब्जेक्ट) और immut-java प्रोजेक्ट में सभी जावा कोड के साथ एक ग्रैडल मल्टी-प्रोजेक्ट है। immut-java परियोजना immut-groovy परियोजना पर निर्भर करता है और अपरिवर्तनीय Something वस्तु का उपयोग करता है:

public class SomethingFactory { 

    Something createSomething(int id, String label){ 
     return new Something(id, label); 
    } 
} 

मैं जावा परियोजना जो अपरिवर्तनीय ग्रूवी वर्ग का एक नया उदाहरण बनाता है और उसकी सामग्री को सत्यापित करता है में एक इकाई परीक्षण गयी।

public class SomethingFactoryTest { 
    @Test 
    public void createSomething(){ 
     Something something = new SomethingFactory().createSomething(42, "wonderful"); 

     assertEquals(something.getId(), 42); 
     assertEquals(something.getLabel(), "wonderful"); 
    } 
} 

यह वास्तव में आदर्श नहीं है, लेकिन यह काम करता है।

संबंधित मुद्दे