What is the "proper" way to cast Hibernate Query.list() to List<Type>?

JavaHibernateGenerics

Java Problem Overview


I'm a newbie with Hibernate, and I'm writing a simple method to return a list of objects matching a specific filter. List<Foo> seemed a natural return type.

Whatever I do, I can't seem to make the compiler happy, unless I employ an ugly @SuppressWarnings.

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class Foo {

    public Session acquireSession() {
        // All DB opening, connection etc. removed,
        // since the problem is in compilation, not at runtime.
        return null;
    }

    @SuppressWarnings("unchecked") /* <----- */

    public List<Foo> activeObjects() {
        Session s = acquireSession();
        Query   q = s.createQuery("from foo where active");
        return (List<Foo>) q.list();
    }
}

I would like to get rid of that SuppressWarnings. But if I do, I get the warning

Warning: Unchecked cast from List to List<Foo>

(I can ignore it, but I'd like to not get it in the first place), and if I remove the generic to conform to .list() return type, I get the warning

Warning: List is a raw type. References to generic type List<E>
should be parameterized.

I noticed that org.hibernate.mapping does declare a List; but it is a different type altogether - Query returns a java.util.List, as a raw type. I find it odd that a recent Hibernate (4.0.x) would not implement parameterized types, so I suspect that it's me instead doing something wrong.

It looks very much like https://stackoverflow.com/questions/4864093/cast-hibernate-result-to-a-list-of-objects, but here I have no "hard" errors (the system knows type Foo, and I'm not using a SQLQuery but a straight Query). So no joy.

I have also looked at https://stackoverflow.com/questions/10754777/hibernate-class-cast-exception since it looked promising, but then I realized that I do not actually get any Exception... my problem is just that of a warning - a coding style, if you will.

Documentation on jboss.org, Hibernate manuals and several tutorials do not seem to cover the topic in such detail (or I didn't search in the right places?). When they do enter into detail, they use on-the-fly casting - and this on tutorials that weren't on the official jboss.org site, so I'm a bit wary.

The code, once compiled, runs with no apparent problem... that I know of... yet; and the results are the expected ones.

So: am I doing this right? Am I missing something obvious? Is there an "official" or "recommended" Way To Do It?

Java Solutions


Solution 1 - Java

Short answer @SuppressWarnings is the right way to go.

Long answer, Hibernate returns a raw List from the Query.list method, see here. This is not a bug with Hibernate or something the can be solved, the type returned by the query is not known at compile time.

Therefore when you write

final List<MyObject> list = query.list();

You are doing an unsafe cast from List to List<MyObject> - this cannot be avoided.

There is no way you can safely carry out the cast as the List could contain anything.

The only way to make the error go away is the even more ugly

final List<MyObject> list = new LinkedList<>();
for(final Object o : query.list()) {
    list.add((MyObject)o);
}

Solution 2 - Java

The resolution is to use TypedQuery instead. When creating a query from the EntityManager instead call it like this:

TypedQuery<[YourClass]> query = entityManager.createQuery("[your sql]", [YourClass].class);
List<[YourClass]> list = query.getResultList(); //no type warning

This also works the same for named queries, native named queries, etc. The corresponding methods have the same names as the ones that would return the vanilla query. Just use this instead of a Query whenever you know the return type.

Solution 3 - Java

To answer your question, there is no "proper way" to do that. Now if it's just the warning that bothers you, the best way to avoid its proliferation is to wrap the Query.list() method into a DAO :

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

This way you get to use the @SuppressWarnings("unchecked") only once.

Solution 4 - Java

You can avoid compiler warning with workarounds like this one:

List<?> resultRaw = query.list();
List<MyObj> result = new ArrayList<MyObj>(resultRaw.size());
for (Object o : resultRaw) {
	result.add((MyObj) o);
}

But there are some issues with this code:

  • created superfluous ArrayList
  • unnecessary loop over all elements returned from the query
  • longer code.

And the difference is only cosmetic, so using such workarounds is - in my opinion - pointless.

You have to live with these warnings or suppress them.

Solution 5 - Java

List<Person> list = new ArrayList<Person>();
Criteria criteria = this.getSessionFactory().getCurrentSession().createCriteria(Person.class);
for (final Object o : criteria.list()) {
    list.add((Person) o);
}

Solution 6 - Java

Only way that work for me was with an Iterator.

Iterator iterator= query.list().iterator();
Destination dest;
ArrayList<Destination> destinations= new ArrayList<>();
Iterator iterator= query.list().iterator();
	while(iterator.hasNext()){
		Object[] tuple= (Object[]) iterator.next();
		dest= new Destination();
		dest.setId((String)tuple[0]);
		dest.setName((String)tuple[1]);
		dest.setLat((String)tuple[2]);
		dest.setLng((String)tuple[3]);
		destinations.add(dest);
	}

With other methods that I found, I had cast problems

Solution 7 - Java

You use a ResultTransformer like that:

public List<Foo> activeObjects() {
    Session s = acquireSession();
    Query   q = s.createQuery("from foo where active");
    q.setResultTransformer(Transformers.aliasToBean(Foo.class));
    return (List<Foo>) q.list();
}

Solution 8 - Java

The proper way is to use Hibernate Transformers:

public class StudentDTO {
private String studentName;
private String courseDescription;

public StudentDTO() { }  
...
} 

.

List resultWithAliasedBean = s.createSQLQuery(
"SELECT st.name as studentName, co.description as courseDescription " +
"FROM Enrolment e " +
"INNER JOIN Student st on e.studentId=st.studentId " +
"INNER JOIN Course co on e.courseCode=co.courseCode")
.setResultTransformer( Transformers.aliasToBean(StudentDTO.class))
.list();

StudentDTO dto =(StudentDTO) resultWithAliasedBean.get(0);

Iterating througth Object[] is redundant and would have some performance penalty. Detailed information about transofrmers usage you will find here: Transformers for HQL and SQL

If you are looking for even more simple solution you can use out-of-the-box-map-transformer:

List iter = s.createQuery(
"select e.student.name as studentName," +
"       e.course.description as courseDescription" +
"from   Enrolment as e")
.setResultTransformer( Transformers.ALIAS_TO_ENTITY_MAP )
.iterate();

String name = (Map)(iter.next()).get("studentName");

Solution 9 - Java

Just just using Transformers It did not work for me I was getting type cast exception.

sqlQuery.setResultTransformer(Transformers.aliasToBean(MYEngityName.class)) did notwork because I was getting Array of Object in the return list element not the fixed MYEngityName type of list element.

It worked for me when I make following changes When I have added sqlQuery.addScalar(-) each selected column and its type and for specific String type column we dont have to map its type. like addScalar("langCode");

And I have join MYEngityName with NextEnity we cant just select * in the Query it will give array of Object in the return list.

Below code sample :

session = ht.getSessionFactory().openSession();
                String sql = new StringBuffer("Select txnId,nft.mId,count,retryReason,langCode FROM  MYEngityName nft INNER JOIN NextEntity m on nft.mId  =  m.id where nft.txnId < ").append(lastTxnId)
                       .append(StringUtils.isNotBlank(regionalCountryOfService)? " And  m.countryOfService in ( "+ regionalCountryOfService +" )" :"")
                       .append(" order by nft.txnId desc").toString();
                SQLQuery sqlQuery = session.createSQLQuery(sql);
                sqlQuery.setResultTransformer(Transformers.aliasToBean(MYEngityName.class));
                sqlQuery.addScalar("txnId",Hibernate.LONG)
                        .addScalar("merchantId",Hibernate.INTEGER)
                        .addScalar("count",Hibernate.BYTE)
                        .addScalar("retryReason")
                        .addScalar("langCode");
                sqlQuery.setMaxResults(maxLimit);
                return sqlQuery.list();

It might help some one. in this way work for me.

Solution 10 - Java

In a project I'm a consultant I had this issue. See the solution:
First, I created the following method:

protected <T> MyTypedQuery<T> createNamedAliasQuery(final String queryName, final Class<T> type) {  
	final Query q = getSafeEntityManager().createNamedQuery(queryName);
	q.unwrap(org.hibernate.Query.class)
		.setResultTransformer(Transformers.aliasToBean(type)); 	
	return new MyTypedQuery<T>(q); 
}

Second, I create a MyTypedQuery, which looks like a wrapper, as below:

public class MyTypedQuery<R> implements TypedQuery<R> {
	private Query q;
	
	public MyTypedQuery(Query q) {
		this.q = q;
	}
	
	@Override
	public int executeUpdate() {
		return this.q.executeUpdate();
	}

	@Override
	public int getFirstResult() {
		return this.q.getFirstResult();
	}

	@Override
	public FlushModeType getFlushMode() {
		return this.q.getFlushMode();
	}

	@Override
	public Map<String, Object> getHints() {
		return this.q.getHints();
	}

	@Override
	public LockModeType getLockMode() {
		return this.q.getLockMode();
	}

	@Override
	public int getMaxResults() {
		return this.q.getMaxResults();
	}

	@Override
	public Parameter<?> getParameter(String arg0) {
		return this.q.getParameter(arg0);
	}

	@Override
	public Parameter<?> getParameter(int arg0) {
		return this.q.getParameter(arg0);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <T> Parameter<T> getParameter(String arg0, Class<T> arg1) {
		return (Parameter<T>) this.q.getParameter(arg0);
	}

	@Override
	public <T> Parameter<T> getParameter(int arg0, Class<T> arg1) {
		return (Parameter<T>) this.q.getParameter(arg0, arg1);
	}

	@Override
	public <T> T getParameterValue(Parameter<T> arg0) {
		return (T) this.q.getParameterValue(arg0);
	}

	@Override
	public Object getParameterValue(String arg0) {
		return this.q.getParameterValue(arg0);
	}

	@Override
	public Object getParameterValue(int arg0) {
		return this.q.getParameterValue(arg0);
	}

	@Override
	public Set<Parameter<?>> getParameters() {
		return this.q.getParameters();
	}

	@Override
	public boolean isBound(Parameter<?> arg0) {
		return this.q.isBound(arg0);
	}

	@Override
	public <T> T unwrap(Class<T> arg0) {
		return this.q.unwrap(arg0);
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<R> getResultList() {
		return (List<R>) this.q.getResultList();
	}

	@SuppressWarnings("unchecked")
	@Override
	public R getSingleResult() {
		return (R) this.q.getSingleResult();
	}

	@Override
	public TypedQuery<R> setFirstResult(int arg0) {
		this.q.setFirstResult(arg0);
		return this;
	}

	@Override
	public TypedQuery<R> setFlushMode(FlushModeType arg0) {
		this.q.setFlushMode(arg0);
		return this;
	}

	@Override
	public TypedQuery<R> setHint(String arg0, Object arg1) {
		this.q.setHint(arg0, arg1);
		return this;
	}

	@Override
	public TypedQuery<R> setLockMode(LockModeType arg0) {
		this.q.setLockMode(arg0);
		return this;
	}

	@Override
	public TypedQuery<R> setMaxResults(int arg0) {
		this.q.setMaxResults(arg0);
		return this;
	}

	@Override
	public <T> TypedQuery<R> setParameter(Parameter<T> arg0, T arg1) {
		this.q.setParameter(arg0, arg1);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(String arg0, Object arg1) {
		this.q.setParameter(arg0, arg1);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(int arg0, Object arg1) {
		this.q.setParameter(arg0, arg1);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(Parameter<Calendar> arg0, Calendar arg1, TemporalType arg2) {
		this.q.setParameter(arg0, arg1, arg2);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(Parameter<Date> arg0, Date arg1, TemporalType arg2) {
		this.q.setParameter(arg0, arg1, arg2);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(String arg0, Calendar arg1, TemporalType arg2) {
		this.q.setParameter(arg0, arg1, arg2);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(String arg0, Date arg1, TemporalType arg2) {
		this.q.setParameter(arg0, arg1, arg2);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(int arg0, Calendar arg1, TemporalType arg2) {
		this.q.setParameter(arg0, arg1, arg2);
		return this;
	}

	@Override
	public TypedQuery<R> setParameter(int arg0, Date arg1, TemporalType arg2) {
		this.q.setParameter(arg0, arg1, arg2);
		return this;
	}
}

Third (and last), the use is straightforward like:

final List<Car> list = 
            createNamedAliasQuery("your-named-query", Car.class)
                .setParameter("idCar", idCar)
                .setParameter("idModel", idModel)
                .getResultList();

Note that @SuppressWarnings("unchecked") appears once in our MyTypedQuery and not in every single use.

Solution 11 - Java

First of you have ensure the naming in HQL.

Use the name of the entity in the HQL query. If you don't specify any name in the @Entity annotation then the default is your class name.

enter image description here

For More Information: https://javabydeveloper.com/org-hibernate-hql-internal-ast-querysyntaxexception-entity-table-is-not-mapped/

Solution 12 - Java

I found the best solution here, the key of this issue is the addEntity method

public static void testSimpleSQL() {
    final Session session = sessionFactory.openSession();
    SQLQuery q = session.createSQLQuery("select * from ENTITY");
    q.addEntity(Entity.class);
    List<Entity> entities = q.list();
    for (Entity entity : entities) {
        System.out.println(entity);
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLSerniView Question on Stackoverflow
Solution 1 - JavaBoris the SpiderView Answer on Stackoverflow
Solution 2 - JavaTaugenichtsView Answer on Stackoverflow
Solution 3 - JavaPdvView Answer on Stackoverflow
Solution 4 - JavaGrzegorz OlszewskiView Answer on Stackoverflow
Solution 5 - Javauser3184564View Answer on Stackoverflow
Solution 6 - JavaPopa AndreiView Answer on Stackoverflow
Solution 7 - JavalakreqtaView Answer on Stackoverflow
Solution 8 - JavaANTARAView Answer on Stackoverflow
Solution 9 - JavaGautamView Answer on Stackoverflow
Solution 10 - JavaRicardo TerraView Answer on Stackoverflow
Solution 11 - JavaMahbub Ul IslamView Answer on Stackoverflow
Solution 12 - JavaFederico TraimanView Answer on Stackoverflow