jparepository generic abstractdao java hibernate generics

java - abstractdao - jparepository generic



¿Cómo evitar las advertencias de seguridad de tipo con los resultados de Hibernate HQL? (15)

Por ejemplo, tengo esa consulta:

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

Si trato de hacer algo como esto, aparecerá la advertencia "Tipo de seguridad: la expresión del tipo Lista necesita conversión no verificada para cumplir con la Lista":

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

¿Hay alguna forma de evitarlo?


Aparentemente, el método Query.list () en la API de Hibernate no es seguro por tipo "por diseño", y no hay planes para cambiarlo .

Creo que la solución más simple para evitar las advertencias del compilador es, de hecho, agregar @SuppressWarnings ("desmarcado"). Esta anotación se puede colocar 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 puedo hacer:

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

Si pruebo el código a continuación:

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

Obtendré un error de compilación: No coinciden los tipos: no se puede convertir de List a ArrayList


En nuestro código anotamos los métodos de llamada con:

@SuppressWarnings ("desmarcado")

Sé que parece un truco, pero un co-desarrollador comprobó recientemente y descubrió que era todo lo que podíamos hacer.


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

Si echas un vistazo a javax.persistence api docs , verás 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 todas las operaciones son seguras ahora.

Entonces, simplemente cambie su código a smth así:

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

Y estás todo listo.


Intenta usar TypedQuery lugar de Query . Por ejemplo en lugar de esto: -

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

Utilizar esta:-

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


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 puedo agregar un comentario directamente a su solución por alguna razón)


Las versiones más nuevas de Hibernate ahora admiten un tipo de objeto Query<T> seguro, por lo que ya no tiene que usar @SuppressWarnings o implementar algún hack para que las advertencias del compilador desaparezcan. En la API de sesión , Session.createQuery ahora devolverá un tipo de objeto Query<T> seguro. Puedes usarlo de esta manera:

Query<Cat> query = session.createQuery("FROM Cat", Cat.class); List<Cat> cats = query.list();

También puede usarlo cuando el resultado de la consulta no devuelva un Cat:

public Integer count() { Query<Integer> query = sessionFactory.getCurrentSession().createQuery("SELECT COUNT(id) FROM Cat", Integer.class); return query.getSingleResult(); }

O al hacer una selección parcial:

public List<Object[]> String getName() { Query<Object[]> query = sessionFactory.getCurrentSession().createQuery("SELECT id, name FROM Cat", Object[].class); return query.list(); }


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.


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


Prueba esto:

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


Sé que esto es más antiguo, pero 2 puntos a tener en cuenta a partir de hoy en Matt Quails Answer.

Punto 1

Esta

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

Debería ser esto

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

Punto 2

De esto

List list = q.list();

a esto

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

reduciría otras advertencias obviamente en los marcadores de etiqueta de respuesta original fueron eliminados por el navegador.


Si no desea usar @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 - Creé un método util que hace esto por mí para que no ensucie mi código y no tenga que usar @SupressWarning.


También usamos @SuppressWarnings("unchecked") , pero a menudo tratamos de usarlo solo en la declaración de la variable, no en el método como un todo:

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


Tuvimos el 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. controlar cuándo se puede comprometer 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 simplemente "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 realmente se hará.
  4. Comportamiento más suave para query.uniqueResult ()

Entonces para nosotros, tenemos:

  1. Crear una interfaz (AmplafiQuery) que extienda Query
  2. Cree una clase (AmplafiQueryImpl) que amplíe AmplafiQuery y que contenga un org.hibernate.Query
  3. Crea un Txmanager que devuelva 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 habilitada genérica de Query.list () AmplafiQuery tiene un "único ()" que es una versión habilitada genérica de Query.uniqueResult () (y simplemente registra un problema en lugar de arrojar un 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.


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

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


Usar @SuppressWarnings todas partes, como se sugiere, es una buena manera de hacerlo, aunque implica un poco de tipeo con los dedos cada vez que llamas a q.list() .

Hay otras tres técnicas que sugeriría:

Collections.checkedList()

Reemplaza tu tarea con esto:

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

Es posible que desee comprobar el javadoc para ese método , especialmente con respecto a equals y hashCode .

Escribir un cast-helper

Simplemente refactorice todas sus @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; }

Evitar que Eclipse genere advertencias para problemas inevitables

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

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

Algunos comentarios:

  • Elegí pasar la Query lugar del resultado de q.list() porque de esa manera este método de "trampa" solo puede usarse para hacer trampa con Hibernate, y no para hacer trampa en ninguna List en general.
  • Puede agregar métodos similares para .iterate() etc.