Как избежать предупреждений о безопасности типов с результатами Hibernate HQL? - PullRequest
101 голосов
/ 22 сентября 2008

Например у меня такой запрос:

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

Если я попытаюсь сделать что-то подобное, на экране появится предупреждение «Тип безопасности: для выражения типа Список требуется преобразование без проверки для соответствия списку»:

List<Cat> cats = q.list();

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

Ответы [ 16 ]

96 голосов
/ 23 сентября 2008

Использование @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() и т. Д.
30 голосов
/ 15 мая 2015

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

Если вы посмотрите на javax.persistence api docs , вы увидите, что после 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();

И все готово.

21 голосов
/ 22 сентября 2008

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

public List<Cat> findAll() {
    Query q = sess.createQuery("from Cat cat");
    @SuppressWarnings("unchecked")
    List<Cat> cats = q.list();
    return cats;
}
11 голосов
/ 05 апреля 2016

Попробуйте использовать 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 голосов
/ 05 декабря 2012

Очевидно, что метод Query.list () в Hibernate API не является безопасным по типу «по замыслу», и не планирует его изменять .

Я считаю, что самое простое решение, позволяющее избежать предупреждений компилятора, - это действительно добавить @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);

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

5 голосов
/ 22 сентября 2008

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

@ SuppressWarnings ( "снят")

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

4 голосов
/ 13 февраля 2009

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

2 голосов
/ 22 сентября 2008

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

1 голос
/ 10 февраля 2018

Более новые версии Hibernate теперь поддерживают тип безопасного объекта Query<T>, поэтому вам больше не нужно использовать @SuppressWarnings или реализовывать некоторые хаки, чтобы убрать предупреждения компилятора. В Session API , Session.createQuery теперь будет возвращать объект типа safe 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 голос
/ 13 февраля 2009

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

В частности:

  1. контроль, когда транзакция может быть совершена. (Мы хотели подсчитать, сколько раз tx был «запущен», и фиксировать, только когда tx был «закончен», столько раз, сколько он был запущен. Полезно для кода, который не знает, нужно ли начинать транзакцию. Теперь любой код, которому требуется tx, просто «запускает» его и заканчивает его, когда все готово.
  2. Сбор метрик производительности.
  3. Задержка запуска транзакции, пока не станет известно, что что-то действительно будет сделано.
  4. Более мягкое поведение для query.uniqueResult ()

Так что для нас у нас есть:

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

И, наконец,

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...