In un'applicazione Web che utilizza Spring Data JPA con Hibernate, utilizziamo la funzionalità web pagination per fornire funzionalità di impaginazione e ordinamento in vari elenchi di entità.Dati Spring JPA Parametri page.sort non validi
@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);
}
Questo permette oggetti di entità da definire in html reso come speciale sorta request parameters, dove il valore page.sort
corrisponde in effetti una proprietà nell'entità su cui ordinare.
<table>
<thead>
<tr>
<th><a href="?page.sort=propertyX&page.sort.dir=asc">Property X</a></th>
<th><a href="?page.sort=propertyY&page.sort.dir=asc">Property Y</a></th>
</tr>
</thead>
<tbody>...</tbody>
</table>
Questo produce un URL risultante come ad esempio:
http://host/context-root/entities/?page.sort=propertyX&page.sort.dir=asc
Il problema è che gli utenti possono modificare l'URL da utilizzare valida page.sort
proprietà che sia di riferimento i nomi di colonna/di proprietà inesistenti o, peggio, che utilizza caratteri di query JPA non validi che producono una sintassi non valida.
Ad esempio, se l'URL viene modificato per ordinare su "noSuchProperty":
http://host/context-root/entities/?page.sort=noSuchProperty&page.sort.dir=asc
ma questa proprietà non esiste, saranno gettati la seguente eccezione:
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
Allo stesso modo, se l'URL viene modificato per un carattere sintassi di query non valida, ad esempio "" ":
http://host/context-root/entities/?page.sort=%22&page.sort.dir=asc
il seguente err o si verificherà:
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)
(C'è anche un terzo sapore di eccezioni che si traduce in un org.hibernate.QueryException
quando il @Query
è definito esplicitamente sul metodo Repository.)
primavera dati JPA astrae i dettagli della ordinamento, impaginazione e gestione di questi parametri; tuttavia, non sembra gestire con grazia questi scenari (vale a dire dove viene specificato un parametro di ordinamento non valido).
È possibile aggiungere alcune regole personalizzate aggiuntive per convalidare che la proprietà di ordinamento esista effettivamente nell'entità; tuttavia, mi chiedo se ci sia un approccio più pulito e centralizzato per fare ciò in modo tale da non perdere i vantaggi e la semplicità delle astrazioni JPA di Spring Data. Utilizziamo questa capacità di ordinamento in tutta la nostra app con molte entità diverse, quindi idealmente, vorremmo più di un approccio generico, piuttosto che dover definire o controllare esplicitamente le proprietà di ordinamento per ogni pagina di entità richiesta. In particolare, estendiamo effettivamente il PageableArgumentResolver
per accettare un valore predefinito di ordinamento annotato fornito nel nostro controller (non illustrato negli esempi di codice per semplicità), quindi ci piacerebbe solo ricorrere a questo ordinamento predefinito, o solo l'ordine di ordinamento predefinito per l'entità, piuttosto che generare un'eccezione.
Alcune idee e tentativi .. Potrei usare un QueryCreationListener
per intercettare la creazione della query e ottenere il parametro sort; tuttavia, non posso realmente modificare la query a quel punto. Oppure, posso estendere e utilizzare un custom PageableArgumentResolver
(lo stiamo già facendo) per ottenere i parametri di ordinamento; tuttavia, non ho accesso all'entità a quel punto, né la capacità di determinare se l'entità abbia effettivamente una proprietà con quel nome.Potremmo dichiarare esplicitamente le proprietà supportate; tuttavia, ancora una volta, questo sconfigge l'idea di gestire centralmente e automaticamente questo scenario senza richiedere una conoscenza specifica o dichiarata delle entità.
Esiste un altro tipo di intercettore o costrutto simile che possa utilizzare per convalidare centralmente i parametri di ordinamento pageable e modificare se necessario prima di richiamare la query? O c'è qualche tipo di configurazione o modo in cui Spring può gestire automaticamente questo scenario in modo tale che gestisca più correttamente i parametri di ordinamento non validi?