programing tip

Hibernate HQL 결과로 유형 안전 경고를 피하는 방법은 무엇입니까?

itbloger 2020. 8. 18. 07:25
반응형

Hibernate HQL 결과로 유형 안전 경고를 피하는 방법은 무엇입니까?


예를 들어 다음과 같은 쿼리가 있습니다.

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

그것을 피할 수있는 방법이 있습니까?


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

Eclipse에서 피할 수없는 문제에 대한 경고를 생성하지 않도록 방지

Eclipse에서 Window> Preferences> Java> Compiler> Errors / Warnings로 이동하고 Generic type에서 확인란을 선택합니다. Ignore unavoidable generic type problems due to raw APIs

이것은 피할 수없는 위에서 설명한 것과 같은 유사한 문제에 대해 불필요한 경고를 해제합니다.

몇 가지 의견 :

  • 나는 Query결과 대신에 전달하기로 결정했다. q.list()왜냐하면이 "속임수"방법은 List일반적으로 어떤 속임수도 아닌 Hibernate로 속이는 데만 사용될 수 있기 때문이다 .
  • 비슷한 방법을 추가 할 수 있습니다 .iterate().

질문을받은 지 오래되었지만 제 답변이 저와 같은 사람에게 도움이 되었으면합니다.

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

그리고 당신은 모두 준비되었습니다.


우리는 또한 사용 @SuppressWarnings("unchecked")하지만, 메서드 전체가 아닌 변수 선언에서만 사용하려고합니다.

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

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

코드에서 호출 메서드에 다음과 같이 주석을 추가합니다.

@SuppressWarnings ( "선택 취소")

해킹처럼 보이지만 최근에 공동 개발자가 확인한 결과 그것이 우리가 할 수있는 전부라는 것을 알았습니다.


분명히 Hibernate API의 Query.list () 메서드는 "설계 상"유형 안전 하지 않으며 변경할 계획없습니다 .

컴파일러 경고를 피하는 가장 간단한 해결책은 실제로 @SuppressWarnings ( "unchecked")를 추가하는 것입니다. 주석은 메서드 수준에 배치 할 수 있으며 메서드 내부에있는 경우 변수 선언 바로 앞에 배치 할 수 있습니다 .

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


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 it's job properly and that the list it returns will only contain Cats. Any of the suggestions here is fine.


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


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.


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

Joe Dean's solution looks interesting, but do you think it's worth it - create a new List and loop through all elements just to get rid of warnings?

(sorry, can't add a comment directly to his solution for some reason)


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.


Try this:

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

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

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

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.

참고URL : https://stackoverflow.com/questions/115692/how-to-avoid-type-safety-warnings-with-hibernate-hql-results

반응형