Skip to content

Commit 768c86a

Browse files
Migrate fetchers to Search.g4 ANTLR parser. (#13691)
* pr: migrate fetchers to Search.g4 ANTLR parser. -Changed inherited fetcher classes to use ANTLR generated classes instead of lucene libraries. - Changed ACMPortalFetcher.java logic for transforming the parsed syntax to URL * pr: migrate fetchers to Search.g4 ANTLR parser. - Changed ACMPortalFetcherTest unit test code to use Search.g4 generated classes instead of Lucene - Removed trivial comment from ACMPortalFetcher * pr: migrate fetchers to Search.g4 ANTLR parser. - Changed AbstractQueryTransformer methods to obey Search.g4 parser rules - Modified ACMPortalFetcher to use the changed transformer logic * Added a new interface for search nodes in order to parse operators correctly * Added 2 new node types and changed SearchQueryNode to implement the new interface * Created a new visitor class for parsing the search syntax and modified the search based fetcher classes to use it * Updated AbstractQueryTransformer to be more in line with the older code while still being compatible with Search.g4 parser * Updated ACMPortalFetcher to use the new parser and node logic * Updated ArxivPortalFetcher to use the new parser and node logic * Updated BvbFetcher and BvbFetcherTest to use the new parser and node logic * Updated DBLPFetcher and DBLPQueryTransformerTest to use the new parser and node logic * Updated DOABFetcher and DOABFetcherTest to use the new parser and node logic * Updated DOAJFetcher to use the new parser and node logic * Updated GoogleScholar and SearchBasedFetcherCapabilityTest to use the new parser and node logic * Updated GvkFetcher GvkFetcherTest and GVKQueryTransformerTest to use the new Search.g4 logic. Fixed how AbstractQueryTransformer handles fields. * Updated IEEE and IEEEQueryTransformerTest to use Search.g4 based parser * Updated InfixTransformerTest to use Search.g4 based parser. * Updated INSPIREFetcher to use Search.g4 based parser. * Updated ISIDOREFetcher and ISIDOREFetcherTest to use Search.g4 based parser * Updated JstorFetcher to use Search.g4 based fetcher * Updated LOBIDFetcher to use Search.g4 based fetcher * Updated MathSciNet to use Search.g4 based fetcher * Changed general exceptions to more specific ones according to feedback * Removed null pointer exception * Removed null pointer exception * Updated ScholarArchiveFetcher to use the ANTLR parser * Updated SpringerFetcher to use the ANTLR parser * Updated rest of the classes needed for compiling * Updated ANTLR parser grammar and updated the transformer testers to be compatible with ANTLR-based parser logic. * Updated ZbMathQueryTransformerTest to throw the appropriate exception * IEEEQueryTransformerTest wont check for the case where the string is just "and" as this is not valid syntax and throws an exception when parsing * SearchBasedFetcher performSearch function now throws fetcher exception if query is not valid * Changed description for function getURLForQuery * Changed how "not comparison expressions" are handled * Added the change to CHANGELOG.md * Update CHANGELOG.md * Reword --------- Co-authored-by: Carl Christian Snethlage <[email protected]>
1 parent 79a78d3 commit 768c86a

File tree

64 files changed

+672
-468
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+672
-468
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
7878
- We introduced walkthrough functionality [#12664](https://github.com/JabRef/jabref/issues/12664)
7979
- The Welcome tab now has a responsive layout. [#12664](https://github.com/JabRef/jabref/issues/12664)
8080
- We introduced a donation prompt in the Welcome tab. [#12664](https://github.com/JabRef/jabref/issues/12664)
81+
- We changed to syntax for the websearch to the one of the main search bar. [#13607](https://github.com/JabRef/jabref/issues/13607)
8182

8283
### Fixed
8384

jablib/src/main/antlr/org/jabref/search/Search.g4

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ CONTAINS: 'CONTAINS';
3939
MATCHES: 'MATCHES';
4040
NOT: 'NOT';
4141

42-
FIELD: [A-Z]+;
42+
FIELD: [A-Z]([A-Z] | '-' | '_')*; // field name should allow for - or _
4343
STRING_LITERAL: '"' ('\\"' | ~["])* '"'; // " should be escaped with a backslash
4444
TERM: ('\\' [=!~()] | ~[ \t\n\r=!~()])+; // =!~() should be escaped with a backslash
4545

jablib/src/main/java/org/jabref/logic/importer/PagedSearchBasedFetcher.java

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@
33
import java.util.ArrayList;
44
import java.util.List;
55

6+
import org.jabref.logic.search.query.SearchQueryVisitor;
67
import org.jabref.model.entry.BibEntry;
78
import org.jabref.model.paging.Page;
9+
import org.jabref.model.search.query.BaseQueryNode;
10+
import org.jabref.model.search.query.SearchQuery;
811

9-
import org.apache.lucene.queryparser.flexible.core.QueryNodeParseException;
10-
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
11-
import org.apache.lucene.queryparser.flexible.core.parser.SyntaxParser;
12-
import org.apache.lucene.queryparser.flexible.standard.parser.StandardSyntaxParser;
12+
import org.antlr.v4.runtime.misc.ParseCancellationException;
1313

1414
public interface PagedSearchBasedFetcher extends SearchBasedFetcher {
1515

1616
/**
17-
* @param luceneQuery the root node of the lucene query
17+
* @param queryNode first search node
1818
* @param pageNumber requested site number indexed from 0
1919
* @return Page with search results
2020
*/
21-
Page<BibEntry> performSearchPaged(QueryNode luceneQuery, int pageNumber) throws FetcherException;
21+
Page<BibEntry> performSearchPaged(BaseQueryNode queryNode, int pageNumber) throws FetcherException;
2222

2323
/**
2424
* @param searchQuery query string that can be parsed into a lucene query
@@ -29,12 +29,12 @@ default Page<BibEntry> performSearchPaged(String searchQuery, int pageNumber) th
2929
if (searchQuery.isBlank()) {
3030
return new Page<>(searchQuery, pageNumber, List.of());
3131
}
32-
SyntaxParser parser = new StandardSyntaxParser();
33-
final String NO_EXPLICIT_FIELD = "default";
32+
SearchQuery searchQueryObject = new SearchQuery(searchQuery);
33+
SearchQueryVisitor visitor = new SearchQueryVisitor(searchQueryObject.getSearchFlags());
3434
try {
35-
return this.performSearchPaged(parser.parse(searchQuery, NO_EXPLICIT_FIELD), pageNumber);
36-
} catch (QueryNodeParseException e) {
37-
throw new FetcherException("An error occurred during parsing of the query.");
35+
return this.performSearchPaged(visitor.visitStart(searchQueryObject.getContext()), pageNumber);
36+
} catch (ParseCancellationException e) {
37+
throw new FetcherException("A syntax error occurred during parsing of the query");
3838
}
3939
}
4040

@@ -48,11 +48,11 @@ default int getPageSize() {
4848
/**
4949
* This method is used to send complex queries using fielded search.
5050
*
51-
* @param luceneQuery the root node of the lucene query
51+
* @param queryNode the first search node
5252
* @return a list of {@link BibEntry}, which are matched by the query (may be empty)
5353
*/
5454
@Override
55-
default List<BibEntry> performSearch(QueryNode luceneQuery) throws FetcherException {
56-
return new ArrayList<>(performSearchPaged(luceneQuery, 0).getContent());
55+
default List<BibEntry> performSearch(BaseQueryNode queryNode) throws FetcherException {
56+
return new ArrayList<>(performSearchPaged(queryNode, 0).getContent());
5757
}
5858
}

jablib/src/main/java/org/jabref/logic/importer/PagedSearchBasedParserFetcher.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,20 @@
99

1010
import org.jabref.model.entry.BibEntry;
1111
import org.jabref.model.paging.Page;
12-
13-
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
12+
import org.jabref.model.search.query.BaseQueryNode;
1413

1514
public interface PagedSearchBasedParserFetcher extends SearchBasedParserFetcher, PagedSearchBasedFetcher, ParserFetcher {
1615

1716
@Override
18-
default Page<BibEntry> performSearchPaged(QueryNode luceneQuery, int pageNumber) throws FetcherException {
17+
default Page<BibEntry> performSearchPaged(BaseQueryNode queryNode, int pageNumber) throws FetcherException {
1918
// ADR-0014
2019
URL urlForQuery;
2120
try {
22-
urlForQuery = getURLForQuery(luceneQuery, pageNumber);
21+
urlForQuery = getURLForQuery(queryNode, pageNumber);
2322
} catch (URISyntaxException | MalformedURLException e) {
2423
throw new FetcherException("Search URI crafted from complex search query is malformed", e);
2524
}
26-
return new Page<>(luceneQuery.toString(), pageNumber, getBibEntries(urlForQuery));
25+
return new Page<>(queryNode.toString(), pageNumber, getBibEntries(urlForQuery));
2726
}
2827

2928
private List<BibEntry> getBibEntries(URL urlForQuery) throws FetcherException {
@@ -41,18 +40,18 @@ private List<BibEntry> getBibEntries(URL urlForQuery) throws FetcherException {
4140
/**
4241
* Constructs a URL based on the query, size and page number.
4342
*
44-
* @param luceneQuery the search query
43+
* @param queryNode the first search node
4544
* @param pageNumber the number of the page indexed from 0
4645
*/
47-
URL getURLForQuery(QueryNode luceneQuery, int pageNumber) throws URISyntaxException, MalformedURLException;
46+
URL getURLForQuery(BaseQueryNode queryNode, int pageNumber) throws URISyntaxException, MalformedURLException;
4847

4948
@Override
50-
default URL getURLForQuery(QueryNode luceneQuery) throws URISyntaxException, MalformedURLException {
51-
return getURLForQuery(luceneQuery, 0);
49+
default URL getURLForQuery(BaseQueryNode queryNode) throws URISyntaxException, MalformedURLException {
50+
return getURLForQuery(queryNode, 0);
5251
}
5352

5453
@Override
55-
default List<BibEntry> performSearch(QueryNode luceneQuery) throws FetcherException {
56-
return SearchBasedParserFetcher.super.performSearch(luceneQuery);
54+
default List<BibEntry> performSearch(BaseQueryNode queryNode) throws FetcherException {
55+
return SearchBasedParserFetcher.super.performSearch(queryNode);
5756
}
5857
}

jablib/src/main/java/org/jabref/logic/importer/SearchBasedFetcher.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@
22

33
import java.util.List;
44

5+
import org.jabref.logic.search.query.SearchQueryVisitor;
56
import org.jabref.model.entry.BibEntry;
7+
import org.jabref.model.search.query.BaseQueryNode;
8+
import org.jabref.model.search.query.SearchQuery;
69

7-
import org.apache.lucene.queryparser.flexible.core.QueryNodeParseException;
8-
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
9-
import org.apache.lucene.queryparser.flexible.core.parser.SyntaxParser;
10-
import org.apache.lucene.queryparser.flexible.standard.parser.StandardSyntaxParser;
11-
12-
import static org.jabref.logic.importer.fetcher.transformers.AbstractQueryTransformer.NO_EXPLICIT_FIELD;
10+
import org.antlr.v4.runtime.misc.ParseCancellationException;
1311

1412
/**
1513
* Searches web resources for bibliographic information based on a free-text query.
@@ -23,28 +21,32 @@ public interface SearchBasedFetcher extends WebFetcher {
2321
/**
2422
* This method is used to send complex queries using fielded search.
2523
*
26-
* @param luceneQuery the root node of the lucene query
24+
* @param queryList the list that contains the parsed nodes
2725
* @return a list of {@link BibEntry}, which are matched by the query (may be empty)
2826
*/
29-
List<BibEntry> performSearch(QueryNode luceneQuery) throws FetcherException;
27+
List<BibEntry> performSearch(BaseQueryNode queryList) throws FetcherException;
3028

3129
/**
3230
* Looks for hits which are matched by the given free-text query.
3331
*
34-
* @param searchQuery query string that can be parsed into a lucene query
32+
* @param searchQuery query string that can be parsed into a search query
3533
* @return a list of {@link BibEntry}, which are matched by the query (may be empty)
3634
*/
3735
default List<BibEntry> performSearch(String searchQuery) throws FetcherException {
3836
if (searchQuery.isBlank()) {
3937
return List.of();
4038
}
4139

42-
SyntaxParser parser = new StandardSyntaxParser();
43-
QueryNode queryNode;
40+
SearchQuery searchQueryObject = new SearchQuery(searchQuery);
41+
if (!searchQueryObject.isValid()) {
42+
throw new FetcherException("The query is not valid");
43+
}
44+
BaseQueryNode queryNode;
45+
SearchQueryVisitor visitor = new SearchQueryVisitor(searchQueryObject.getSearchFlags());
4446
try {
45-
queryNode = parser.parse(searchQuery, NO_EXPLICIT_FIELD);
46-
} catch (QueryNodeParseException e) {
47-
throw new FetcherException("An error occurred when parsing the query");
47+
queryNode = visitor.visitStart(searchQueryObject.getContext());
48+
} catch (ParseCancellationException e) {
49+
throw new FetcherException("A syntax error occurred during parsing of the query");
4850
}
4951

5052
return this.performSearch(queryNode);

jablib/src/main/java/org/jabref/logic/importer/SearchBasedParserFetcher.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
import java.util.List;
99

1010
import org.jabref.model.entry.BibEntry;
11-
12-
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
11+
import org.jabref.model.search.query.BaseQueryNode;
1312

1413
/**
1514
* Provides a convenient interface for search-based fetcher, which follows the usual three-step procedure:
@@ -40,14 +39,14 @@ public interface SearchBasedParserFetcher extends SearchBasedFetcher, ParserFetc
4039
* This method is necessary as the performSearch method does not support certain URL parameters that are used for
4140
* fielded search, such as a title, author, or year parameter.
4241
*
43-
* @param luceneQuery the root node of the lucene query
42+
* @param queryNode the first search node
4443
*/
4544
@Override
46-
default List<BibEntry> performSearch(QueryNode luceneQuery) throws FetcherException {
45+
default List<BibEntry> performSearch(BaseQueryNode queryNode) throws FetcherException {
4746
// ADR-0014
4847
URL urlForQuery;
4948
try {
50-
urlForQuery = getURLForQuery(luceneQuery);
49+
urlForQuery = getURLForQuery(queryNode);
5150
} catch (URISyntaxException | MalformedURLException | FetcherException e) {
5251
throw new FetcherException("Search URI crafted from complex search query is malformed", e);
5352
}
@@ -76,7 +75,7 @@ private List<BibEntry> getBibEntries(URL urlForQuery) throws FetcherException {
7675
/**
7776
* Constructs a URL based on the lucene query.
7877
*
79-
* @param luceneQuery the root node of the lucene query
78+
* @param queryList the list that contains the parsed nodes
8079
*/
81-
URL getURLForQuery(QueryNode luceneQuery) throws URISyntaxException, MalformedURLException, FetcherException;
80+
URL getURLForQuery(BaseQueryNode queryList) throws URISyntaxException, MalformedURLException, FetcherException;
8281
}

jablib/src/main/java/org/jabref/logic/importer/fetcher/ACMPortalFetcher.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
import org.jabref.logic.importer.SearchBasedParserFetcher;
1313
import org.jabref.logic.importer.fetcher.transformers.DefaultQueryTransformer;
1414
import org.jabref.logic.importer.fileformat.ACMPortalParser;
15+
import org.jabref.model.search.query.BaseQueryNode;
1516

1617
import org.apache.hc.core5.net.URIBuilder;
17-
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
1818

1919
public class ACMPortalFetcher implements SearchBasedParserFetcher {
2020

@@ -37,20 +37,20 @@ public Optional<HelpFile> getHelpPage() {
3737
return Optional.of(HelpFile.FETCHER_ACM);
3838
}
3939

40-
private static String createQueryString(QueryNode query) {
41-
return new DefaultQueryTransformer().transformLuceneQuery(query).orElse("");
40+
private static String createQueryString(BaseQueryNode queryNode) {
41+
return new DefaultQueryTransformer().transformSearchQuery(queryNode).orElse("");
4242
}
4343

4444
/**
4545
* Constructing the url for the searchpage.
4646
*
47-
* @param query query node
47+
* @param queryNode the first query node
4848
* @return query URL
4949
*/
5050
@Override
51-
public URL getURLForQuery(QueryNode query) throws URISyntaxException, MalformedURLException {
51+
public URL getURLForQuery(BaseQueryNode queryNode) throws URISyntaxException, MalformedURLException {
5252
URIBuilder uriBuilder = new URIBuilder(SEARCH_URL);
53-
uriBuilder.addParameter("AllField", createQueryString(query));
53+
uriBuilder.addParameter("AllField", createQueryString(queryNode));
5454
return uriBuilder.build().toURL();
5555
}
5656

jablib/src/main/java/org/jabref/logic/importer/fetcher/ArXivFetcher.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@
4545
import org.jabref.model.entry.identifier.DOI;
4646
import org.jabref.model.entry.types.StandardEntryType;
4747
import org.jabref.model.paging.Page;
48+
import org.jabref.model.search.query.BaseQueryNode;
4849
import org.jabref.model.strings.StringUtil;
4950
import org.jabref.model.util.OptionalUtil;
5051

5152
import org.apache.hc.core5.net.URIBuilder;
52-
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
5353
import org.slf4j.Logger;
5454
import org.slf4j.LoggerFactory;
5555
import org.w3c.dom.Document;
@@ -332,13 +332,13 @@ private void inplaceAsyncInfuseArXivWithDoi(CompletableFuture<Optional<BibEntry>
332332
* Constructs a complex query string using the field prefixes specified at https://arxiv.org/help/api/user-manual
333333
* and modify resulting BibEntries with additional info from the ArXiv-issued DOI
334334
*
335-
* @param luceneQuery the root node of the lucene query
335+
* @param queryNode the first search query node
336336
* @return A list of entries matching the complex query
337337
*/
338338
@Override
339-
public Page<BibEntry> performSearchPaged(QueryNode luceneQuery, int pageNumber) throws FetcherException {
339+
public Page<BibEntry> performSearchPaged(BaseQueryNode queryNode, int pageNumber) throws FetcherException {
340340

341-
Page<BibEntry> result = arXiv.performSearchPaged(luceneQuery, pageNumber);
341+
Page<BibEntry> result = arXiv.performSearchPaged(queryNode, pageNumber);
342342
if (this.doiFetcher == null) {
343343
return result;
344344
}
@@ -604,13 +604,13 @@ public Optional<HelpFile> getHelpPage() {
604604
/**
605605
* Constructs a complex query string using the field prefixes specified at https://arxiv.org/help/api/user-manual
606606
*
607-
* @param luceneQuery the root node of the lucene query
607+
* @param queryNode the first search node
608608
* @return A list of entries matching the complex query
609609
*/
610610
@Override
611-
public Page<BibEntry> performSearchPaged(QueryNode luceneQuery, int pageNumber) throws FetcherException {
611+
public Page<BibEntry> performSearchPaged(BaseQueryNode queryNode, int pageNumber) throws FetcherException {
612612
ArXivQueryTransformer transformer = new ArXivQueryTransformer();
613-
String transformedQuery = transformer.transformLuceneQuery(luceneQuery).orElse("");
613+
String transformedQuery = transformer.transformSearchQuery(queryNode).orElse("");
614614
List<BibEntry> searchResult = searchForEntries(transformedQuery, pageNumber)
615615
.stream()
616616
.map(arXivEntry -> arXivEntry.toBibEntry(importFormatPreferences.bibEntryPreferences().getKeywordSeparator()))

jablib/src/main/java/org/jabref/logic/importer/fetcher/AstrophysicsDataSystem.java

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@
3333
import org.jabref.model.entry.field.StandardField;
3434
import org.jabref.model.entry.field.UnknownField;
3535
import org.jabref.model.paging.Page;
36+
import org.jabref.model.search.query.BaseQueryNode;
3637
import org.jabref.model.strings.StringUtil;
3738

3839
import kong.unirest.core.json.JSONArray;
3940
import kong.unirest.core.json.JSONException;
4041
import kong.unirest.core.json.JSONObject;
4142
import org.apache.hc.core5.net.URIBuilder;
42-
import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode;
4343

4444
/**
4545
* Fetches data from the SAO/NASA Astrophysics Data System (<a href="https://ui.adsabs.harvard.edu/">https://ui.adsabs.harvard.edu/</a>)
@@ -81,13 +81,14 @@ public String getName() {
8181
}
8282

8383
/**
84-
* @param luceneQuery query string, matching the apache solr format
84+
* @param queryList the list that contains the parsed nodes
8585
* @return URL which points to a search request for given query
8686
*/
8787
@Override
88-
public URL getURLForQuery(QueryNode luceneQuery, int pageNumber) throws URISyntaxException, MalformedURLException {
88+
public URL getURLForQuery(BaseQueryNode queryList, int pageNumber) throws URISyntaxException, MalformedURLException {
8989
URIBuilder builder = new URIBuilder(API_SEARCH_URL);
90-
builder.addParameter("q", new DefaultQueryTransformer().transformLuceneQuery(luceneQuery).orElse(""));
90+
builder.addParameter("q", new DefaultQueryTransformer().transformSearchQuery(queryList).orElse(""));
91+
builder.addParameter("q", "");
9192
builder.addParameter("fl", "bibcode");
9293
builder.addParameter("rows", String.valueOf(getPageSize()));
9394
builder.addParameter("start", String.valueOf(getPageSize() * pageNumber));
@@ -278,10 +279,10 @@ private List<BibEntry> performSearchByIds(Collection<String> identifiers) throws
278279
}
279280

280281
@Override
281-
public List<BibEntry> performSearch(QueryNode luceneQuery) throws FetcherException {
282+
public List<BibEntry> performSearch(BaseQueryNode queryList) throws FetcherException {
282283
URL urlForQuery;
283284
try {
284-
urlForQuery = getURLForQuery(luceneQuery);
285+
urlForQuery = getURLForQuery(queryList);
285286
} catch (URISyntaxException | MalformedURLException e) {
286287
throw new FetcherException("Search URI is malformed", e);
287288
}
@@ -290,17 +291,17 @@ public List<BibEntry> performSearch(QueryNode luceneQuery) throws FetcherExcepti
290291
}
291292

292293
@Override
293-
public Page<BibEntry> performSearchPaged(QueryNode luceneQuery, int pageNumber) throws FetcherException {
294+
public Page<BibEntry> performSearchPaged(BaseQueryNode queryList, int pageNumber) throws FetcherException {
294295
URL urlForQuery;
295296
try {
296-
urlForQuery = getURLForQuery(luceneQuery, pageNumber);
297+
urlForQuery = getURLForQuery(queryList, pageNumber);
297298
} catch (URISyntaxException | MalformedURLException e) {
298299
throw new FetcherException("Search URI is malformed", e);
299300
}
300301
// This is currently just interpreting the complex query as a default string query
301302
List<String> bibCodes = fetchBibcodes(urlForQuery);
302303
Collection<BibEntry> results = performSearchByIds(bibCodes);
303-
return new Page<>(luceneQuery.toString(), pageNumber, results);
304+
return new Page<>(queryList.toString(), pageNumber, results);
304305
}
305306

306307
@Override

0 commit comments

Comments
 (0)