JPA Criteria API , un enfoque diferente

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.

Sin JPA Criteria

 

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.


package com.arquitecturajava;

import java.util.List;

import 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;

public class Principal2 {

	public static void main(String[] args) {

		seleccionarPersonas("pedro","perez");

	}

	private static void seleccionarPersonas(String nombre, 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(nombre!=null) {
				
				 p1= cb.equal(personas.get("nombre"),"pedro");
			}
			
			if(apellidos!=null) {
				
				 p2= cb.equal(personas.get("apellidos"),"perez");	
			}
			
			Predicate nombreApellidos=cb.or(p1,p2);
			
			
			
			consulta.select(personas).where(nombreApellidos);
		
			
			List<Persona> lista =	em.createQuery(consulta).getResultList();
			lista.forEach((p) -> {

				System.out.println(p.getNombre());

			});
		} 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

JPA Criteria y Builders

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:

JPA Criteria Queries

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:

  1. JPA Composite Key y business objects
  2. JPA Single Table Inheritance
  3. Utilizando JPA NamedQueries
  4. Hibernate Criteria
It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

About Cecilio Álvarez Caules

Cecilio Álvarez Caules Sun Certified Enterprise Architech (J2EE/JEE).

2 Responses to JPA Criteria API , un enfoque diferente

  1. Camilo 11 julio, 2017 at 16:45 #

    Gracias.. por tan excelentes artículos

    • Cecilio Álvarez Caules 12 julio, 2017 at 8:48 #

      De nada 🙂

Deja un comentario