Skip to content

Commit 9ab7cb2

Browse files
authored
Merge pull request #1487 from microsoftgraph/dev
3.1.1 release
2 parents 1b03a1e + c71f45e commit 9ab7cb2

File tree

7 files changed

+154
-83
lines changed

7 files changed

+154
-83
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Changed
1313

14+
## [3.1.1] - 2024-02-09
15+
16+
### Changed
17+
18+
- Fixes a bug to allow the PageIterator to iterate across all pages.
19+
1420
## [3.1.0] - 2024-02-07
1521

1622
### Changed

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ mavenGroupId = com.microsoft.graph
2525
mavenArtifactId = microsoft-graph-core
2626
mavenMajorVersion = 3
2727
mavenMinorVersion = 1
28-
mavenPatchVersion = 0
28+
mavenPatchVersion = 1
2929
mavenArtifactSuffix =
3030

3131
#These values are used to run functional tests

src/main/java/com/microsoft/graph/core/tasks/PageIterator.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
/**
1919
* A class for iterating through pages of a collection
20-
* Uses to automatically pages through result sets across multiple calls and process each item in the result set.
20+
* Use to automatically page through result sets across multiple calls and process each item in the result set.
2121
* @param <TEntity> The type of the entity returned in the collection. This type must implement {@link Parsable}
2222
* @param <TCollectionPage> The Microsoft Graph collection response type returned in the collection response. This type must implement {@link Parsable} and {@link AdditionalDataHolder}
2323
*/
@@ -302,16 +302,14 @@ protected static <TEntity extends Parsable, TCollectionPage extends Parsable & A
302302
}
303303
private static <TCollectionPage extends Parsable & AdditionalDataHolder> String extractNextLinkFromParsable(@Nonnull TCollectionPage parsableCollection, @Nullable String getNextLinkMethodName) throws ReflectiveOperationException {
304304
String methodName = getNextLinkMethodName == null ? CoreConstants.CollectionResponseMethods.GET_ODATA_NEXT_LINK : getNextLinkMethodName;
305-
Method[] methods = parsableCollection.getClass().getDeclaredMethods();
305+
Method[] methods = parsableCollection.getClass().getMethods();
306306
String nextLink;
307-
if(Arrays.stream(methods).anyMatch(m -> m.getName().equals(methodName))) {
308-
try {
309-
nextLink = (String) parsableCollection.getClass().getDeclaredMethod(methodName).invoke(parsableCollection);
310-
if(!Compatibility.isBlank(nextLink)) {
311-
return nextLink;
312-
}
313-
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
314-
throw new ReflectiveOperationException("Could not extract nextLink from parsableCollection.");
307+
Optional<Method> nextLinkOptional = Arrays.stream(methods).filter(m -> m.getName().equals(methodName)).findFirst();
308+
if (nextLinkOptional.isPresent()) {
309+
Method nextLinkMethod = nextLinkOptional.get();
310+
nextLink = (String) nextLinkMethod.invoke(parsableCollection);
311+
if(!Compatibility.isBlank(nextLink)) {
312+
return nextLink;
315313
}
316314
}
317315
nextLink = (String) parsableCollection.getAdditionalData().get(CoreConstants.OdataInstanceAnnotations.NEXT_LINK);

src/test/java/com/microsoft/graph/core/tasks/PageIteratorTest.java

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import java.util.HashMap;
1919
import java.util.LinkedList;
2020
import java.util.List;
21+
import java.util.concurrent.atomic.AtomicBoolean;
22+
import java.util.concurrent.atomic.AtomicInteger;
2123
import java.util.function.Function;
2224
import java.util.function.UnaryOperator;
2325

@@ -152,13 +154,10 @@ void given_CollectionPage_Without_NextLink_Property_It_Iterates_Across_Pages() t
152154
secondPage.getValue().add(testEventItem);
153155
}
154156

155-
final Boolean[] reachedNextPage = {false};
157+
AtomicInteger totalItemsProcessed = new AtomicInteger(0);
156158

157159
Function<TestEventItem, Boolean> processPageItemCallback = item -> {
158-
if(item.getSubject().contains("Second Page Test Event")) {
159-
reachedNextPage[0] = true;
160-
return false;
161-
}
160+
totalItemsProcessed.incrementAndGet();
162161
return true;
163162
};
164163

@@ -172,27 +171,42 @@ void given_CollectionPage_Without_NextLink_Property_It_Iterates_Across_Pages() t
172171

173172
pageIterator.iterate();
174173

175-
assertTrue(reachedNextPage[0]);
176-
assertEquals(PageIterator.PageIteratorState.PAUSED, pageIterator.getPageIteratorState());
177-
assertEquals("http://localhost/events?$skip=11", pageIterator.getNextLink());
178-
174+
assertEquals(PageIterator.PageIteratorState.COMPLETE, pageIterator.getPageIteratorState());
175+
assertEquals("", pageIterator.getNextLink());
176+
assertEquals(inputEventCount + secondPageEventCount, totalItemsProcessed.get());
179177
}
180178
@Test
181179
void given_CollectionPage_Delta_Link_Property_It_Iterates_Across_Pages() throws ReflectiveOperationException, ApiException {
182180
TestEventsDeltaResponse originalPage = new TestEventsDeltaResponse();
183181
originalPage.setValue(new LinkedList<>());
184-
originalPage.setOdataDeltaLink("http://localhost/events?$skip=11");
182+
originalPage.setOdataNextLink("http://localhost/events?$skip=11");
185183
int inputEventCount = 17;
186184
for(int i = 0; i < inputEventCount; i++) {
187185
TestEventItem testEventItem = new TestEventItem();
188186
testEventItem.setSubject("Test Event: " + i);
189187
originalPage.getValue().add(testEventItem);
190188
}
191189

192-
Function<TestEventItem, Boolean> processPageItemCallback = item -> true;
190+
TestEventsDeltaResponse secondPage = new TestEventsDeltaResponse();
191+
secondPage.setValue(new LinkedList<TestEventItem>());
192+
secondPage.setOdataDeltaLink("http://localhost/events?$skip=11");
193+
int secondPageEventCount = 5;
194+
for(int i = 0; i < secondPageEventCount; i++) {
195+
TestEventItem testEventItem = new TestEventItem();
196+
testEventItem.setSubject("Second Page Test Event: " + i);
197+
secondPage.getValue().add(testEventItem);
198+
}
199+
200+
AtomicInteger totalItemsProcessed = new AtomicInteger(0);
201+
202+
Function<TestEventItem, Boolean> processPageItemCallback = item -> {
203+
totalItemsProcessed.incrementAndGet();
204+
return true;
205+
};
193206

207+
MockAdapter mockAdapter = new MockAdapter(mock(AuthenticationProvider.class), secondPage);
194208
PageIterator<TestEventItem, TestEventsDeltaResponse> pageIterator = new PageIterator.Builder<TestEventItem, TestEventsDeltaResponse>()
195-
.client(baseClient)
209+
.requestAdapter(mockAdapter)
196210
.collectionPage(originalPage)
197211
.collectionPageFactory(TestEventsDeltaResponse::createFromDiscriminatorValue)
198212
.processPageItemCallback(processPageItemCallback)
@@ -202,6 +216,7 @@ void given_CollectionPage_Delta_Link_Property_It_Iterates_Across_Pages() throws
202216

203217
assertEquals(PageIterator.PageIteratorState.DELTA, pageIterator.getPageIteratorState());
204218
assertEquals("http://localhost/events?$skip=11", pageIterator.getDeltaLink());
219+
assertEquals(inputEventCount + secondPageEventCount, totalItemsProcessed.get());
205220
}
206221

207222
@Test
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package com.microsoft.graph.core.testModels;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
import java.util.Objects;
6+
7+
import com.microsoft.kiota.serialization.AdditionalDataHolder;
8+
import com.microsoft.kiota.serialization.Parsable;
9+
import com.microsoft.kiota.serialization.ParseNode;
10+
import com.microsoft.kiota.serialization.SerializationWriter;
11+
12+
public class BaseCollectionPaginationCountResponse implements AdditionalDataHolder, Parsable {
13+
public Map<String, Object> additionalData;
14+
private String odataNextLink;
15+
private Long odataCount;
16+
/**
17+
* Instantiates a new BaseCollectionPaginationCountResponse and sets the default values.
18+
*/
19+
public BaseCollectionPaginationCountResponse() {
20+
this.setAdditionalData(new HashMap<>());
21+
}
22+
/**
23+
* Creates a new instance of the appropriate class based on discriminator value
24+
* @param parseNode The parse node to use to read the discriminator value and create the object
25+
* @return a BaseCollectionPaginationCountResponse
26+
*/
27+
@jakarta.annotation.Nonnull
28+
public static BaseCollectionPaginationCountResponse createFromDiscriminatorValue(@jakarta.annotation.Nonnull final ParseNode parseNode) {
29+
Objects.requireNonNull(parseNode);
30+
return new BaseCollectionPaginationCountResponse();
31+
}
32+
/**
33+
* Gets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.
34+
* @return a Map<String, Object>
35+
*/
36+
@jakarta.annotation.Nonnull
37+
public Map<String, Object> getAdditionalData() {
38+
return this.additionalData;
39+
}
40+
/**
41+
* The deserialization information for the current model
42+
* @return a Map<String, java.util.function.Consumer<ParseNode>>
43+
*/
44+
@jakarta.annotation.Nonnull
45+
public Map<String, java.util.function.Consumer<ParseNode>> getFieldDeserializers() {
46+
final HashMap<String, java.util.function.Consumer<ParseNode>> deserializerMap = new HashMap<String, java.util.function.Consumer<ParseNode>>(2);
47+
deserializerMap.put("@odata.count", (n) -> { this.setOdataCount(n.getLongValue()); });
48+
deserializerMap.put("@odata.nextLink", (n) -> { this.setOdataNextLink(n.getStringValue()); });
49+
return deserializerMap;
50+
}
51+
/**
52+
* Gets the @odata.count property value. The OdataCount property
53+
* @return a Long
54+
*/
55+
@jakarta.annotation.Nullable
56+
public Long getOdataCount() {
57+
return this.odataCount;
58+
}
59+
/**
60+
* Gets the @odata.nextLink property value. The OdataNextLink property
61+
* @return a String
62+
*/
63+
@jakarta.annotation.Nullable
64+
public String getOdataNextLink() {
65+
return this.odataNextLink;
66+
}
67+
/**
68+
* Serializes information the current object
69+
* @param writer Serialization writer to use to serialize this model
70+
*/
71+
public void serialize(@jakarta.annotation.Nonnull final SerializationWriter writer) {
72+
Objects.requireNonNull(writer);
73+
writer.writeLongValue("@odata.count", this.getOdataCount());
74+
writer.writeStringValue("@odata.nextLink", this.getOdataNextLink());
75+
writer.writeAdditionalData(this.getAdditionalData());
76+
}
77+
/**
78+
* Sets the AdditionalData property value. Stores additional data not described in the OpenAPI description found when deserializing. Can be used for serialization as well.
79+
* @param value Value to set for the AdditionalData property.
80+
*/
81+
public void setAdditionalData(@jakarta.annotation.Nullable final Map<String, Object> value) {
82+
this.additionalData = value;
83+
}
84+
/**
85+
* Sets the @odata.count property value. The OdataCount property
86+
* @param value Value to set for the @odata.count property.
87+
*/
88+
public void setOdataCount(@jakarta.annotation.Nullable final Long value) {
89+
this.odataCount = value;
90+
}
91+
/**
92+
* Sets the @odata.nextLink property value. The OdataNextLink property
93+
* @param value Value to set for the @odata.nextLink property.
94+
*/
95+
public void setOdataNextLink(@jakarta.annotation.Nullable final String value) {
96+
this.odataNextLink = value;
97+
}
98+
}

src/test/java/com/microsoft/graph/core/testModels/TestEventsDeltaResponse.java

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,12 @@
88
import java.util.*;
99
import java.util.function.Consumer;
1010

11-
public class TestEventsDeltaResponse implements Parsable, AdditionalDataHolder {
12-
public Map<String, Object> additionalData;
11+
public class TestEventsDeltaResponse extends BaseCollectionPaginationCountResponse {
1312
private String odataDeltaLink;
14-
private String odataNextLink;
1513
public List<TestEventItem> value;
1614

1715
public TestEventsDeltaResponse() {
18-
additionalData = new HashMap<>();
19-
}
20-
21-
public Map<String, Object> getAdditionalData() {
22-
return additionalData;
23-
}
24-
25-
public void setAdditionalData(Map<String, Object> additionalData) {
26-
this.additionalData = additionalData;
16+
super();
2717
}
2818

2919
public String getOdataDeltaLink() {
@@ -34,14 +24,6 @@ public void setOdataDeltaLink(String odataDeltaLink) {
3424
this.odataDeltaLink = odataDeltaLink;
3525
}
3626

37-
public String getOdataNextLink() {
38-
return odataNextLink;
39-
}
40-
41-
public void setOdataNextLink(String odataNextLink) {
42-
this.odataNextLink = odataNextLink;
43-
}
44-
4527
public List<TestEventItem> getValue() {
4628
return value;
4729
}
@@ -51,22 +33,15 @@ public void setValue(List<TestEventItem> value) {
5133
}
5234

5335
public Map<String, Consumer<ParseNode>> getFieldDeserializers() {
54-
HashMap<String, Consumer<ParseNode>> fieldDeserializers = new HashMap<>();
55-
fieldDeserializers.put("@odata.deltaLink", (n) -> setOdataDeltaLink(n.getStringValue()));
56-
fieldDeserializers.put("@odata.nextLink", (n) -> setOdataNextLink(n.getStringValue()));
57-
fieldDeserializers.put("value", (n) -> setValue(n.getCollectionOfObjectValues(TestEventItem::createFromDiscriminatorValue)));
58-
return fieldDeserializers;
36+
final HashMap<String, java.util.function.Consumer<ParseNode>> deserializerMap = new HashMap<String, java.util.function.Consumer<ParseNode>>(super.getFieldDeserializers());
37+
deserializerMap.put("value", (n) -> { this.setValue(n.getCollectionOfObjectValues(TestEventItem::createFromDiscriminatorValue)); });
38+
return deserializerMap;
5939
}
6040

6141
public void serialize(SerializationWriter writer) {
62-
if (writer == null) {
63-
throw new IllegalArgumentException("writer");
64-
}
65-
66-
writer.writeStringValue("@odata.deltaLink", odataDeltaLink);
67-
writer.writeStringValue("@odata.nextLink", odataNextLink);
68-
writer.writeCollectionOfObjectValues("value", value);
69-
writer.writeAdditionalData(additionalData);
42+
Objects.requireNonNull(writer);
43+
super.serialize(writer);
44+
writer.writeCollectionOfObjectValues("value", getValue());
7045
}
7146

7247
public static TestEventsDeltaResponse createFromDiscriminatorValue(ParseNode parseNode) {

src/test/java/com/microsoft/graph/core/testModels/TestEventsResponse.java

Lines changed: 6 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,11 @@
1313
import java.util.Objects;
1414
import java.util.function.Consumer;
1515

16-
public class TestEventsResponse implements Parsable, AdditionalDataHolder {
17-
public Map<String, Object> additionalData;
18-
private String odataNextLink;
16+
public class TestEventsResponse extends BaseCollectionPaginationCountResponse {
1917
public List<TestEventItem> value;
2018

2119
public TestEventsResponse() {
22-
additionalData = new HashMap<>();
23-
}
24-
25-
@Nonnull
26-
public Map<String, Object> getAdditionalData() {
27-
return additionalData;
28-
}
29-
30-
public void setAdditionalData(Map<String, Object> additionalData) {
31-
this.additionalData = additionalData;
32-
}
33-
34-
public String getOdataNextLink() {
35-
return odataNextLink;
36-
}
37-
38-
public void setOdataNextLink(String odataNextLink) {
39-
this.odataNextLink = odataNextLink;
20+
super();
4021
}
4122

4223
public List<TestEventItem> getValue() {
@@ -48,17 +29,15 @@ public void setValue(List<TestEventItem> value) {
4829
}
4930
@Nonnull
5031
public Map<String, Consumer<ParseNode>> getFieldDeserializers() {
51-
HashMap<String, Consumer<ParseNode>> fieldDeserializers = new HashMap<>();
52-
fieldDeserializers.put("@odata.nextLink", (n) -> setOdataNextLink(n.getStringValue()));
53-
fieldDeserializers.put("value", (n) -> setValue(n.getCollectionOfObjectValues(TestEventItem::createFromDiscriminatorValue)));
54-
return fieldDeserializers;
32+
final HashMap<String, java.util.function.Consumer<ParseNode>> deserializerMap = new HashMap<String, java.util.function.Consumer<ParseNode>>(super.getFieldDeserializers());
33+
deserializerMap.put("value", (n) -> { this.setValue(n.getCollectionOfObjectValues(TestEventItem::createFromDiscriminatorValue)); });
34+
return deserializerMap;
5535
}
5636

5737
public void serialize(@Nonnull SerializationWriter writer) {
5838
Objects.requireNonNull(writer);
59-
writer.writeStringValue("@odata.nextLink", getOdataNextLink());
39+
super.serialize(writer);
6040
writer.writeCollectionOfObjectValues("value", getValue());
61-
writer.writeAdditionalData(getAdditionalData());
6241
}
6342

6443
public static TestEventsResponse createFromDiscriminatorValue(ParseNode parseNode) {

0 commit comments

Comments
 (0)