Hibernate HQL sonuçlarıyla tür güvenlik uyarılarından nasıl kaçınılır?


105

Örneğin böyle bir sorgum var:

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

Böyle bir şey yapmaya çalışırsam şu uyarıyı gösterir

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


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

Bundan kaçınmanın bir yolu var mı?


11
JPA ile, türü createQuery'ye ekleyerek yazım güvenli sorgulara sahip olabileceğinizi belirtmek gerekir.
Elazar Leibovich

5
Biraz geç ama sess.createQuery("from Cat cat", Cat.class);Elazar'ın dediği gibi.
Dominik Mohr

Yanıtlar:


99

@SuppressWarningsHer aradığınızda biraz parmakla yazmayı gerektirse de, önerildiği gibi her yerde kullanmak bunu yapmanın iyi bir yoludur q.list().

Önereceğim iki teknik daha var:

Yardımcı yaz

Basitçe, tüm bilgilerinizi @SuppressWarningstek bir yerde yeniden düzenleyin :

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

...

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

Eclipse'in kaçınılmaz sorunlar için uyarılar oluşturmasını önleyin

Eclipse'de Pencere> Tercihler> Java> Derleyici> Hatalar / Uyarılar'a gidin ve Genel tür altında onay kutusunu seçin Ignore unavoidable generic type problems due to raw APIs

Bu, yukarıda açıklanan gibi kaçınılmaz olan benzer sorunlar için gereksiz uyarıları kapatacaktır.

Bazı yorumlar:

  • QuerySonuç yerine geçmeyi seçtim q.list()çünkü bu şekilde bu "hile" yöntemi sadece Hibernate ile hile yapmak için kullanılabilir ve Listgenel olarak herhangi bir hile yapmak için kullanılamaz .
  • .iterate()Vb için benzer yöntemler ekleyebilirsiniz .

20
İlk bakışta, Collections.checkedList (Collection <E>, Class <E>) yöntemi mükemmel bir çözüm gibi görünüyor. Bununla birlikte, javadoc, yalnızca yanlış yazılmış öğelerin yöntemin oluşturduğu tür güvenli görünüm aracılığıyla eklenmesini engellediğini söyler. Verilen listede hiçbir kontrol yapılmaz.
phatblat

11
"List <Cat> list = Collections.checkedList (q.list (), Cat.class);" Eclipse'de hala "@SuppressWarnings" gerektirir. Diğer ipucu hakkında: "listAndCast" yazmak, Eclipse aracılığıyla otomatik olarak eklenen "@SuppressWarnings" den daha kısa değildir.
Tristan

2
BTW, Collections.checkedList()yöntem kontrol edilmeyen atama uyarısını bastırmayacaktır.
Diablo

39

Soru sorulalı uzun zaman oldu ama umarım cevabım benim gibi birine yardımcı olur.

Javax.persistence api belgelerine bir göz atarsanız , o zamandan beri oraya yeni yöntemlerin eklendiğini göreceksiniz Java Persistence 2.0. Bunlardan biri createQuery(String, Class<T>)geri dönen TypedQuery<T>. Sen kullanabilirsiniz TypedQuerysen bunu yaptığı gibi Querytüm işlemler artık tip güvenli olmasını o küçük bir farkla.

Öyleyse, kodunuzu şu şekilde değiştirin:

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

Ve hepiniz hazırsınız.


1
Soru JPA ile ilgili değil
Mathijs Segers

2
Hibernate'in son sürümleri JPA 2.x'i uygular, bu nedenle bu yanıt önemlidir.
caspinos

TypedQuery <T> en iyi senaryodur.
Muneeb Mirza

21

Biz de kullanıyoruz @SuppressWarnings("unchecked"), ancak çoğu zaman onu bir bütün olarak yöntemde değil, yalnızca değişkenin bildiriminde kullanmaya çalışıyoruz:

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

15

TypedQueryBunun yerine kullanmayı deneyin Query. Örneğin bunun yerine: -

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

Bunu kullan:-

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

1
CriteriaYine de bunu yapmanın bir yolu var mı ?
Stealth Rabbi

5

Kodumuzda çağırma yöntemlerini şu şekilde açıklıyoruz:

@SuppressWarnings ("kontrol edilmemiş")

Bunun bir hack gibi göründüğünü biliyorum, ancak bir ortak geliştirici yakın zamanda kontrol etti ve yapabileceğimizin tek şey olduğunu gördü.


5

Görünüşe göre, Hazırda Bekletme API'sindeki Query.list () yöntemi "tasarım gereği" güvenli değildir ve bunu değiştirme planları yoktur .

Derleyici uyarılarından kaçınmanın en basit çözümünün @SuppressWarnings ("kontrol edilmemiş") eklemek olduğuna inanıyorum. Bu açıklama , yöntem düzeyinde veya bir yöntemin içindeyse, değişken bildiriminden hemen önce yerleştirilebilir.

Query.list () 'i kapsülleyen ve List (veya Collection) döndüren bir yönteminiz varsa, ayrıca bir uyarı alırsınız. Ancak bu, @SuppressWarnings ("rawtypes") kullanılarak bastırılır.

Matt Quail tarafından önerilen listAndCast (Query) yöntemi, Query.list () 'den daha az esnektir. Ben yapabiliyorken:

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

Aşağıdaki kodu denersem:

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

Bir derleme hatası alacağım: Tür uyuşmazlığı: Listeden ArrayList'e dönüştürülemiyor


1
"onu değiştirmeye yönelik bir plan yok." - bu 2005'ten bir yazı. O zamandan beri işler değişmemiş olsaydı şaşırırdım.
Rup

4

Bu bir gözetim ya da hata değil. Uyarı gerçek bir temel sorunu yansıtır - java derleyicisinin hazırda bekletme sınıfının işini düzgün bir şekilde yapacağından ve döndürdüğü listenin yalnızca Kediler içereceğinden gerçekten emin olmasının hiçbir yolu yoktur. Buradaki önerilerden herhangi biri uygundur.


2

Hayır, ancak bunu belirli sorgu yöntemlerine ayırabilir ve uyarıları bir @SuppressWarnings("unchecked")ek açıklamayla bastırabilirsiniz .


Yanlış ... Joe Dean haklı, kullanabilir misin? uyarılardan kaçınmak için jenerik tür olarak ...
Mike Stone

1
Bu doğru değil. Bir Liste <?> Kullanırsanız, listenin öğelerini, gereksiz bir yinelenen liste oluşturma ve her öğeyi yayınlama adımı olmadan Cat'inki gibi kullanamazsınız.
Dave L.

Pekala, sonuçları doğrudan döküm yoluyla kullanırsanız, listeyi oluşturmanıza gerek yoktur ve soru "bundan kaçınmanın bir yolu var mı" idi, cevap kesinlikle EVET'tir (bastırma uyarıları olmasa bile)
Mike Stone

2

Hibernate'in daha yeni sürümleri artık güvenli bir Query<T>nesneyi destekliyor, bu nedenle artık @SuppressWarningsderleyici uyarılarını ortadan kaldırmak için bazı hackler kullanmak veya uygulamak zorunda değilsiniz . In Oturum API , Session.createQueryşimdi bir tür güvenli dönecektir Query<T>nesneyi. Bunu şu şekilde kullanabilirsiniz:

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

Ayrıca, sorgu sonucu bir Cat döndürmediğinde de kullanabilirsiniz:

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

Veya kısmi bir seçim yaparken:

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

1

Aynı problemimiz vardı. Ancak bu bizim için büyük bir mesele değildi çünkü daha büyük sorunları Hazırda Bekletme Sorgusu ve Oturumu ile çözmemiz gerekiyordu.

Özellikle:

  1. bir işlemin ne zaman yapılabileceğini kontrol edin. (Bir tx'in kaç kez "başlatıldığını" saymak istedik ve yalnızca tx başladığında aynı sayıda "bittiğinde" kesinleştirme istedik. Bir işlem başlatması gerekip gerekmediğini bilmeyen kod için kullanışlıdır. Şimdi tx gerektiren herhangi bir kod, birini "başlatır" ve bittiğinde onu bitirir.)
  2. Performans ölçütlerinin toplanması.
  3. Bir şeyin gerçekten yapılacağı bilinene kadar işlemin başlatılmasını geciktirmek.
  4. Query.uniqueResult () için daha nazik davranış

Yani bizim için bizde:

  1. Sorguyu genişleten bir arayüz (AmplafiQuery) oluşturun
  2. AmplafiQuery'yi genişleten ve bir org.hibernate.Query'yi saran bir sınıf (AmplafiQueryImpl) oluşturun
  3. Bir Tx döndüren bir Txmanager oluşturun.
  4. Tx, çeşitli createQuery yöntemlerine sahiptir ve AmplafiQueryImpl döndürür

Ve son olarak,

AmplafiQuery, Query.list () 'in genel olarak etkinleştirilmiş bir sürümü olan bir "asList ()" içerir. AmplafiQuery, Query.uniqueResult ()' un genel etkin bir sürümü olan "benzersiz ()" e sahiptir (ve yalnızca bir istisna)

Bu, @SuppressWarnings'den kaçınmak için çok fazla çalışma. Ancak, dediğim (ve listelediğim) gibi daha iyi olan birçok şey var! sarma işi yapmak için nedenler.


0

Bunun daha eski olduğunu biliyorum, ancak Matt Quails Answer'da bugün itibariyle not edilmesi gereken 2 nokta.

1. Nokta

Bu

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

Bu olmalı

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

2. Nokta

Bundan

List list = q.list();

buna

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

diğer uyarıları azaltacaktı, tabii ki orijinal yanıt etiketi işaretçileri tarayıcı tarafından kaldırıldı.


Cevapları başka bir cevaba değil, soruya cevap vermeye çalışın. Matt Quail'in cevabına güncel olmadığını söylemek için bir yorum eklemek sorun değil, ancak cevabınızı tamamen ve doğru bir şekilde yazın.
Cory Kendall

-1

Bunu dene:

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

4
Bu Joe Dean'in cevabının kötü bir kopyası , çünkü catörnekle hala bir şeyler yapmanız gerekiyor .
Artjom B.

-1

Hazırda bekletme sorgusuyla tür güvenlik uyarılarından kaçınmak için iyi bir çözüm, tür güvenli hql oluşturmanıza yardımcı olacak TorpedoQuery gibi bir araç kullanmaktır .

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
Lütfen çözümünüzün nasıl çalıştığı hakkında güzel bir açıklama sağlamaya çalışın. Bakınız: Nasıl iyi bir cevap yazabilirim? . Teşekkürler.
Shree

1
Başkalarının ondan öğrenebileceği şekilde kodunuza bir açıklama ekleyebilir misiniz?
Nico Haase

-6

@SuppressWarnings ("işaretlenmemiş") kullanmak istemiyorsanız, aşağıdakileri yapabilirsiniz.

   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);
    }

Bilginize - Bunu benim için yapan bir kullanım yöntemi yarattım, böylece kodumu kirletmiyor ve @SupressWarning kullanmak zorunda kalmıyorum.


2
Bu çok aptalca. Tamamen derleyici ile ilgili bir sorunun üstesinden gelmek için çalışma zamanı ek yükü ekliyorsunuz. Tür bağımsız değişkenlerinin somutlaştırılmadığını, dolayısıyla türün çalışma zamanı denetimi olmadığını unutmayın.
John Nilsson

Kabul edildi, eğer yine de böyle bir şey yapmak istiyorsanız, şu şekilde çalışma zamanı denetimi ekleyebilirsiniz: List <Cat> cats = Collections.checkedList (new ArrayList <Cat> (), Cat.class); cats.addAll (q.list ()); Bu çalışmalı.
ddcruver
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.