Как избежать предупреждений о безопасности типа с результатами 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();

Есть ли способ избежать этого?

Ответ 1

@SuppressWarnings использование @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 перейдите в "Окно"> "Установки"> "Java"> "Компилятор"> "Ошибки/предупреждения" и в разделе "Универсальный тип" установите флажок " Ignore unavoidable generic type problems due to raw APIs

Это отключит ненужные предупреждения для подобных проблем, подобных описанной выше, которые неизбежны.

Некоторые комментарии:

  • Я решил передать Query вместо результата q.list() потому что таким образом этот "читерский" метод может использоваться только для мошенничества с Hibernate, а не для мошенничества с любым List вообще.
  • Вы можете добавить аналогичные методы для .iterate() и т.д.

Ответ 2

Прошло много времени с тех пор, как был задан вопрос, но я надеюсь, что мой ответ может быть полезен для кого-то вроде меня.

Если вы посмотрите на javax.persistence api docs, вы увидите, что там появились некоторые новые методы с Java Persistence 2.0. Один из них createQuery(String, Class<T>), который возвращает TypedQuery<T>. Вы можете использовать TypedQuery так же, как вы сделали это с помощью Query с той небольшой разницей, что все операции теперь безопасны по типу.

Итак, просто измените свой код на smth вот так:

Query q = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q.list();

И вы все настроены.

Ответ 3

Мы также используем @SuppressWarnings("unchecked"), но мы чаще всего пытаемся использовать его только при объявлении переменной, а не в методе в целом:

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

Ответ 4

Попробуйте использовать 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();

Ответ 5

В нашем коде мы аннотируем вызывающие методы с помощью:

@SuppressWarnings ( "флажок" )

Я знаю, что это похоже на взломать, но недавно был проверен со-разработчик и нашел, что все, что мы можем сделать.

Ответ 6

По-видимому, метод Query.list() в API-интерфейсе Hibernate не безопасен по типу "по дизайну", и есть не планирует его изменять.

Я считаю, что самым простым решением избежать предупреждений компилятора действительно является добавление @SuppressWarnings ( "unchecked" ). Эта аннотация может быть размещена на уровне метода или, если внутри метода, непосредственно перед объявлением переменной.

Если у вас есть метод, который инкапсулирует Query.list() и возвращает List (или Collection), вы также получите предупреждение. Но это подавляется с помощью @SuppressWarnings ( "rawtypes" ).

Метод listAndCast (Query), предложенный Matt Quail, менее гибкий, чем 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);

Я получу ошибку компиляции: Тип несоответствия: невозможно преобразовать из List в ArrayList

Ответ 7

Это не недосмотр или ошибка. Предупреждение отражает реальную основную проблему - нет никакого способа, чтобы java-компилятор действительно мог убедиться, что класс hibernate будет корректно выполнять эту работу и что в списке, который он возвращает, будут содержаться только Cats. Любое из предложений здесь прекрасно.

Ответ 8

Нет, но вы можете выделить его в конкретные методы запросов и подавить предупреждения с помощью аннотации @SuppressWarnings("unchecked").

Ответ 9

У нас была такая же проблема. Но для нас это было не очень важно, потому что нам пришлось решать другие более серьезные проблемы с помощью Hibernate Query и Session.

В частности:

  • контролировать транзакцию. (мы хотели подсчитать, сколько раз tx был "запущен" и только фиксировать, когда tx "закончился" столько же раз, сколько он был запущен. Полезно для кода, который не знает, нужно ли ему начинать транзакцию. любой код, который требует tx, просто "запускает" один и заканчивает его, когда это делается.)
  • Сбор показателей производительности.
  • Откладывание начала транзакции до тех пор, пока не станет известно, что что-то действительно будет выполнено.
  • Более мягкое поведение для query.uniqueResult()

Итак, для нас мы имеем:

  • Создайте интерфейс (AmplafiQuery), который расширяет Query
  • Создайте класс (AmplafiQueryImpl), который расширяет AmplafiQuery и обертывает org.hibernate.Query
  • Создайте Txmanager, который возвращает Tx.
  • Tx имеет различные методы createQuery и возвращает AmplafiQueryImpl

И наконец,

AmplafiQuery имеет "asList()", который является общей версией Query.list() У AmplafiQuery есть "unique()", который является универсальной версией Query.uniqueResult() (и просто регистрирует проблему, а не бросает исключение).

Это большая работа, чтобы просто избежать @SuppressWarnings. Однако, как я уже сказал (и перечислены), есть много других лучше! причины для выполнения обертывания.

Ответ 10

Новые версии Hibernate теперь поддерживают типобезопасный объект Query<T> поэтому вам больше не нужно использовать @SuppressWarnings или реализовывать некоторые хаки, чтобы компиляция предупреждений компилятора прошла. В Session 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();
}

Ответ 11

Решение Joe Dean выглядит интересно, но как вы думаете, стоит ли это - создать новый список и пропустить все элементы, чтобы избавиться от предупреждений?

(извините, не могу добавить комментарий прямо к его решению по какой-то причине)

Ответ 12

Я знаю, что это старше, но 2 пункта, чтобы отметить на сегодняшний день в ответе Matt Quails.

Точка 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();

приведет к уменьшению других предупреждений, очевидно, в оригинальном марке тега ответа, который был удален браузером.

Ответ 13

Попробуйте следующее:

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

Ответ 14

Хорошим решением, чтобы избежать предупреждений о безопасности типа с помощью запроса на спящий режим, является использование инструмента, такого как TorpedoQuery, чтобы помочь вам построить безопасный тип hql.

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

Ответ 15

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

Ответ 16

Если вы не хотите использовать @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);
    }

FYI - я создал метод утилиты, который делает это для меня, поэтому он не мешает моему коду, и мне не нужно использовать @SupressWarning.