[java] Hibernate Query.list ()를 List <Type>으로 캐스팅하는“적절한”방법은 무엇입니까?

저는 Hibernate의 초보자이고 특정 필터와 일치하는 개체 목록을 반환하는 간단한 메서드를 작성하고 있습니다. List<Foo>자연스러운 반환 유형처럼 보였습니다.

내가 무엇을하든, 나는 추악한 .NET을 사용하지 않는 한 컴파일러를 행복하게 만들 수 없습니다 @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();
    }
}

나는 그것을 없애고 싶다SuppressWarnings . 하지만 그렇게하면 경고를받습니다

Warning: Unchecked cast from List to List<Foo>

(무시할 수 있지만 처음에는 가져 오지 않으려 고합니다.) .list()반환 유형 을 준수하기 위해 제네릭을 제거 하면 경고가 표시됩니다.

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

나는 그 발견 org.hibernate.mapping 하지 를 선언 List; 그러나 그것은 완전히 다른 유형입니다- 원시 유형으로를 Query반환합니다 java.util.List. 최근의 Hibernate (4.0.x)가 매개 변수화 된 유형을 구현하지 않는 것이 이상하다는 것을 알게 되었기 때문에 대신 내가 뭔가 잘못한 것 같다고 생각합니다.

객체 목록에 대한 Cast Hibernate 결과 와 매우 유사 하지만 여기에는 “하드”오류가 없습니다 (시스템은 Foo 유형을 알고 있으며 SQLQuery가 아니라 직접적인 쿼리를 사용하고 있습니다). 그래서 기쁨이 없습니다.

나는 또한 유망 해 보였기 때문에 Hibernate Class Cast Exception 을 보았지만 실제로 는 아무것도 얻지 못한다 는 것을 깨달았습니다 Exception… 내 문제는 경고의 문제입니다.

jboss.org에 대한 문서, Hibernate 매뉴얼 및 여러 튜토리얼은 그 주제를 그렇게 자세하게 다루지 않는 것 같습니다 (또는 올바른 위치에서 검색하지 않았습니까?). 세부 사항을 입력 할 때, 그들은 즉석 캐스팅을 사용합니다. 그리고 이것은 공식 jboss.org 사이트에 없었던 튜토리얼에 대한 것이므로 약간 조심합니다.

일단 컴파일 된 코드는 명백한 문제 없이 실행됩니다 … 내가 아는 … 아직; 결과는 예상되는 것입니다.

그래서 :이 일을 제대로하고 있습니까? 나는 명백한 것을 놓치고 있습니까? “공식”또는 “권장” 방법이 있습니까?



답변

짧은 대답 @SuppressWarnings이 올바른 방법입니다.

긴 대답, Hibernate는 메서드 List에서 원시 를 반환합니다 . 여기를Query.list 참조 하십시오 . 이것은 Hibernate의 버그 나 해결할 수있는 것이 아닙니다 . 쿼리에 의해 반환 된 유형 은 컴파일 타임에 알려지지 않습니다 .

따라서 당신이 쓸 때

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

에서 List로 안전하지 않은 캐스트를 수행하고 List<MyObject>있습니다. 이것은 피할 수 없습니다.

무엇이든 포함 List 할 수 있으므로 캐스트를 안전하게 수행 할 수있는 방법은 없습니다 .

오류를 없애는 유일한 방법은

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


답변

해결 방법은 대신 TypedQuery를 사용하는 것입니다. EntityManager에서 쿼리를 만들 때 대신 다음과 같이 호출합니다.

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

이것은 또한 명명 된 쿼리, 네이티브 명명 된 쿼리 등에 대해 동일하게 작동합니다. 해당 메서드는 바닐라 쿼리를 반환하는 것과 동일한 이름을 갖습니다. 반환 유형을 알 때마다 Query 대신 이것을 사용하십시오.


답변

다음과 같은 해결 방법으로 컴파일러 경고를 피할 수 있습니다.

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

그러나이 코드에는 몇 가지 문제가 있습니다.

  • 불필요한 ArrayList 생성
  • 쿼리에서 반환 된 모든 요소에 대한 불필요한 루프
  • 더 긴 코드.

그리고 그 차이는 외형 일 뿐이므로 그러한 해결 방법을 사용하는 것은-제 생각에는-무의미합니다.

당신은 이러한 경고와 함께 살거나 억제해야합니다.


답변

귀하의 질문에 답하기위한 “올바른 방법”은 없습니다. 이제 당신을 괴롭히는 경고 일 뿐이라면 확산을 피하는 가장 좋은 방법은 Query.list()메서드를 DAO로 래핑하는 것입니다.

public class MyDAO {

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

이렇게하면 @SuppressWarnings("unchecked")한 번만 사용할 수 있습니다 .


답변

나를 위해 일하는 유일한 방법은 반복자를 사용하는 것입니다.

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

내가 찾은 다른 방법으로는 캐스트 문제가있었습니다.


답변

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


답변

다음과 같은 ResultTransformer를 사용합니다.

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