El uso de JPA Criteria nos aporta muchas ventajas en cuanto a la construcción de SQL Dinámico utilizando JPA . Ahora bien su su sintaxis y su forma de trabajar son bastante diferentes a la forma clásica. Vamos a apoyarnos en el ejemplo anterior de JPA SQL Injection para construir el mismo ejemplo utilizando JPA Criteria . En el ejemplo anterior teníamos el siguiente código:
package com.arquitecturajava;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
public class Principal {
public static void main(String[] args) {
seleccionarPersona("pedro", "perez");
}
private static void seleccionarPersona(String nombre, String apellidos) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("UnidadPersonas");
EntityManager em = emf.createEntityManager();
try {
String sql = "select p from Persona p ";
if (nombre != null || apellidos != null) {
sql += " where ";
}
if (nombre != null) {
sql += " nombre='" + nombre + "'";
}
if (apellidos != null) {
if(nombre!=null) {
sql += " and apellidos='" + apellidos + "'";
}else{
sql += " apellidos='" + apellidos + "'";
}
}
TypedQuery<Persona&> consulta = em.createQuery(sql, Persona.class);
List<Persona&> lista = consulta.getResultList();
lista.forEach((p) -&> {
System.out.println(p.getNombre());
});
} catch (Exception e) {
e.printStackTrace();
} finally {
em.close();
}
}
}
El código nos generaba una SQL dinámica pero ya habíamos visto que si cambiamos los parámetros e intentabamos inyectar SQL , podríamos generar un agujero de seguridad.

JPA Criteria API
Para solventar este problema que se genera a partir de la necesidad de construir SQL Dinámico podemos recurrir al API de Criteria y diseñar la consulta con ella.
ppackage com.arquitecturajava;
pimport java.util.List;
pimport javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
ppublic class Principal2 {
public static void main(String[] args) {
seleccionarPersonas("pedro","perez");
}
private static void seleccionarPersonas(String nome, String apellidos) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("UnidadPersonas");
EntityManager em = emf.createEntityManager();
try {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Persona&> consulta = cb.createQuery(Persona.class);
Root<Persona&> personas = consulta.from(Persona.class);
Predicate p1 = null,p2 = null;
if(nome!=null) {
p1= cb.equal(personas.get("nome"),"pedro");
}
if(apellidos!=null) {
p2= cb.equal(personas.get("apellidos"),"perez");
}
Predicate nomeApellidos=cb.or(p1,p2);
consulta.select(personas).where(nomeApellidos);
List<Persona&> lista = em.createQuery(consulta).getResultList();
lista.forEach((p) -&> {
System.out.println(p.getNome());
});
} catch (Exception e) {
e.printStackTrace();
} finally {
em.close();
}
}
}
¿Como funciona exactamente el API de Criteria? . Este API se encarga de diseñar la consulta a través de un Builder, un patrón de diseño que construye un objeto paso a paso

A través de estos pasos se construye el objeto por complejo verificando que todo es correcto. Este es el enfoque JPA Criteria API , vamos construyendo poco a poco cada trazo.

Para después ejecutar esa consulta construida utilizando el EntityManager:

De tal forma que si invocamos la consulta y pasamos los siguientes parámetros
seleccionarPersonas(“pedro”,”perez”);
La consulta se ejecutara sin problemas :

Como el API de Criteria valida cada parámetro , tampoco tendremos problemas si nos inyectan código no válido.
seleccionarPersonas(“pedro”,“”='”);
El Api de Criteria se encargará de revisarlo y generar la consulta parametrizada correcta.

No sufriremos una inyección de SQL.
Otros artículos relacionados:
Usando este segundo enfoque, si la consulta requiere 2 o mas entidades, como se agregan?
gracias.
Con la clausula join 🙂
Hola, gracias por el articulo…tengo una pregunta.
¿En criteria hay evaluación perezosa?, ¿en que orden??
En… Predicate nombreApellidos=cb.or(p1,p2);
¿Es el primer parametro p1 el que prevalece?, ¿es p1 el que si es evaluado a cierto hace que no se evalúe p2?
No , ya que se va construyendo dinamicamente la query y esta es la que se ejecuta completa
Gracias.. por tan excelentes artículos
De nada 🙂