I am trying to create a new Page
using a list of objects retrieved from the database. First I get all the elements from the DB, convert it to a Stream and then use lambda to filter the results. Then I need a Page with a set number of elements, however, instantiating a new PageImpl
doesn't seem to return a page with the correct size.
Here is my code:
List<Produtos> listaFinal;
Stream<Produtos> stream = produtosRepository.findAll().stream();
listaFinal = stream.filter(p -> p.getProdNome().contains("uio")).collect(Collectors.toList());
long total = listaFinal.size();
Page<Produtos> imp = new PageImpl<>(listaFinal,pageable,total);
Here's a screenshot from debugging:
Note the size in the Pageable object is set to 20 and it understands that it needs 4 pages to render the 70 elements, but it returns the whole list.
What am I missing?
Edit answering the comment made by Thomas:
I understand how to use Page to return just a slice of the data. The code I showed was my attempt to use a lambda expression to filter my collection. The problem for me is I want to use Java 8's lambda to query the database via Spring Data JPA. Im used to VB.NET's and Entity function(x)
query expressions and was wondering how to do the same with Spring JPA.
In my repository, Im using extends JpaRepository<Produtos, Integer>, QueryDslPredicateExecutor<Produtos>
which gives me access to findAll(Predicate,Pageable)
. However, the Predicate is not typed so I cant simply use p -> p.getProdNome().contains("uio")
in the query. I'm using SQL Server and Hibernate.
after applying a lot of methodes , this was the solution in my case and it's working
PageImpl
is not intended to perform any kind of pagination of your list. From the docs you can see that it's just the "basicPage
implementation" which almost sounds like what you want, but it's really misleading.Use
PagedListHolder
which is a simple state holder for handling lists of objects, separating them into pages.After learning more about how Spring Data works I ended up using
@Query
annotations on my methods inside the JpaRepository implementations to properly query the DB and filter the results, eliminating the need to use a stream and then convert back to Page.Here's how the code above would look in case anyone needs an example:
Im aware of Spring's
findBy
methods but sometimes the method names become really difficult to read depending on the amount of parameters so I just stuck to JPQL.Doing it this way the Page's content will always have up to the maximum amount of elements defined by you in the Spring configuration.
I also use a custom implementation of
PageImpl
, I'm not at work right now and don't have access to the code, but I'll post it whenever I can.Edit: Custom implementation can be found here
If I understood your code right, then your intent is to load all records from the database and and split them into x buckets that are collected in the
PageImpl
, right?Thats not how it used to work. The actual intent of the
Pageable
andPage
abstraction is NOT having to query all the data but just the "slice" of data that is needed.In your case you could query the data via
Page<X> page = repository.findAll(pageable);
and simply return that. Page holds the records for the current page alongside some additional information like e.g., the total number of records and whether there is a next page.In your client code you can use that information to render a list of records and generating next / prev links appropriately. Note that a query with
Page<X>
as result type issues 2 queries (1 to determine the overall total count for the query and 1 for the actual page data).If you don't need the information about the total number of results but still want to be able to generate a next link you should use
Slice<X>
as a return type - since it only issues 1 query.To extend stites' answer, a PagedListHolder is the way to go and here is how:
If you need sorting, use another PagedListHolder constructor with a MutableSortDefinition.