91 votes

Quelle est la "bonne" façon de convertir Hibernate Query.list() en List<Type> ?

Je suis un débutant avec Hibernate et j'écris une méthode simple pour retourner une liste d'objets. correspondant à un filtre spécifique. List<Foo> semblait un type de retour naturel.

Quoi que je fasse, je n'arrive pas à rendre le compilateur heureux, à moins d'employer un vilain @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();
    }
}

Je voudrais me débarrasser de ça SuppressWarnings . Mais si je le fais, je reçois l'avertissement

Warning: Unchecked cast from List to List<Foo>

(je peux l'ignorer, mais j'aimerais ne pas l'avoir en premier lieu), et si je supprime le générique pour me conformer à la norme .list() le type de retour, je reçois l'avertissement

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

J'ai remarqué que org.hibernate.mapping fait déclarer un List ; mais c'est un tout autre type - Query renvoie un java.util.List comme un type brut. Je trouve étrange qu'un Hibernate récent (4.0.x) n'implémente pas les types paramétrés, je soupçonne donc que c'est moi qui fais plutôt quelque chose de mal.

Il ressemble beaucoup à Conversion du résultat d'Hibernate en une liste d'objets Mais ici, je n'ai pas d'erreur "dure" (le système connaît le type Foo, et je n'utilise pas une SQLQuery mais une simple Query). Donc pas de joie.

J'ai également examiné Hibernate Class Cast Exception parce qu'il avait l'air prometteur, mais ensuite j'ai réalisé que j'ai no obtenir des Exception ... mon problème est simplement celui d'un avertissement - un style de codage, si vous voulez.

La documentation sur jboss.org, les manuels d'Hibernate et plusieurs tutoriels ne semblent pas couvrir le sujet en tel (ou je n'ai pas cherché dans les bons endroits ?). Lorsqu'ils entrent dans les détails, ils utilisent le moulage à la volée - et ceci sur des tutoriels qui n'étaient pas sur le site officiel jboss.org, donc je suis un peu méfiant.

Le code, une fois compilé, s'exécute sans aucune apparent problème... que je sache... pour le moment ; et les résultats sont ceux attendus.

Alors : est-ce que je fais bien les choses ? Est-ce que je rate quelque chose d'évident ? Existe-t-il une méthode "officielle" ou "recommandé" La manière de le faire ?

108voto

Boris the Spider Points 20200

Réponse courte @SuppressWarnings est la bonne voie à suivre.

Pour faire court, Hibernate renvoie un fichier brut List del Query.list méthode, voir [ici](http://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/Query.html#list()) . Il ne s'agit pas d'un bogue d'Hibernate ou de quelque chose qui peut être résolu, le type renvoyé par la requête est pas connu au moment de la compilation.

Par conséquent, lorsque vous écrivez

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

Vous faites une distribution non sécurisée de List a List<MyObject> - cela ne peut être évité.

Il n'y a aucune chance que vous puissiez effectuer le casting en toute sécurité en tant que List pourrait ne contient rien.

Le seul moyen de faire disparaître l'erreur est la méthode encore plus laide

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

32voto

Taugenichts Points 802

La solution consiste à utiliser TypedQuery à la place. Lorsque vous créez une requête à partir de l'EntityManager, appelez-la plutôt comme ceci :

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

Cela fonctionne également de la même manière pour les requêtes nommées, les requêtes nommées natives, etc. Les méthodes correspondantes ont les mêmes noms que celles qui renvoient la requête vanille. Utilisez simplement cette méthode au lieu d'une requête lorsque vous connaissez le type de retour.

6voto

Pdv Points 61

Pour répondre à votre question, il n'y a pas de "bonne façon" de le faire. Maintenant, si c'est seulement l'avertissement qui vous dérange, la meilleure façon d'éviter sa prolifération est d'envelopper la balise Query.list() dans un DAO :

public class MyDAO {

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

De cette façon, vous pouvez utiliser le @SuppressWarnings("unchecked") une seule fois.

5voto

Vous pouvez éviter l'avertissement du compilateur avec des solutions de contournement comme celle-ci :

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

Mais il y a quelques problèmes avec ce code :

  • a créé une ArrayList superflue
  • boucle inutile sur tous les éléments retournés par la requête
  • code plus long.

Et la différence n'est que cosmétique, de sorte que l'utilisation de telles solutions de contournement est - à mon avis - inutile.

Vous devez vivre avec ces avertissements ou les supprimer.

3voto

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X