Last active
September 26, 2023 06:21
-
-
Save josericardo/5102304 to your computer and use it in GitHub Desktop.
Helper to iterate over pageable sources. Should reduce memory usage when querying large tables via Spring Data.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
====================================== | |
Usage: | |
Fetcher<Source, MyEntity> f = new Fetcher<Source, MyEntity>(source) { | |
@Override | |
public List<MyEntity> fetch(Pageable pageRequest) | |
{ | |
return source.findAll(pageRequest); | |
} | |
}; | |
PageableCollection<Source,MyEntity> pageableCollection = new PageableCollection<Source, MyEntity>(f); | |
for (MyEntity e : pageableCollection) { | |
// ... | |
} | |
============================================================================ | |
public class PageableCollection<T> implements Iterable<T> | |
{ | |
private static final int DEFAULT_PAGE_SIZE = 100; | |
private Fetcher<?, T> fetcher; | |
private int pageSize; | |
public PageableCollection(Fetcher<?, T> f) { | |
this(f, DEFAULT_PAGE_SIZE); | |
} | |
public PageableCollection(Fetcher<?, T> f, int pageSize) | |
{ | |
this.fetcher = f; | |
this.pageSize = pageSize; | |
} | |
@Override | |
public Iterator<T> iterator() | |
{ | |
return new PageableIterator<T>(fetcher, pageSize); | |
} | |
} | |
/** | |
* Initially makes sense only inside the PageableCollection class | |
*/ | |
class PageableIterator<T> implements Iterator<T> | |
{ | |
private static final int FIRST_PAGE = 0; | |
private List<T> currentData; | |
private int cursor; | |
private int pageSize; | |
private Pageable page; | |
private Fetcher<?, T> fetcher; | |
public PageableIterator(Fetcher<?, T> f, int pageSize) { | |
this.fetcher = f; | |
this.pageSize = pageSize; | |
page = new PageRequest(FIRST_PAGE, pageSize); | |
currentData = new ArrayList<T>(); | |
} | |
@Override | |
public boolean hasNext() | |
{ | |
if (hasDataLoaded()) { | |
return true; | |
} | |
tryToFetchMoreData(); | |
return !currentData.isEmpty(); | |
} | |
private void tryToFetchMoreData() | |
{ | |
currentData = fetcher.fetch(page); | |
page = new PageRequest(page.getPageNumber()+1, pageSize); | |
cursor = 0; | |
} | |
private boolean hasDataLoaded() | |
{ | |
return cursor < currentData.size(); | |
} | |
@Override | |
public T next() | |
{ | |
return currentData.get(cursor++); | |
} | |
@Override | |
public void remove() | |
{ | |
throw new UnsupportedOperationException(); | |
} | |
} | |
public abstract class Fetcher<S, T> | |
{ | |
protected S source; | |
public Fetcher(S s) { | |
this.source = s; | |
} | |
public abstract List<T> fetch(Pageable pageRequest); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks a lot,
I just refactored it to make usage more readable and general:
=============================================================
Usage:
=============================================================
=============================================================
=============================================================