2012-06-27 12 views
6

En una aplicación web que utiliza Spring Data JPA con Hibernate, utilizamos la funcionalidad web pagination para proporcionar funciones de paginación y clasificación en varias listas de entidades.Spring Data JPA no válido page.sort Parámetros

@Controller 
public class MyEntityController { 
    @RequestMapping(method = RequestMethod.GET) 
    public ModelAndView list(Pageable pageable) { ... } 
} 

@Configuration 
public class MyWebMvcConfig extends WebMvcConfigurationSupport { 
    @Override 
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { 
     super.addArgumentResolvers(argumentResolvers); 
     argumentResolvers.add(new PageableArgumentResolver()); 
    } 
} 

public interface MyEntityRepository extends PagingAndSortingRepository<MyEntity, String> { 
    Page<MyEntity> findByPropertyX(String propertyX, Pageable pagable); 
} 

Esto permite propiedades de la entidad que se definirán en el HTML representado como una especie especial request parameters, donde el valor page.sort realidad coincide con una propiedad en la entidad en el que se ordenan.

<table> 
    <thead> 
     <tr> 
      <th><a href="?page.sort=propertyX&amp;page.sort.dir=asc">Property X</a></th> 
      <th><a href="?page.sort=propertyY&amp;page.sort.dir=asc">Property Y</a></th> 
     </tr> 
    </thead> 
    <tbody>...</tbody> 
</table> 

Esto produce una URL que se obtiene como:

http://host/context-root/entities/?page.sort=propertyX&page.sort.dir=asc 

El es que los usuarios pueden modificar la dirección URL a usar inválida page.sort propiedades problema de que los nombres de cualquiera de referencia inexistentes columna/propiedad, o peor aún, que utilizan caracteres de consulta JPA no válidos que dan como resultado una sintaxis no válida.

Por ejemplo, si la URL es modificado para ordenar en "noSuchProperty":

http://host/context-root/entities/?page.sort=noSuchProperty&page.sort.dir=asc 

Pero esta propiedad no existe, se lanzará la siguiente excepción:

java.lang.IllegalArgumentException: No property noSuchProperty found for type class com.my.company.MyEntity 
    at org.springframework.data.repository.query.parser.Property.<init>(Property.java:76) 
    . . . 
    at org.springframework.data.repository.query.parser.AbstractQueryCreator.createQuery(AbstractQueryCreator.java:86) 
    . . . 
    at $Proxy68.findByPropertyX(Unknown Source) 
    at com.my.company.MyEntityRepository.findByPropertyX(MyEntityRepository.java:17 

Del mismo modo, si la URL se modifica a un carácter de sintaxis de consulta no válida, como "" ":

http://host/context-root/entities/?page.sort=%22&page.sort.dir=asc 

Lo que sigue o se producirá:

java.lang.StackOverflowError 
    java.util.regex.Pattern$GroupTail.match(Pattern.java:4227) 
    . . . 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 
    org.springframework.data.repository.query.parser.Property.create(Property.java:326) 

(Hay también un tercer sabor de excepciones que resulta en una org.hibernate.QueryException cuando el @Query se define explícitamente en el método de repositorio.)

primavera de datos JPA abstrae los detalles de la clasificación, paginación y manejo de estos parámetros; sin embargo, no parece manejar con elegancia estos escenarios (es decir, cuando se especifica un parámetro de clasificación no válido).

Podríamos agregar algo de lógica personalizada adicional para validar que la propiedad de ordenamiento realmente existe en la entidad; sin embargo, me pregunto si existe un enfoque más centralizado y más limpio para hacer esto, de modo que no perdamos los beneficios y la simplicidad de las abstracciones de Spring Data JPA. Usamos esta capacidad de clasificación en toda nuestra aplicación con muchas entidades diferentes, por lo que, idealmente, desearíamos un enfoque más genérico, en lugar de tener que definir explícitamente o verificar las propiedades de clasificación para cada página de entidad solicitada.

Específicamente, ampliamos el PageableArgumentResolver para aceptar un valor predeterminado de orden anotado que se proporciona en nuestro controlador (no ilustrado en los ejemplos del código por simplicidad), por lo que nos gustaría recurrir a este orden de clasificación predeterminado, o solo el orden de clasificación predeterminado para la entidad, en lugar de lanzar una excepción.

Algunas ideas e intentos .. Podría usar un QueryCreationListener para interceptar la creación de la consulta y obtener el parámetro de ordenamiento; sin embargo, no puedo modificar la consulta en ese momento. O bien, puedo extender y usar un PageableArgumentResolver personalizado (ya lo estamos haciendo) para obtener los parámetros de clasificación; sin embargo, no tengo acceso a la entidad en ese punto, ni la capacidad de determinar si la entidad tiene realmente una propiedad con ese nombre.Podríamos declarar explícitamente las propiedades compatibles; sin embargo, una vez más, esto frustra la idea de manejar de forma central y automática este escenario sin requerir un conocimiento específico o declarado de las entidades.

¿Hay algún otro tipo de interceptor o construcción similar que pueda utilizar para validar centralmente los parámetros de clasificación paginable y modificarlos si es necesario antes de invocar la consulta? ¿O hay algún tipo de configuración o forma en que Spring pueda manejar automáticamente este escenario de manera que maneje con mayor gracia los parámetros de clasificación no válidos?

Respuesta

3

Estaba echando un vistazo al código y creo que un poco más del trazado de la pila sería útil. Pero, por lo que puedo ver, creo que hay dos lugares en los que podría tratar si tiene ganas de reescribir algún código de Spring.

Existen dos escenarios aquí, en el primero de ellos está pasando un campo de ordenación que no existe en el objeto/tabla. Lo que realmente desea es que ese parámetro incorrecto se ignore silenciosamente todo el tiempo, no solo cuando se pasa un 1 PageableArgumentResolver] 1. Estoy pensando que debería ser una opción en el AbstractQueryCreator (y por lo tanto, el JpaQueryCreator) para ignorar los parámetros incorrectos en una ordenación.

La segunda parte que debe abordarse es probablemente la PageableArgumentResolver. Si pasa cadenas vacías o algo que no tiene sentido como %20, entonces debe ignorar ese parámetro y no enviarlo a través del PageRequest.

Happy hacking y buena suerte. Leer tu publicación me ha hecho darme cuenta de que mi sitio es vulnerable al mismo problema y realmente no tengo una buena solución.

1

Creo que mejorar el PageableArgumentResolver para manejar con gracia esos escenarios. Podría intentar crear una instancia PropertyPath desde String entregada como Sort y así asegurarse de que sea válida. Estoy un poco desgarrado sobre si tiene sentido simplemente dejar caer el String inválido de forma predeterminada, lo que devolvería el resultado no ordenado en absoluto. Esta es probablemente la experiencia más fluida, pero también podría llevar a tediosos intentos de averiguar por qué el resultado no está ordenado.

Sin embargo, esto. Sería genial si pudieras subir un boleto JIRA contra Spring Data Commons y simplemente vincular este boleto aquí. Siéntase libre de abrir una solicitud de extracción en caso de que haya concretado una implementación viable. Gracias por traer esto a la mesa ya!

Cuestiones relacionadas