Hibernate 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
JPA를 사용하면 createQuery에 유형을 추가하여 유형 안전 쿼리를 가질 수 있다는 점을 언급 할 가치가 있습니다.
Elazar Leibovich 2011-08-05

5
조금 늦었지만 sess.createQuery("from Cat cat", Cat.class);Elazar가 언급했듯이.
Dominik Mohr 2013

답변:


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

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

20
언뜻보기에 Collections.checkedList (Collection <E>, Class <E>) 메서드는 완벽한 솔루션처럼 보입니다. 그러나 javadoc은 메소드가 생성하는 typesafe 뷰를 통해 잘못 입력 된 요소가 추가되는 것을 막을 뿐이라고 말합니다. 주어진 목록에 대한 검사가 수행되지 않습니다.
phatblat

11
"List <Cat> list = Collections.checkedList (q.list (), Cat.class);" Eclipse에서는 여전히 "@SuppressWarnings"가 필요합니다. 다른 팁 : "listAndCast"를 입력하는 것은 Eclipse를 통해 자동으로 추가되는 "@SuppressWarnings"보다 실제로 짧지 않습니다.
트리스탄

2
BTW, Collections.checkedList()메서드는 확인되지 않은 할당 경고를 억제하지 않습니다.
Diablo

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
Hibernate의 최신 버전은 JPA 2.x를 구현하므로이 답변은 관련이 있습니다.
caspinos

TypedQuery <T>가 최상의 시나리오입니다.
Muneeb Mirza

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그래도 이것을 수행하는 방법이 있습니까?
Stealth Rabbi

5

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

@SuppressWarnings ( "선택 취소")

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


5

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

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

Query.list ()를 캡슐화하고 List (또는 Collection)를 반환하는 메서드가있는 경우에도 경고가 표시됩니다. 그러나 이것은 @SuppressWarnings ( "rawtypes")를 사용하여 억제됩니다.

Matt Quail이 제안한 listAndCast (Query) 메서드는 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

감독이나 실수가 아닙니다. 경고는 실제 근본적인 문제를 반영합니다. 자바 컴파일러가 hibernate 클래스가 제대로 작업을 수행 할 것인지 그리고 반환하는 목록에 Cats 만 포함되어 있는지 실제로 확인할 수있는 방법은 없습니다. 여기에 제안하는 것이 좋습니다.


2

아니요,하지만 특정 쿼리 메서드로 격리하고 @SuppressWarnings("unchecked")주석으로 경고를 표시하지 않을 수 있습니다 .


틀렸어 ... 조 딘이 맞아, 당신은? 경고를 피하기 위해 일반적인 유형으로 ...
Mike Stone

1
그건 사실이 아니야. List <?>를 사용하는 경우 중복 목록을 만들고 각 항목을 캐스팅하는 불필요한 단계 없이는 목록의 요소를 Cat 's로 사용할 수 없습니다.
Dave L.

음, 캐스팅을 통해 결과를 직접 사용하는 경우 목록을 만들 필요가 없으며 질문이 "피할 수있는 방법이 있습니까?"라는 질문 이었지만 대답은 가장 확실하게 예입니다 (억제 경고 없이도)
Mike 스톤

2

최신 버전의 Hibernate는 이제 타입 안전 Query<T>객체를 지원 하므로 @SuppressWarnings컴파일러 경고를 없애기 위해 더 이상 해킹을 사용 하거나 구현할 필요가 없습니다 . 에서 세션 API , Session.createQuery지금 형 안전의 반환 Query<T>개체를. 다음과 같이 사용할 수 있습니다.

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

쿼리 결과가 Cat을 반환하지 않을 때도 사용할 수 있습니다.

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

우리도 같은 문제가있었습니다. 그러나 Hibernate Query 및 Session으로 다른 주요 문제를 해결해야했기 때문에 우리에게는 큰 문제가 아니 었습니다.

구체적으로 특별히:

  1. 트랜잭션이 커밋 될 수있는시기를 제어합니다. (우리는 tx가 "시작"된 횟수를 계산하고 tx가 시작된 횟수와 "종료"되었을 때만 커밋하려고했습니다. 트랜잭션을 시작해야하는지 알 수없는 코드에 유용합니다. 이제 tx가 필요한 모든 코드는 하나를 "시작"하고 완료되면 종료합니다.)
  2. 성능 메트릭 수집.
  3. 어떤 일이 실제로 수행 될 것임을 알 때까지 트랜잭션 시작을 지연합니다.
  4. query.uniqueResult ()에 대한보다 부드러운 동작

따라서 우리에게는 다음이 있습니다.

  1. Query를 확장하는 인터페이스 (AmplafiQuery) 생성
  2. AmplafiQuery를 확장하고 org.hibernate.Query를 래핑하는 클래스 (AmplafiQueryImpl)를 만듭니다.
  3. Tx를 반환하는 Txmanager를 만듭니다.
  4. Tx에는 다양한 createQuery 메서드가 있으며 AmplafiQueryImpl을 반환합니다.

그리고 마지막으로

AmplafiQuery에는 Query.list ()의 제네릭 활성화 버전 인 "asList ()"가 있습니다. AmplafiQuery에는 Query.uniqueResult ()의 제네릭 활성화 버전 인 "unique ()"가 있습니다. 예외)

이것은 @SuppressWarnings를 피하기위한 많은 작업입니다. 그러나 내가 말하고 나열된 것처럼 다른 많은 것이 더 좋습니다! 포장 작업을하는 이유.


0

나는 이것이 더 오래되었다는 것을 알고 있지만 오늘 Matt Quails Answer에서 주목해야 할 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();

브라우저에 의해 제거 된 원래 응답 태그 마커에서 분명히 다른 경고를 줄일 수 있습니다.


다른 답변에 대한 답변이 아니라 질문에 대한 답변을 만드십시오. Matt Quail의 답변에 그가 시대에 뒤떨어 졌다는 의견을 포함하는 것은 좋지만 답을 순수하고 정확하게 작성하십시오.
Cory Kendall

-1

이 시도:

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

4
이것은 여전히 인스턴스로 뭔가를해야하기 때문에 Joe Dean의 대답의 잘못된 복사본입니다 cat.
Artjom B. 2007

-1

최대 절전 모드 쿼리에서 형식 안전 경고를 방지하는 좋은 솔루션은 형식 안전 hql을 빌드하는 데 도움이되는 TorpedoQuery 와 같은 도구를 사용하는 것입니다.

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


-6

@SuppressWarnings ( "unchecked")를 사용하지 않으려면 다음을 수행 할 수 있습니다.

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

참고로-이 작업을 수행하는 util 메서드를 만들었으므로 내 코드가 흩어지지 않고 @SupressWarning을 사용할 필요가 없습니다.


2
그건 바보 같아. 완전한 컴파일러 관련 문제를 극복하기 위해 런타임 오버 헤드를 추가하고 있습니다. 유형 인수는 수정되지 않으므로 유형의 런타임 검사가 없습니다.
John Nilsson

동의합니다. 여전히 이와 같은 작업을 수행하려면 다음을 사용하여 유형의 런타임 검사를 추가 할 수 있습니다. List <Cat> cats = Collections.checkedList (new ArrayList <Cat> (), Cat.class); cats.addAll (q.list ()); 작동합니다.
ddcruver 2010
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.