@@ -45,6 +45,7 @@ public class Pager<T> implements Iterator<List<T>>, Constants {
4545 private int totalPages ;
4646 private int totalItems ;
4747 private int currentPage ;
48+ private int kaminariNextPage ;
4849
4950 private List <String > pageParam = new ArrayList <>(1 );
5051 private List <T > currentItems ;
@@ -92,41 +93,74 @@ public class Pager<T> implements Iterator<List<T>>, Constants {
9293 throw new GitLabApiException (e );
9394 }
9495
96+ if (currentItems == null ) {
97+ throw new GitLabApiException ("Invalid response from from GitLab server" );
98+ }
99+
95100 this .api = api ;
96101 this .queryParams = queryParams ;
97102 this .pathArgs = pathArgs ;
103+ this .itemsPerPage = getIntHeaderValue (response , PER_PAGE );
104+
105+ // Some API endpoints do not return the "X-Per-Page" header when there is only 1 page, check for that condition and act accordingly
106+ if (this .itemsPerPage == -1 ) {
107+ this .itemsPerPage = itemsPerPage ;
108+ totalPages = 1 ;
109+ totalItems = currentItems .size ();
110+ return ;
111+ }
98112
99- try {
100- this .itemsPerPage = getHeaderValue (response , PER_PAGE );
101- totalPages = getHeaderValue (response , TOTAL_PAGES_HEADER );
102- totalItems = getHeaderValue (response , TOTAL_HEADER );
103- } catch (GitLabApiException glae ) {
104-
105- // Some API endpoints do not return the proper headers, check for that condition and act accordingly
106- if (currentItems != null && currentItems .size () < itemsPerPage ) {
107- this .itemsPerPage = itemsPerPage ;
113+ totalPages = getIntHeaderValue (response , TOTAL_PAGES_HEADER );
114+ totalItems = getIntHeaderValue (response , TOTAL_HEADER );
115+
116+ // Since GitLab 11.8 and behind the api_kaminari_count_with_limit feature flag,
117+ // if the number of resources is more than 10,000, the X-Total and X-Total-Page
118+ // headers as well as the rel="last" Link are not present in the response headers.
119+ if (totalPages == -1 || totalItems == -1 ) {
120+
121+ int nextPage = getIntHeaderValue (response , NEXT_PAGE_HEADER );
122+ if (nextPage < 2 ) {
108123 totalPages = 1 ;
109124 totalItems = currentItems .size ();
110125 } else {
111- throw ( glae ) ;
126+ kaminariNextPage = 2 ;
112127 }
113128 }
114- }
129+ }
115130
116131 /**
117- * Get the specified integer header value from the Response instance.
132+ * Get the specified header value from the Response instance.
118133 *
119134 * @param response the Response instance to get the value from
120135 * @param key the HTTP header key to get the value for
121- * @return the specified integer header value from the Response instance
136+ * @return the specified header value from the Response instance, or null if the header is not present
122137 * @throws GitLabApiException if any error occurs
123138 */
124- private int getHeaderValue (Response response , String key ) throws GitLabApiException {
139+ private String getHeaderValue (Response response , String key ) throws GitLabApiException {
125140
126141 String value = response .getHeaderString (key );
127142 value = (value != null ? value .trim () : null );
128- if (value == null || value .length () == 0 )
129- throw new GitLabApiException ("Missing '" + key + "' header from server" );
143+ if (value == null || value .length () == 0 ) {
144+ return (null );
145+ }
146+
147+ return (value );
148+ }
149+
150+ /**
151+ * Get the specified integer header value from the Response instance.
152+ *
153+ * @param response the Response instance to get the value from
154+ * @param key the HTTP header key to get the value for
155+ * @return the specified integer header value from the Response instance, or -1 if the header is not present
156+ * @throws GitLabApiException if any error occurs
157+ */
158+ private int getIntHeaderValue (Response response , String key ) throws GitLabApiException {
159+
160+ String value = getHeaderValue (response , key );
161+ if (value == null ) {
162+ return -1 ;
163+ }
130164
131165 try {
132166 return (Integer .parseInt (value ));
@@ -157,7 +191,7 @@ public int getItemsPerPage() {
157191 /**
158192 * Get the total number of pages returned by the GitLab API.
159193 *
160- * @return the total number of pages returned by the GitLab API
194+ * @return the total number of pages returned by the GitLab API, or -1 if the Kaminari limit of 10,000 has been exceeded
161195 */
162196 public int getTotalPages () {
163197 return (totalPages );
@@ -166,7 +200,7 @@ public int getTotalPages() {
166200 /**
167201 * Get the total number of items (T instances) returned by the GitLab API.
168202 *
169- * @return the total number of items (T instances) returned by the GitLab API
203+ * @return the total number of items (T instances) returned by the GitLab API, or -1 if the Kaminari limit of 10,000 has been exceeded
170204 */
171205 public int getTotalItems () {
172206 return (totalItems );
@@ -188,7 +222,7 @@ public int getCurrentPage() {
188222 */
189223 @ Override
190224 public boolean hasNext () {
191- return (currentPage < totalPages );
225+ return (currentPage < totalPages || currentPage < kaminariNextPage );
192226 }
193227
194228 /**
@@ -230,6 +264,11 @@ public List<T> first() throws GitLabApiException {
230264 * @throws GitLabApiException if any error occurs
231265 */
232266 public List <T > last () throws GitLabApiException {
267+
268+ if (kaminariNextPage != 0 ) {
269+ throw new GitLabApiException ("Kaminari count limit exceeded, unable to fetch last page" );
270+ }
271+
233272 return (page (totalPages ));
234273 }
235274
@@ -263,7 +302,7 @@ public List<T> current() throws GitLabApiException {
263302 */
264303 public List <T > page (int pageNumber ) {
265304
266- if (pageNumber > totalPages ) {
305+ if (pageNumber > totalPages && pageNumber > kaminariNextPage ) {
267306 throw new NoSuchElementException ();
268307 } else if (pageNumber < 1 ) {
269308 throw new NoSuchElementException ();
@@ -284,6 +323,11 @@ public List<T> page(int pageNumber) {
284323 Response response = api .get (Response .Status .OK , queryParams , pathArgs );
285324 currentItems = mapper .readValue ((InputStream ) response .getEntity (), javaType );
286325 currentPage = pageNumber ;
326+
327+ if (kaminariNextPage > 0 ) {
328+ kaminariNextPage = getIntHeaderValue (response , NEXT_PAGE_HEADER );
329+ }
330+
287331 return (currentItems );
288332
289333 } catch (GitLabApiException | IOException e ) {
0 commit comments