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