2008-09-22 6 views
90

Por ejemplo, tengo tales consulta:Cómo evitar las advertencias de seguridad de tipo con los resultados Hibernate HQL?

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

Si trato de hacer algo como esto se mostrará la advertencia "Tipo de seguridad: La expresión de tipo List necesita conversión sin control para ajustarse a la lista":

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

¿Hay alguna manera de evitarlo?

+9

Vale la pena mencionar que con JPA puede tener consultas de tipo seguro al agregar el tipo a createQuery. –

+2

Un poco tarde pero 'sess.createQuery (" de Cat cat ", Cat.class);' como mencionó Elazar. –

+0

@Dommel Hmm, 5 años pueden ser más que un poco tarde :). Espero que todavía no haya trabajado en él – cowls

Respuesta

91

Usando @SuppressWarnings todas partes, como se sugiere, es una buena manera de hacerlo, a pesar de que no implican un poco de dedo de escribir cada vez que llame q.list().

Hay otras tres técnicas me gustaría sugerir:

Collections.checkedList()

reemplazar su asignación con esto:

List<Cat> cats = Collections.checkedList(q.list(), Cat.class); 

Es posible que desee comprobar la javadoc for that method, especialmente con respecto a equals y hashCode.

Escribir un elenco-helper

Simplemente refactorizar toda su @SuppressWarnings en un solo lugar:

List<Cat> cats = MyHibernateUtils.listAndCast(q); 

... 

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

Prevenir Eclipse desde la generación de advertencias para los problemas inevitables

En Eclipse, vaya a Ventana> Preferencias> Java> Compilador> Errores/Advertencias y en Tipo genérico, seleccione la casilla de verificación Ignore unavoidable generic type problems due to raw APIs

Esto desactivará las advertencias innecesarias para problemas similares a los descritos anteriormente que son inevitables.

Algunos comentarios:

  • me eligieron para pasar en el Query en lugar del resultado de q.list() porque de esa manera este método "trampa" sólo se puede utilizar para hacer trampa con Hibernate, y no para hacer trampa cualquier List en general.
  • Se podría añadir métodos similares para .iterate() etc.
+19

A primera vista, las Colecciones.El método checkList (Colección , clase ) parece ser la solución perfecta. Sin embargo, el javadoc dice que solo evita que se agreguen elementos incorrectamente tipeados a través de la vista de tipo seguro que genera el método. No se realiza ninguna comprobación en la lista dada. – phatblat

+11

"listado = Collections.checkedList (q.list(), Cat.class);" todavía requiere un "@SuppressWarnings" en Eclipse. Sobre el otro consejo: escribir "listAndCast" no es realmente más corto que "@SuppressWarnings" que se agrega automáticamente a través de Eclipse. – Tristan

+2

BTW, el método 'Collections.checkedList()' no eliminará la advertencia de asignación no marcada. – Diablo

5

En nuestro código se van registrando los métodos de llamada con:

@SuppressWarnings ("sin marcar")

Sé que parece como un corte, sino un co-desarrollador comprobado recientemente y nos pareció que era todo lo podría hacer.

2

No, pero puede aislarlo en métodos de consulta específicos y suprimir las advertencias con una anotación @SuppressWarnings("unchecked").

+0

Mal ... Joe Dean tiene razón, ¿puedes usar el? como el tipo genérico para evitar las advertencias ... –

+1

Eso no es verdad. Si usa una Lista , entonces no puede usar los elementos de la lista como Cat sin el paso innecesario de crear una lista duplicada y fundir cada elemento. –

+0

bueno, si usas los resultados directamente a través del casting, no necesitas crear la lista, y sin tener en cuenta, la pregunta era "¿hay alguna manera de evitarlo?", La respuesta es definitivamente SÍ (incluso sin advertencias de supresión) –

-5

Si no desea utilizar @SuppressWarnings ("desmarcado") puede hacer lo siguiente.

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 - He creado un método util que hace esto para mí por lo que no se tire mi código y no tener que usar @SupressWarning.

+2

Eso es estúpido Está agregando sobrecarga de tiempo de ejecución para superar un problema completamente relacionado con el compilador. Recuerde que los argumentos de tipo no se reifican por lo que no hay verificación de tiempo de ejecución del tipo. –

+0

De acuerdo, si aún desea hacer algo como esto, puede agregar la verificación de tiempo de ejecución de tipo con: List cats = Collections.checkedList (new ArrayList (), Cat.class); cats.addAll (q.list()); Esto debería funcionar. – ddcruver

0

La solución de Joe Dean parece interesante, pero ¿cree que vale la pena - crear una nueva lista y recorrer todos los elementos solo para deshacerse de las advertencias?

(lo siento, no se puede añadir un comentario directamente a su solución por alguna razón)

+0

De acuerdo. Parece innecesario y más feo que simplemente usar una anotación para informar al compilador que usted sabe que la lista existente ya contiene el tipo correcto. –

+0

Una alternativa es usar la lista directamente con el casting en lugar de construir la lista copiada ... de cualquier manera, prefiero evitar el uso de las anotaciones si puedo, aunque es una opción subjetiva por supuesto y debes hacer lo que te gusta mejor –

+0

Un problema con la advertencia de supresión es que no recibirá una excepción de clase hasta que use la lista ... si copia la lista, obtendrá la excepción de inmediato ... un beneficio menor, pero agradable (y si sus resultados no son enormes, entonces la copia no será prohibitivamente ineficaz) –

21

Utilizamos @SuppressWarnings("unchecked") así, pero más a menudo tratamos de usarlo sólo en la declaración de la variable, no en el método en su conjunto:

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

Tuvimos mismo problema. Pero no fue un gran problema para nosotros porque tuvimos que resolver otros problemas más importantes con Hibernate Query y Session.

Específicamente:

  1. control cuando puede ser cometido una transacción. (Queríamos contar cuántas veces se "inició" un tx y solo confirmar cuando el tx se "terminó" la misma cantidad de veces que se inició. Útil para código que no sabe si necesita iniciar una transacción. cualquier código que necesite un tx solo "comience" uno y lo finaliza cuando termine).
  2. Recopilación de métricas de rendimiento.
  3. Retrasar el inicio de la transacción hasta que se sepa que algo se hará realmente.
  4. comportamiento más suave para el query.uniqueResult()

Así que para nosotros, tenemos:

  1. crear una interfaz (AmplafiQuery) que se extiende de consulta
  2. Crear una clase (AmplafiQueryImpl) que extiende AmplafiQuery y envuelve un org.hibernate.Query
  3. Crea un Txmanager que devuelve un Tx.
  4. Tx tiene los diversos métodos CreateQuery y devuelve AmplafiQueryImpl

Y, por último,

AmplafiQuery tiene un "asList()" que es una versión genérica de Query.list permitido() AmplafiQuery tiene un " unique() "que es una versión habilitada genérica de Query.uniqueResult() (y simplemente registra un problema en lugar de lanzar una excepción)

Esto es mucho trabajo para evitar @SuppressWarnings. Sin embargo, como dije (y enumeré) ¡hay muchos otros mejores! razones para hacer el trabajo de envolver.

4

No es un descuido o un error. La advertencia refleja un problema subyacente real: no hay forma de que el compilador de Java pueda estar seguro de que la clase de hibernación hará su trabajo correctamente y de que la lista que devuelve solo contendrá Gatos. Cualquiera de las sugerencias aquí está bien.

0

Sé que esto es anterior, pero 2 puntos a tener en cuenta a partir de hoy en Matt Quails Respuesta.

El punto 1

Este

List<Cat> cats = Collections.checkedList(Cat.class, q.list()); 

debería ser tan

List<Cat> cats = Collections.checkedList(q.list(), Cat.class); 

El punto 2

De esta

List list = q.list(); 

a este

List<T> list = q.list(); 

reduciría otras advertencias, obviamente, en los marcadores de etiquetas respuesta originales fueron despojados por el navegador.

+0

Intente hacer que las respuestas sean una respuesta a la pregunta, no una respuesta a otra respuesta. Está bien incluir un comentario sobre la respuesta de Matt Quail para decir que está desactualizado, pero solo escriba su respuesta pura y correctamente. –

5

Aparentemente, el método Query.list() en la API de Hibernate no es seguro "por diseño" y hay no plans to change it.

Creo que la solución más sencilla para evitar las advertencias del compilador es de hecho agregar @SuppressWarnings ("desmarcado"). Esto annotation can be placed en el nivel de método o, si está dentro de un método, justo antes de una declaración de variable.

En caso de que tenga un método que encapsule Query.list() y devuelva List (o Collection), también recibirá una advertencia. Pero este se suprime utilizando @SuppressWarnings ("tipos de raw").

El método listAndCast (Query) propuesto por Matt Quail es menos flexible que Query.list(). Mientras que puedo hacer:

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

Si intento el código de abajo:

Query q = sess.createQuery("from Cat cat"); 
ArrayList<Cat> cats = MyHibernateUtils.listAndCast(q); 

que obtendrá un error de compilación: coinciden los tipos: no se puede convertir de la lista para arrayList

+1

"no hay planes para cambiarlo". - Esa es una publicación de 2005. Me sorprendería si las cosas no hubieran cambiado desde entonces. – Rup

-1

Pruebe esto:

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

Esta es una mala copia de [respuesta de Joe Dean] (http://stackoverflow.com/a/115952/1816580), ya que todavía tiene que hacer algo con la instancia de 'cat'. –

14

Ha sido un mucho tiempo desde que se hizo la pregunta, pero espero que mi respuesta sea útil para alguien como yo.

Si echa un vistazo a javax.persistence api docs, verá que se han agregado algunos métodos nuevos desde Java Persistence 2.0. Uno de ellos es createQuery(String, Class<T>) que devuelve TypedQuery<T>.Puede usar TypedQuery tal como lo hizo con Query con la pequeña diferencia de que ahora todas las operaciones son seguras.

lo tanto, sólo cambiar el código para smth como esto:

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

Y que está todo listo.

+1

pregunta no es acerca de la APP –

+0

Parece que funciona con Hibernate 5, sin embargo. – Marvo

-1

Una buena solución para evitar las advertencias de seguridad de tipo con la consulta de hibernación es utilizar una herramienta como TorpedoQuery para ayudarlo a compilar tipo hql seguro.

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

Intente utilizar TypedQuery en lugar de Query. Por ejemplo en lugar de esto: -

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

Utilice esta: -

TypedQuery<Cat> q1 = sess.createQuery("from Cat cat", Cat.class); 
List<Cat> cats = q1.list(); 
+0

¿Hay alguna manera de hacer esto con 'Criteria'? –

+0

No funciona en 4.3.x. – RabbitBones22

0

Esta pregunta es muy viejo, pero Hibernate 5.2 ahora es compatible con una caja fuerte Query<T> objeto de tipo por lo que ya no tiene que utilizar @SuppressWarnings o implemente algún truco para que las advertencias del compilador desaparezcan. En el Session API, Session.createQuery ahora devolverá un tipo de objeto seguro Query<T>. Puede usarlo de esta manera:

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

El viejo Query tipo de prima ahora es obsoleto y programado para ser eliminado en Hibernate 6.0.

Cuestiones relacionadas