110

For example I have such query:

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

If I try to make something like this it shows the following warning

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


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

Is there a way to avoid it?

Dhaval Solanki
  • 4,589
  • 1
  • 23
  • 39
serg
  • 109,619
  • 77
  • 317
  • 330

15 Answers15

101

Using @SuppressWarnings everywhere, as suggested, is a good way to do it, though it does involve a bit of finger typing each time you call q.list().

There are two other techniques I'd suggest:

Write a cast-helper

Simply refactor all your @SuppressWarnings into one place:

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

...

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

Prevent Eclipse from generating warnings for unavoidable problems

In Eclipse, go to Window>Preferences>Java>Compiler>Errors/Warnings and under Generic type, select the checkbox Ignore unavoidable generic type problems due to raw APIs

This will turn off unnecessary warnings for similar problems like the one described above which are unavoidable.

Some comments:

  • I chose to pass in the Query instead of the result of q.list() because that way this "cheating" method can only be used to cheat with Hibernate, and not for cheating any List in general.
  • You could add similar methods for .iterate() etc.
nikodaemus
  • 1,918
  • 3
  • 21
  • 32
Matt Quail
  • 6,189
  • 2
  • 23
  • 20
  • 20
    At first glance, the Collections.checkedList(Collection,Class) method looks like the perfect solution. However, the javadoc says that it only prevents incorrectly typed elements from being added through the typesafe view that the method generates. No checking is done on the given list. – phatblat Oct 07 '09 at 18:20
  • 11
    "List list = Collections.checkedList(q.list(), Cat.class);" still requires a "@SuppressWarnings" in Eclipse. About the other tip : typing "listAndCast" is not really shorter than "@SuppressWarnings" which is added automatically via Eclipse. – Tristan Jul 29 '11 at 07:46
  • 2
    BTW, `Collections.checkedList()` method will not suprpress the unchecked assignment warning. – Diablo Sep 09 '16 at 12:55
45

It is been a long time since the question was asked but I hope my answer might be helpful to someone like me.

If you take a look at javax.persistence api docs, you will see that some new methods have been added there since Java Persistence 2.0. One of them is createQuery(String, Class<T>) which returns TypedQuery<T>. You can use TypedQuery just as you did it with Query with that small difference that all operations are type safe now.

So, just change your code to smth like this:

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

And you are all set.

antonpp
  • 2,333
  • 23
  • 28
21

We use @SuppressWarnings("unchecked") as well, but we most often try to use it only on the declaration of the variable, not on the method as a whole:

public List<Cat> findAll() {
    Query q = sess.createQuery("from Cat cat");
    @SuppressWarnings("unchecked")
    List<Cat> cats = q.list();
    return cats;
}
cretzel
  • 19,864
  • 19
  • 58
  • 71
17

Try to use TypedQuery instead of Query. For example instead of this:-

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

Use this:-

TypedQuery<Cat> q1 = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q1.list();
CubeJockey
  • 2,209
  • 8
  • 24
  • 31
shivam oberoi
  • 237
  • 4
  • 8
5

In our code we annotate the calling methods with:

@SuppressWarnings("unchecked")

I know it seems like a hack, but a co-developer checked recently and found that was all we could do.

tyshock
  • 1,333
  • 8
  • 13
5

Apparently, the Query.list() method in the Hibernate API is not type safe "by design", and there are no plans to change it.

I believe the simplest solution to avoid compiler warnings is indeed to add @SuppressWarnings("unchecked"). This annotation can be placed at the method level or, if inside a method, right before a variable declaration.

In case you have a method that encapsulates Query.list() and returns List (or Collection), you also get a warning. But this one is suppressed using @SuppressWarnings("rawtypes").

The listAndCast(Query) method proposed by Matt Quail is less flexible than Query.list(). While I can do:

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

If I try the code below:

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

I'll get a compile error: Type mismatch: cannot convert from List to ArrayList

Community
  • 1
  • 1
Paulo Merson
  • 13,270
  • 8
  • 79
  • 72
  • 1
    "there are no plans to change it." - that's a post from 2005. I'd be surprised if things hadn't changed since then. – Rup Dec 05 '12 at 19:29
4

It's not an oversight or a mistake. The warning reflects a real underlying problem - there is no way that the java compiler can really be sure that the hibernate class is going to do its job properly and that the list it returns will only contain Cats. Any of the suggestions here is fine.

Pang
  • 9,564
  • 146
  • 81
  • 122
paulmurray
  • 3,355
  • 1
  • 22
  • 17
2

No, but you can isolate it into specific query methods and suppress the warnings with a @SuppressWarnings("unchecked") annotation.

Dave L.
  • 43,907
  • 11
  • 63
  • 62
  • Wrong... Joe Dean is right, you can use the ? as the generic type to avoid the warnings... – Mike Stone Sep 22 '08 at 16:40
  • 1
    That's not true. If you use a List> then you cannot use the elements of the list as Cat's without the unnecessary step of creating a duplicate list and casting each item. – Dave L. Sep 22 '08 at 16:52
  • well, if you use the results directly via casting you don't need to create the list, and regardless, the question was "is there a way to avoid it", the answer is most definitely YES (even without supress warnings) – Mike Stone Sep 22 '08 at 17:36
2

Newer versions of Hibernate now support a type safe Query<T> object so you no longer have to use @SuppressWarnings or implement some hack to make the compiler warnings go away. In the Session API, Session.createQuery will now return a type safe Query<T> object. You can use it this way:

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

You can also use it when the query result won't return a Cat:

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

Or when doing a partial select:

public List<Object[]> String getName() {
    Query<Object[]> query = sessionFactory.getCurrentSession().createQuery("SELECT id, name FROM Cat", Object[].class);
    return query.list();
}
David DeMar
  • 2,390
  • 2
  • 32
  • 45
1

We had same problem. But it wasn't a big deal for us because we had to solve other more major issues with Hibernate Query and Session.

Specifically:

  1. control when a transaction could be committed. (we wanted to count how many times a tx was "started" and only commit when the tx was "ended" the same number of times it was started. Useful for code that doesn't know if it needs to start a transaction. Now any code that needs a tx just "starts" one and ends it when done.)
  2. Performance metrics gathering.
  3. Delaying starting the transaction until it is known that something will actually be done.
  4. More gentle behavior for query.uniqueResult()

So for us, we have:

  1. Create an interface (AmplafiQuery) that extends Query
  2. Create a class (AmplafiQueryImpl) that extends AmplafiQuery and wraps a org.hibernate.Query
  3. Create a Txmanager that returns a Tx.
  4. Tx has the various createQuery methods and returns AmplafiQueryImpl

And lastly,

AmplafiQuery has a "asList()" that is a generic enabled version of Query.list() AmplafiQuery has a "unique()" that is a generic enabled version of Query.uniqueResult() ( and just logs an issue rather than throwing an exception)

This is a lot of work for just avoiding @SuppressWarnings. However, like I said (and listed) there are lots of other better! reasons to do the wrapping work.

Pat
  • 5,761
  • 5
  • 34
  • 50
0

I know this is older but 2 points to note as of today in Matt Quails Answer.

Point 1

This

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

Should be this

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

Point 2

From this

List list = q.list();

to this

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

would reduce other warnings obviously in original reply tag markers were stripped by the browser.

dldnh
  • 8,923
  • 3
  • 40
  • 52
Tony Shih
  • 430
  • 5
  • 6
  • Try to make answers a response to the question, not a response to another answer. It's fine to include a comment on Matt Quail's answer to say he's out of date, but just write your answer purely and correctly. – Cory Kendall Oct 26 '12 at 06:58
-1

Try this:

Query q = sess.createQuery("from Cat cat");
List<?> results = q.list();
for (Object obj : results) {
    Cat cat = (Cat) obj;
}
  • 4
    This is a bad copy of [Joe Dean's answer](http://stackoverflow.com/a/115952/1816580), because you still have to do something with the `cat` instance. – Artjom B. Jul 15 '14 at 22:19
-1

A good solution to avoid type safety warnings with hibernate query is to use a tool like TorpedoQuery to help you to build type safe hql.

Cat cat = from(Cat.class);
org.torpedoquery.jpa.Query<Entity> select = select(cat);
List<Cat> cats = select.list(entityManager);
xjodoin
  • 519
  • 5
  • 15
-1
TypedQuery<EntityName> createQuery = entityManager.createQuery("from EntityName", EntityName.class);
List<EntityName> resultList = createQuery.getResultList();
  • 3
    Please try to provide a nice description about how your solution works. See: [How do I write a good answer?](https://stackoverflow.com/help/how-to-answer). Thanks. – 4b0 Sep 17 '18 at 05:56
  • 1
    Can you add some explanation to you code such that others can learn from it? – Nico Haase Nov 19 '18 at 10:16
-6

If you don't want to use @SuppressWarnings("unchecked") you can do the following.

   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 - I created a util method that does this for me so it doesn't litter my code and I don't have to use @SupressWarning.

Joe Dean
  • 3,356
  • 5
  • 26
  • 31
  • 2
    That just stupid. You're adding runtime overhead to overcome a completely compiler related problem. Remember that type arguments aren't reified so there is no runtime checking of the type. – John Nilsson Oct 17 '08 at 22:06
  • Agreed, if you still wanted to do something like this you could add runtime checking of type with: List cats = Collections.checkedList(new ArrayList(), Cat.class); cats.addAll(q.list()); This should work. – ddcruver Nov 30 '10 at 16:52