Skip to content

Commit 5a482ba

Browse files
authored
Merge branch 'master' into keep-dependencies-up-to-date
2 parents 9fbe204 + b065eff commit 5a482ba

10 files changed

+220
-11
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# [2.1.0](https://github.com/parse-community/Parse-SDK-Android/compare/2.0.6...2.1.0) (2021-11-21)
2+
3+
4+
### Features
5+
6+
* add support for custom objectId ([#1088](https://github.com/parse-community/Parse-SDK-Android/issues/1088)) ([d420371](https://github.com/parse-community/Parse-SDK-Android/commit/d420371e761b07fac02f8ad747de0191817db5fa))
7+
18
## [2.0.6](https://github.com/parse-community/Parse-SDK-Android/compare/2.0.5...2.0.6) (2021-11-16)
29

310

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version = 2.0.6
1+
version = 2.1.0
22
android.enableJetifier = true
33
android.useAndroidX = true

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse-sdk-android",
3-
"version": "2.0.6",
3+
"version": "2.1.0",
44
"repository": {
55
"type": "git",
66
"url": "git+https://github.com/parse-community/Parse-SDK-Android.git"

parse/src/main/java/com/parse/Parse.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class Parse {
4949
private static final Object MUTEX_CALLBACKS = new Object();
5050
static ParseEventuallyQueue eventuallyQueue = null;
5151
private static boolean isLocalDatastoreEnabled;
52+
private static boolean allowCustomObjectId = false;
5253

5354
// endregion
5455
private static OfflineStore offlineStore;
@@ -110,6 +111,14 @@ public static boolean isLocalDatastoreEnabled() {
110111
return isLocalDatastoreEnabled;
111112
}
112113

114+
/**
115+
* @return {@code True} if {@link Configuration.Builder#allowCustomObjectId()} has been called,
116+
* otherwise {@code false}.
117+
*/
118+
public static boolean isAllowCustomObjectId() {
119+
return allowCustomObjectId;
120+
}
121+
113122
/**
114123
* Authenticates this client as belonging to your application. This must be called before your
115124
* application can use the Parse library. The recommended way is to put a call to {@code
@@ -140,6 +149,8 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) {
140149
// isLocalDataStoreEnabled() to perform additional behavior.
141150
isLocalDatastoreEnabled = configuration.localDataStoreEnabled;
142151

152+
allowCustomObjectId = configuration.allowCustomObjectId;
153+
143154
if (parsePlugins == null) {
144155
ParsePlugins.initialize(configuration.context, configuration);
145156
} else {
@@ -271,6 +282,7 @@ public static void destroy() {
271282
ParsePlugins.reset();
272283

273284
setLocalDatastore(null);
285+
allowCustomObjectId = false;
274286
}
275287

276288
/** @return {@code True} if {@link #initialize} has been called, otherwise {@code false}. */
@@ -564,6 +576,7 @@ public static final class Configuration {
564576
final String clientKey;
565577
final String server;
566578
final boolean localDataStoreEnabled;
579+
final boolean allowCustomObjectId;
567580
final OkHttpClient.Builder clientBuilder;
568581
final int maxRetries;
569582

@@ -573,6 +586,7 @@ private Configuration(Builder builder) {
573586
this.clientKey = builder.clientKey;
574587
this.server = builder.server;
575588
this.localDataStoreEnabled = builder.localDataStoreEnabled;
589+
this.allowCustomObjectId = builder.allowCustomObjectId;
576590
this.clientBuilder = builder.clientBuilder;
577591
this.maxRetries = builder.maxRetries;
578592
}
@@ -584,6 +598,7 @@ public static final class Builder {
584598
private String clientKey;
585599
private String server;
586600
private boolean localDataStoreEnabled;
601+
private boolean allowCustomObjectId;
587602
private OkHttpClient.Builder clientBuilder;
588603
private int maxRetries = DEFAULT_MAX_RETRIES;
589604

@@ -648,6 +663,20 @@ private Builder setLocalDatastoreEnabled(boolean enabled) {
648663
return this;
649664
}
650665

666+
/**
667+
* Allow to set a custom objectId for ParseObjects.
668+
*
669+
* @return The same builder, for easy chaining.
670+
*/
671+
public Builder allowCustomObjectId() {
672+
return this.setAllowCustomObjectId(true);
673+
}
674+
675+
private Builder setAllowCustomObjectId(boolean enabled) {
676+
allowCustomObjectId = enabled;
677+
return this;
678+
}
679+
651680
/**
652681
* Set the {@link okhttp3.OkHttpClient.Builder} to use when communicating with the Parse
653682
* REST API

parse/src/main/java/com/parse/ParseObject.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2250,6 +2250,10 @@ Task<Void> saveAsync(final String sessionToken, final Task<Void> toAwait) {
22502250
return Task.forResult(null);
22512251
}
22522252

2253+
if (Parse.isAllowCustomObjectId() && getObjectId() == null) {
2254+
return Task.forError(new ParseException(104, "ObjectId must not be null"));
2255+
}
2256+
22532257
final ParseOperationSet operations;
22542258
synchronized (mutex) {
22552259
updateBeforeSave();
@@ -2357,6 +2361,10 @@ public final Task<Void> saveEventually() {
23572361
return Task.forResult(null);
23582362
}
23592363

2364+
if (Parse.isAllowCustomObjectId() && getObjectId() == null) {
2365+
return Task.forError(new ParseException(104, "ObjectId must not be null"));
2366+
}
2367+
23602368
final ParseOperationSet operationSet;
23612369
final ParseRESTCommand command;
23622370
final Task<JSONObject> runEventuallyTask;

parse/src/main/java/com/parse/ParseRESTObjectCommand.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,18 @@ public static ParseRESTObjectCommand saveObjectCommand(
3636
return ParseRESTObjectCommand.createObjectCommand(
3737
state.className(), operations, sessionToken);
3838
} else {
39-
return ParseRESTObjectCommand.updateObjectCommand(
40-
state.objectId(), state.className(), operations, sessionToken);
39+
if (Parse.isAllowCustomObjectId()) {
40+
if (state.createdAt() == -1) {
41+
return ParseRESTObjectCommand.createObjectCommand(
42+
state.className(), operations, sessionToken);
43+
} else {
44+
return ParseRESTObjectCommand.updateObjectCommand(
45+
state.objectId(), state.className(), operations, sessionToken);
46+
}
47+
} else {
48+
return ParseRESTObjectCommand.updateObjectCommand(
49+
state.objectId(), state.className(), operations, sessionToken);
50+
}
4151
}
4252
}
4353

parse/src/test/java/com/parse/ParseClientConfigurationTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ public void testBuilder() {
2525
builder.applicationId("foo");
2626
builder.clientKey("bar");
2727
builder.enableLocalDataStore();
28+
builder.allowCustomObjectId();
2829
Parse.Configuration configuration = builder.build();
2930

3031
assertNull(configuration.context);
3132
assertEquals(configuration.applicationId, "foo");
3233
assertEquals(configuration.clientKey, "bar");
3334
assertTrue(configuration.localDataStoreEnabled);
35+
assertEquals(configuration.allowCustomObjectId, true);
3436
}
3537

3638
@Test

parse/src/test/java/com/parse/ParseObjectTest.java

Lines changed: 121 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@
88
*/
99
package com.parse;
1010

11+
import static org.hamcrest.core.Is.is;
1112
import static org.junit.Assert.assertEquals;
1213
import static org.junit.Assert.assertFalse;
14+
import static org.junit.Assert.assertNotNull;
1315
import static org.junit.Assert.assertNull;
1416
import static org.junit.Assert.assertSame;
17+
import static org.junit.Assert.assertThat;
1518
import static org.junit.Assert.assertTrue;
1619
import static org.mockito.ArgumentMatchers.nullable;
1720
import static org.mockito.Matchers.any;
@@ -46,7 +49,7 @@
4649
import org.robolectric.RuntimeEnvironment;
4750

4851
@RunWith(RobolectricTestRunner.class)
49-
public class ParseObjectTest {
52+
public class ParseObjectTest extends ResetPluginsParseTest {
5053

5154
@Rule public final ExpectedException thrown = ExpectedException.none();
5255

@@ -80,16 +83,17 @@ private static TaskCompletionSource<Void> mockObjectControllerForDelete() {
8083
}
8184

8285
@Before
83-
public void setUp() {
86+
public void setUp() throws Exception {
87+
super.setUp();
8488
ParseFieldOperations.registerDefaultDecoders(); // to test JSON / Parcel decoding
8589
}
8690

8791
// region testRevert
8892

8993
@After
90-
public void tearDown() {
91-
ParseCorePlugins.getInstance().reset();
92-
ParsePlugins.reset();
94+
public void tearDown() throws Exception {
95+
super.tearDown();
96+
Parse.destroy();
9397
}
9498

9599
@Test
@@ -159,6 +163,118 @@ public void testFromJsonWithLdsStackOverflow() throws JSONException {
159163

160164
// endregion
161165

166+
@Test
167+
public void testSaveCustomObjectIdMissing() {
168+
// Mocked to let save work
169+
mockCurrentUserController();
170+
171+
Parse.Configuration configuration =
172+
new Parse.Configuration.Builder(RuntimeEnvironment.application)
173+
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
174+
.server("https://api.parse.com/1")
175+
.enableLocalDataStore()
176+
.allowCustomObjectId()
177+
.build();
178+
ParsePlugins plugins = mock(ParsePlugins.class);
179+
when(plugins.configuration()).thenReturn(configuration);
180+
when(plugins.applicationContext()).thenReturn(RuntimeEnvironment.application);
181+
Parse.initialize(configuration, plugins);
182+
183+
ParseObject object = new ParseObject("TestObject");
184+
try {
185+
object.save();
186+
} catch (ParseException e) {
187+
assertEquals(e.getCode(), 104);
188+
assertThat(e.getMessage(), is("ObjectId must not be null"));
189+
}
190+
}
191+
192+
@Test
193+
public void testSaveCustomObjectIdNotMissing() {
194+
// Mocked to let save work
195+
mockCurrentUserController();
196+
197+
Parse.Configuration configuration =
198+
new Parse.Configuration.Builder(RuntimeEnvironment.application)
199+
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
200+
.server("https://api.parse.com/1")
201+
.enableLocalDataStore()
202+
.allowCustomObjectId()
203+
.build();
204+
ParsePlugins plugins = mock(ParsePlugins.class);
205+
when(plugins.configuration()).thenReturn(configuration);
206+
when(plugins.applicationContext()).thenReturn(RuntimeEnvironment.application);
207+
Parse.initialize(configuration, plugins);
208+
209+
ParseObject object = new ParseObject("TestObject");
210+
object.setObjectId("ABCDEF123456");
211+
212+
ParseException exception = null;
213+
try {
214+
object.save();
215+
} catch (ParseException e) {
216+
exception = e;
217+
}
218+
assertNull(exception);
219+
}
220+
221+
@Test
222+
public void testSaveEventuallyCustomObjectIdMissing() {
223+
// Mocked to let save work
224+
mockCurrentUserController();
225+
226+
Parse.Configuration configuration =
227+
new Parse.Configuration.Builder(RuntimeEnvironment.application)
228+
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
229+
.server("https://api.parse.com/1")
230+
.enableLocalDataStore()
231+
.allowCustomObjectId()
232+
.build();
233+
ParsePlugins plugins = ParseTestUtils.mockParsePlugins(configuration);
234+
Parse.initialize(configuration, plugins);
235+
236+
ParseObject object = new ParseObject("TestObject");
237+
object.saveEventually(
238+
new SaveCallback() {
239+
@Override
240+
public void done(ParseException e) {
241+
assertNotNull(e);
242+
assertEquals(e.getCode(), 104);
243+
assertThat(e.getMessage(), is("ObjectId must not be null"));
244+
}
245+
});
246+
247+
Parse.setLocalDatastore(null);
248+
}
249+
250+
@Test
251+
public void testSaveEventuallyCustomObjectIdNotMissing() throws ParseException {
252+
// Mocked to let save work
253+
mockCurrentUserController();
254+
255+
Parse.Configuration configuration =
256+
new Parse.Configuration.Builder(RuntimeEnvironment.application)
257+
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
258+
.server("https://api.parse.com/1")
259+
.enableLocalDataStore()
260+
.allowCustomObjectId()
261+
.build();
262+
ParsePlugins plugins = ParseTestUtils.mockParsePlugins(configuration);
263+
Parse.initialize(configuration, plugins);
264+
265+
ParseObject object = new ParseObject("TestObject");
266+
object.setObjectId("ABCDEF123456");
267+
object.saveEventually(
268+
new SaveCallback() {
269+
@Override
270+
public void done(ParseException e) {
271+
assertNull(e);
272+
}
273+
});
274+
275+
Parse.setLocalDatastore(null);
276+
}
277+
162278
// region testGetter
163279

164280
@Test

0 commit comments

Comments
 (0)