हाइबरनेट HQL परिणामों के साथ सुरक्षा चेतावनी से कैसे बचें?


105

उदाहरण के लिए मेरे पास ऐसी क्वेरी है:

Query q = sess.createQuery("from Cat cat");
List cats = q.list();

अगर मैं ऐसा कुछ बनाने की कोशिश करता हूं तो यह निम्न चेतावनी दिखाता है

Type safety: The expression of type List needs unchecked conversion to conform to List<Cat>


List<Cat> cats = q.list();

क्या इससे बचने का कोई तरीका है?


11
यह ध्यान देने योग्य है कि जेपीए के साथ आप टाइप क्विक को बना सकते हैं, टाइप करने के लिए createQuery को जोड़कर।
एलज़ार लीबोविच

5
थोड़ा देर से लेकिन sess.createQuery("from Cat cat", Cat.class);जैसा कि एलज़ार ने उल्लेख किया है।
डोमिनिक मोहर

जवाबों:


99

@SuppressWarningsहर जगह, जैसा कि सुझाव दिया गया है, इसका उपयोग करना एक अच्छा तरीका है, हालांकि इसमें आपके द्वारा कॉल करने पर हर बार उंगली टाइप करना शामिल है q.list()

दो अन्य तकनीकें हैं जिनका मैं सुझाव दूंगा:

कास्ट-हेल्पर लिखें

बस अपने सभी @SuppressWarningsको एक जगह पर रिफ्लेक्टर करें :

List<Cat> cats = MyHibernateUtils.listAndCast(q);

...

public static <T> List<T> listAndCast(Query q) {
    @SuppressWarnings("unchecked")
    List list = q.list();
    return list;
}

अपरिहार्य समस्याओं के लिए चेतावनी उत्पन्न करने से ग्रहण को रोकें

ग्रहण में, विंडो पर जाएं> प्राथमिकताएं> जावा> कंपाइलर> त्रुटियां / चेतावनी और सामान्य प्रकार के तहत, चेकबॉक्स चुनें Ignore unavoidable generic type problems due to raw APIs

यह ऊपर बताई गई समस्याओं के समान अनावश्यक चेतावनी को बंद कर देगा, जो कि अपरिहार्य हैं।

कुछ टिप्पणियां:

  • मैंने Queryइसके परिणाम के बजाय पास होने का विकल्प चुना q.list()क्योंकि इस "धोखा" पद्धति का उपयोग केवल हाइबरनेट के साथ धोखा देने के लिए किया जा सकता है, और Listसामान्य रूप से किसी को धोखा देने के लिए नहीं ।
  • आप इसके लिए समान तरीके जोड़ सकते हैं .iterate()आदि।

20
पहली नज़र में, Collections.checkedList (संग्रह <E>, कक्षा <E>) विधि सही समाधान की तरह दिखती है। हालांकि, javadoc का कहना है कि यह केवल गलत तरीके से टाइप किए गए तत्वों को उस प्रकार के दृश्य के माध्यम से जोड़े जाने से रोकता है जो विधि उत्पन्न करता है। दी गई सूची पर कोई जाँच नहीं की जाती है।
फतबल

11
"सूची <कैट> सूची = संग्रह। चेकडिस्टलिस्ट (क्यू.लिस्ट (), कैट.क्लास);" अभी भी ग्रहण में "@SuppressWarnings" की आवश्यकता है। अन्य टिप के बारे में: "listAndCast" टाइप करना वास्तव में "@SuppressWarnings" से छोटा नहीं है जो कि ग्रहण के माध्यम से स्वचालित रूप से जोड़ा जाता है।
ट्रिस्टन

2
BTW, Collections.checkedList()विधि अनियंत्रित असाइनमेंट चेतावनी को दबाएगी नहीं।
डियाब्लो

39

प्रश्न पूछे जाने में काफी समय हो गया है, लेकिन मुझे आशा है कि मेरा उत्तर मेरे जैसे किसी व्यक्ति के लिए मददगार हो सकता है।

यदि आप javax.persistence api डॉक्स पर एक नज़र डालते हैं , तो आप देखेंगे कि वहाँ कुछ नए तरीके जोड़े गए हैं Java Persistence 2.0। उनमें से एक है createQuery(String, Class<T>)जो रिटर्न करता है TypedQuery<T>। आप इसका उपयोग कर सकते हैं TypedQueryजैसा कि आपने इसे Queryउस छोटे अंतर के साथ किया था कि सभी ऑपरेशन अब सुरक्षित हैं।

तो, इस तरह से अपने कोड को बदल दें:

Query q = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q.list();

और आप सब सेट हैं।


1
प्रश्न JPA
Mathijs Segers

2
हाइबरनेट के हाल के संस्करण जेपीए 2.x को लागू करते हैं, इसलिए यह उत्तर प्रासंगिक है।
कैसपीनो

टाइपेडिक्यू <टी> सबसे अच्छा परिदृश्य है।
मुनीब मिर्जा

21

हम भी उपयोग @SuppressWarnings("unchecked")करते हैं, लेकिन हम अक्सर इसे केवल चर की घोषणा पर उपयोग करने की कोशिश करते हैं, न कि पूरी विधि के रूप में:

public List<Cat> findAll() {
    Query q = sess.createQuery("from Cat cat");
    @SuppressWarnings("unchecked")
    List<Cat> cats = q.list();
    return cats;
}

15

के TypedQueryबजाय उपयोग करने का प्रयास करें Query। इसके बजाय उदाहरण के लिए: -

Query q = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q.list();

इसे इस्तेमाल करो:-

TypedQuery<Cat> q1 = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q1.list();

1
Criteriaहालांकि इसके साथ ऐसा करने का कोई तरीका है ?
चुपके रब्बी

5

हमारे कोड में हम कॉलिंग विधियों को एनोटेट करते हैं:

@SuppressWarnings ( "अनियंत्रित")

मुझे पता है कि यह एक हैक की तरह लगता है, लेकिन एक सह-डेवलपर ने हाल ही में जाँच की और पाया कि यह सब हम कर सकते थे।


5

जाहिर है, हाइबरनेट एपीआई में Query.list () विधि "डिजाइन द्वारा" सुरक्षित नहीं है, और इसे बदलने की कोई योजना नहीं है

मेरा मानना ​​है कि कंपाइलर चेतावनियों से बचने का सबसे सरल उपाय वास्तव में @SuppressWarnings ("अनियंत्रित") जोड़ना है। इस एनोटेशन को विधि स्तर पर रखा जा सकता है या, यदि किसी विधि के अंदर, चर घोषणा से ठीक पहले।

यदि आपके पास एक विधि है जो Query.list () को वापस लाती है और सूची (या संग्रह) लौटाती है, तो आपको एक चेतावनी भी मिलती है। लेकिन यह @SuppressWarnings ("rawtypes") का उपयोग करके दबा दिया गया है।

मैट क्वाइल द्वारा प्रस्तावित लिस्टएंडकैस्ट (क्वेरी) विधि Query.list () से कम लचीली है। जबकि मैं कर सकता हूँ:

Query q = sess.createQuery("from Cat cat");
ArrayList cats = q.list();

अगर मैं नीचे दिए गए कोड को आज़माऊं:

Query q = sess.createQuery("from Cat cat");
ArrayList<Cat> cats = MyHibernateUtils.listAndCast(q);

मुझे एक संकलित त्रुटि मिलेगी: प्रकार बेमेल: सूची से ArrayList में परिवर्तित नहीं कर सकता


1
"इसे बदलने की कोई योजना नहीं है।" - यह 2005 से एक पोस्ट है। मुझे आश्चर्य होगा अगर चीजें तब से बदल नहीं गई थीं।
Rup

4

यह एक निरीक्षण या एक गलती नहीं है। चेतावनी एक वास्तविक अंतर्निहित समस्या को दर्शाती है - कोई रास्ता नहीं है कि जावा कंपाइलर वास्तव में यह सुनिश्चित कर सकता है कि हाइबरनेट वर्ग यह ठीक से काम करने जा रहा है और जो सूची इसे लौटाती है उसमें केवल बिल्लियाँ होंगी। यहाँ कोई भी सुझाव ठीक है।


2

नहीं, लेकिन आप इसे विशिष्ट क्वेरी विधियों में अलग कर सकते हैं और @SuppressWarnings("unchecked")एनोटेशन के साथ चेतावनियों को दबा सकते हैं।


गलत ... जो डीन सही है, आप का उपयोग कर सकते हैं? चेतावनियों से बचने के लिए सामान्य प्रकार के रूप में ...
माइक स्टोन

1
यह सच नहीं है। यदि आप एक सूची का उपयोग करते हैं <?> तो आप कैट के रूप में सूची के तत्वों का उपयोग नहीं कर सकते हैं बिना डुप्लिकेट सूची बनाने और उनके आइटम को कास्टिंग के अनावश्यक कदम के बिना।
डेव एल।

ठीक है, अगर आप सीधे कास्टिंग के माध्यम से परिणामों का उपयोग करते हैं, तो आपको सूची बनाने की आवश्यकता नहीं है, और इसकी परवाह किए बिना, सवाल था "क्या इससे बचने का एक तरीका है", इसका जवाब सबसे निश्चित रूप से हां (यहां तक ​​कि बिना किसी चेतावनी के) है
माइक पत्थर का

2

हाइबरनेट के नए संस्करण अब एक प्रकार की सुरक्षित Query<T>वस्तु का समर्थन करते हैं ताकि आपको @SuppressWarningsसंकलक चेतावनी को दूर करने के लिए कुछ हैक का उपयोग या क्रियान्वित न करना पड़े । में सत्र एपीआई , Session.createQueryअब एक प्रकार सुरक्षित वापस आ जाएगी Query<T>वस्तु। आप इसे इस तरह से उपयोग कर सकते हैं:

Query<Cat> query = session.createQuery("FROM Cat", Cat.class);
List<Cat> cats = query.list();

जब क्वेरी परिणाम एक कैट नहीं लौटाएगा तो आप इसका उपयोग भी कर सकते हैं:

public Integer count() {
    Query<Integer> query = sessionFactory.getCurrentSession().createQuery("SELECT COUNT(id) FROM Cat", Integer.class);
    return query.getSingleResult();
}

या आंशिक चयन करते समय:

public List<Object[]> String getName() {
    Query<Object[]> query = sessionFactory.getCurrentSession().createQuery("SELECT id, name FROM Cat", Object[].class);
    return query.list();
}

1

हमारी भी यही समस्या थी। लेकिन यह हमारे लिए कोई बड़ी बात नहीं थी क्योंकि हमें हाइबरनेट क्वेरी और सत्र के साथ अन्य अधिक प्रमुख मुद्दों को हल करना था।

विशेष रूप से:

  1. नियंत्रण जब एक लेनदेन प्रतिबद्ध हो सकता है। (हम गिनना चाहते थे कि कितनी बार एक tx "शुरू" हुआ था और केवल उसी समय प्रतिबद्ध था जब tx को "जितनी बार" शुरू किया गया था उसी समय समाप्त कर दिया गया था। कोड के लिए उपयोगी जिसे पता नहीं है कि क्या उसे लेनदेन शुरू करने की आवश्यकता है। अब कोई भी कोड जिसे tx की आवश्यकता होती है, वह "एक" शुरू करता है और जब किया जाता है, तब इसे समाप्त करता है।
  2. प्रदर्शन मेट्रिक्स सभा।
  3. लेन-देन शुरू करने में देरी जब तक यह पता नहीं चलता कि वास्तव में कुछ किया जाएगा।
  4. Query.uniqueResult () के लिए और अधिक कोमल व्यवहार

तो हमारे लिए, हमारे पास है:

  1. एक इंटरफ़ेस (AmplafiQuery) बनाएँ जो क्वेरी का विस्तार करता है
  2. एक वर्ग (AmplafiQueryImpl) बनाएँ जो AmplafiQuery का विस्तार करता है और एक org.hiberbate.Query लपेटता है
  3. एक Txmanager बनाएँ जो एक Tx देता है।
  4. Tx के पास विभिन्न createQuery तरीके हैं और AmplafiQueryImpl देता है

और अंत में,

AmplafiQuery में एक "asList ()" है जो Query.list का एक सामान्य सक्षम संस्करण है () (AmplafiQuery में एक "अनूठा ()" है जो Query.uniqueResult () का एक सामान्य सक्षम संस्करण है (और केवल एक फेंकने के बजाय किसी समस्या को लॉग करता है) अपवाद)

यह @SuppressWarnings से बचने के लिए बहुत काम है। हालाँकि, जैसा मैंने कहा (और सूचीबद्ध) बहुत सारे अन्य बेहतर हैं! रैपिंग कार्य करने के लिए कारण।


0

मुझे पता है कि यह पुराना है लेकिन आज के मैट कॉल्स उत्तर में ध्यान देने योग्य 2 बिंदु हैं।

बिंदु 1

यह

List<Cat> cats = Collections.checkedList(Cat.class, q.list());

यह होना चाहिए

List<Cat> cats = Collections.checkedList(q.list(), Cat.class);

बिंदु 2

इस से

List list = q.list();

इसके लिए

List<T> list = q.list();

स्पष्ट रूप से अन्य चेतावनियों को कम करेगा मूल उत्तर टैग मार्करों में ब्राउज़र द्वारा छीन लिए गए थे।


सवाल के जवाब की कोशिश करें, दूसरे जवाब की प्रतिक्रिया नहीं। यह कहने के लिए कि वह आउट ऑफ डेट है, मैट क्वेल के उत्तर पर एक टिप्पणी शामिल करना ठीक है, लेकिन बस अपना उत्तर शुद्ध और सही तरीके से लिखें।
कोरी केंडल


-1

हाइबरनेट क्वेरी के साथ प्रकार की सुरक्षा चेतावनियों से बचने का एक अच्छा उपाय यह है कि आप टॉरपीडो की तरह एक टूल का उपयोग करें ताकि आप सुरक्षित एचक्यूएल का निर्माण कर सकें।

Cat cat = from(Cat.class);
org.torpedoquery.jpa.Query<Entity> select = select(cat);
List<Cat> cats = select.list(entityManager);

-1
TypedQuery<EntityName> createQuery = entityManager.createQuery("from EntityName", EntityName.class);
List<EntityName> resultList = createQuery.getResultList();

3
कृपया अपने समाधान के बारे में एक अच्छा विवरण प्रदान करने का प्रयास करें। देखें: मैं एक अच्छा उत्तर कैसे लिखूं? । धन्यवाद।
श्री

1
क्या आप अपने लिए कुछ स्पष्टीकरण जोड़ सकते हैं जैसे कि अन्य लोग इससे सीख सकते हैं?
निको हसे

-6

यदि आप @SuppressWarnings ("अनियंत्रित") का उपयोग नहीं करना चाहते हैं, तो आप निम्न कार्य कर सकते हैं।

   Query q = sess.createQuery("from Cat cat");
   List<?> results =(List<?>) q.list();
   List<Cat> cats = new ArrayList<Cat>();
   for(Object result:results) {
       Cat cat = (Cat) result;
       cats.add(cat);
    }

FYI करें - मैंने एक उपयोग विधि बनाई है जो मेरे लिए ऐसा करती है ताकि यह मेरे कोड को लेट न करे और मुझे @SupressWarning का उपयोग न करना पड़े।


2
वह सिर्फ बेवकूफ है। आप पूरी तरह से कंपाइलर संबंधित समस्या को दूर करने के लिए रनटाइम ओवरहेड जोड़ रहे हैं। याद रखें कि टाइप आर्ग्युमेंट्स का पुनरीक्षण नहीं किया जाता है, इसलिए टाइप की कोई रनटाइम जाँच नहीं होती है।
जॉन निल्सन

सहमत, अगर आप अभी भी ऐसा कुछ करना चाहते हैं, तो आप टाइप के साथ रनटाइम चेकिंग को जोड़ सकते हैं: सूची <कैट> बिल्लियों = संग्रह। चेकडेलिस्ट (नया एरियरिस्ट <कैट> (), कैट.क्लास); cats.addAll (q.list ()); यह काम करना चाहिए।
ddcruver
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.