मैं यह लागू करना चाहता हूं कि यह एनोटेशन केवल सार्वजनिक सदस्यों, फ़ील्ड या विधि पर ही रखा जा सकता है। क्या यह संभव है? इस विषय पर मेरे संक्षिप्त शोध ने कहा नहीं।

@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CsvAttribute {
     String columnName();
     int position();
}

मेरा लक्ष्य ट्राइ-कैच ब्लॉक के बिना इसे हासिल करना है। चूंकि मेरे पास वस्तु तक पहुंच है, क्या मैं इसे प्रतिबिंब के बिना कर सकता हूं?

public abstract class CsvExportable {

protected final Map<Integer, String> convertFieldsToMap(){
    final Method[] m = this.getClass().getDeclaredMethods();
    return new ArrayList<>(Arrays.asList(m)).stream()
            .filter(p -> p.isAnnotationPresent(CsvAttribute.class))
            .collect(Collectors.toMap(
                    p -> p.getAnnotation(CsvAttribute.class).position(),
                    p -> this.invokeGetter(p)));
}

private String invokeGetter(Method m){
    try {
        return Objects.toString(m.invoke(this), "");
    } catch (IllegalAccessException | InvocationTargetException e) {
        LOG.error("@CsvAttribute annotation must be placed on public getters!");
        e.printStackTrace();
    }
    return "";
}

}
0
Andrew 27 अप्रैल 2020, 15:12
1
यहां तक ​​​​कि जब एनोटेशन को केवल public सदस्यों पर उपस्थित होने के लिए मजबूर किया जाता है, तो संकलक को यह नहीं पता होता है कि Method हमेशा एक public विधि का प्रतिनिधित्व करेगा। इसलिए वह IllegalAccessException को पकड़ने पर जोर देता रहेगा। इसके अलावा, इससे कोई फर्क नहीं पड़ता कि विधि public है या नहीं, यह अपवाद फेंक सकती है, इसलिए, आपको हमेशा InvocationTargetException को संभालना होगा। दूसरे शब्दों में, वैसे भी ट्राइ-कैच ब्लॉक के आसपास कोई रास्ता नहीं है। वैसे, StringUtils.EMPTY का क्या मतलब है, विशेष रूप से, जब आप स्ट्रेट-फॉरवर्ड "" का उपयोग कर रहे हैं, ठीक उसी तरीके से?
 – 
Holger
29 अप्रैल 2020, 15:44
1
नामांकित स्थिरांक तब उपयोगी होते हैं जब नाम आपको कुछ बताता है, लेकिन तब नहीं जब नाम आपको स्थिरांक से अधिक नहीं बताता है। हर कोई देख सकता है कि "" एक खाली स्ट्रिंग है, इसलिए केवल EMPTY शब्द के साथ एक ही बात कहने से किसी तृतीय पक्ष लाइब्रेरी पर निर्भरता जोड़ने का औचित्य नहीं बनता है। एक अलग कहानी "@CsvAttribute annotation must be placed on public getters!" स्थिरांक होगी, जिसमें निहित धारणा भी शामिल है कि विधि को @CsvAttribute के साथ एनोटेट किया गया है जो invokeGetter विधि के दायरे से बाहर है।
 – 
Holger
12 मई 2020, 12:12
1
मुझे पता है कि विधि केवल उपयुक्त तरीकों के लिए लागू की जाती है, लेकिन यह अभी भी कॉलर की ज़िम्मेदारी है, इसलिए लॉग संदेश कक्षा के दायरे में निरंतर घोषित होने के लिए एक प्राकृतिक उम्मीदवार होगा। वैसे भी, आपकी वास्तविक समस्या के बारे में सोचते हुए, मैं सोच रहा हूँ कि क्या आपने इसके विपरीत माना है; जब आप java.lang.invoke API का उपयोग करते हैं, तो आप इस आवश्यकता को छोड़ सकते हैं कि विधियों को public होना चाहिए।
 – 
Holger
12 मई 2020, 13:12
2
वैसे, new ArrayList<>(Arrays.asList(m)).stream() दो बार अनावश्यक चक्कर लगा रहा है: Arrays.asList(m) के माध्यम से बनाए गए List को ArrayList में कॉपी करने की कोई आवश्यकता नहीं है, जैसा कि Arrays.asList(m).stream() करेंगे। साथ ही, लेकिन आप बिना किसी List के पहले एक Stream भी बना सकते हैं: बस Arrays.stream(m)
 – 
Holger
12 मई 2020, 13:14
1
ठीक है, मैंने अपनी पहली टिप्पणी में यही कहा था, यहां तक ​​​​कि जब आप सार्वजनिक होने के तरीके को लागू करते हैं, तब भी ट्राइ-कैच ब्लॉक रहेगा। लेकिन मैं setAccessible(true) का उपयोग करने के बारे में बात नहीं कर रहा हूं, लेकिन java.lang.invoke एपीआई का उपयोग करने के लिए जो कॉल करने वाले को आवश्यक एक्सेस अधिकारों को उपयोगिता विधि में स्थानांतरित करने की अनुमति देता है, इसलिए अपर्याप्त पहुंच अधिकारों के कारण यह विफल नहीं हो सकता है। एक्सेसर विधियों के लिए Function ऑब्जेक्ट उत्पन्न करने का विकल्प भी है, जो आप प्रति वर्ग केवल एक बार करेंगे, इसलिए बाद के उपयोग के लिए अब ट्राइ कैच ब्लॉक की आवश्यकता नहीं होगी। हालांकि आरंभीकरण अधिक जटिल होगा।
 – 
Holger
12 मई 2020, 13:48

2 जवाब

मेरी जानकारी के लिए नहीं, आप बिना प्रतिबिंब के ऐसा नहीं कर सकते क्योंकि आपको एनोटेशन प्रोसेसिंग करने की आवश्यकता है। फ़ील्ड या विधि सार्वजनिक है या नहीं यह निर्धारित करने के लिए आप संशोधक# isPublic का उपयोग कर सकते हैं। यदि आप बताए गए तरीकों का समर्थन करना चाहते हैं तो आपको ElementType.METHOD का भी उपयोग करना चाहिए।

एक असंबंधित नोट पर, बेझिझक ClassGraph या प्रतिबिंब कुछ प्रतिबिंब एपिस के लिए जो आपके जीवन को आसान बना सकते हैं।

// if a method or field
if (!Modifier.isPublic(method)) {
    throw new IllegalStateException("Modifier must be public.");
}
// if a field
if (!Modifier.isPublic(field)) {
    throw new IllegalStateException("Modifier must be public.");

}
@Target({ ElementType.FIELD, ElementType.METHOD })
1
Jason 27 अप्रैल 2020, 15:45

इसे एनोटेशन में ही कॉन्फ़िगर करना संभव नहीं है, लेकिन यदि आपके पास एक है तो आप इसे अपने कंपाइल टाइम एनोटेशन प्रोसेसर में कर सकते हैं। यदि एनोटेटेड तत्व मान्य नहीं है तो बस एक अपवाद फेंक दें।

यदि आप केवल रनटाइम पर एनोटेशन संसाधित कर रहे हैं, तो इससे बहुत मदद नहीं मिलेगी। आप एक रनटाइम अपवाद को ट्रिगर कर सकते हैं, लेकिन कोई संकलन त्रुटि नहीं।

1
Jorn 27 अप्रैल 2020, 16:25
उत्तर के लिए धन्यवाद। क्या आप किसी भी मौके से जानते हैं कि लोम्बोक (और इसी तरह के पुस्तकालय) इसे कैसे हल करते हैं? ऐसा लगता है कि वे बॉयलरप्लेट कोड उत्पन्न करने के लिए संकलन के दौरान एनोटेशन संसाधित कर रहे हैं।
 – 
Andrew
9 अगस्त 2021, 18:27
हाँ, लोम्बोक संकलन समय पर एनोटेशन प्रोसेसिंग करता है। यह संकलन के दौरान बहुत अधिक, गैर-आधिकारिक तौर पर समर्थित चीजें भी करता है। और भी बहुत से प्रोजेक्ट हैं जो उनके एनोटेशन प्रोसेसिंग में बहुत आसान हैं, जैसे Google Auto
 – 
Jorn
9 अगस्त 2021, 18:58