diff --git a/.codecov.yml b/.codecov.yml index ac4fc988a..09585f0ef 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,11 +1,11 @@ coverage: precision: 2 round: down - range: "45...100" + range: "65...100" status: - project: + project: default: - target: 45% + target: 65% patch: yes changes: no diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..9154f0993 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle + +name: ci +on: + push: + branches: + - master + pull_request: + branches: + - '**' +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 11 + uses: actions/setup-java@v2 + with: + java-version: '11' + distribution: 'adopt' + - name: Validate Gradle wrapper + uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b + - run: pip install --user codecov + - run: mkdir "$ANDROID_HOME/licenses" || true + - run: echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" >> "$ANDROID_HOME/licenses/android-sdk-license" + - run: ./gradlew clean jacocoTestReport + - run: codecov \ No newline at end of file diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9bff4cc2c..000000000 --- a/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -branches: - only: - - master - - /^\d+\.\d+\.\d+$/ # regex - -language: android - -jdk: - - openjdk8 - -before_install: - - pip install --user codecov - - mkdir "$ANDROID_HOME/licenses" || true - - echo "24333f8a63b6825ea9c5514f83c2829b004d1fee" >> "$ANDROID_HOME/licenses/android-sdk-license" - -script: - - ./gradlew clean testDebugUnitTest jacocoTestReport - -after_success: - - ./gradlew coveralls - - codecov - -cache: - directories: - - $HOME/.gradle - - $HOME/.m2/repository diff --git a/CHANGELOG.md b/CHANGELOG.md index 857262025..a8d7ee7c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,53 @@ -## Changelog - -### master - -### 1.25.0 +# Changelog + +# master + +### BREAKING CHANGES +- Required minimum SDK version is 16 + +### Feature +- Update all dependencies and modernize the source base (Asen Lekov) [#1095](https://github.com/parse-community/Parse-SDK-Android/pull/1095) + +### Internal Changes + - SDK targets the latest Android version API 30 + - Update the codebase to advantage of Java 8 syntax + - Update Kotlin and Coroutines version to `1.5.31` + - Update project from Android Studio `3.6` to `4.2` + - Update Gradle version from `5.6.4` to `6.8.3` + - Update Robolectric from `3.8` to `4.6` and adjust all tests + - Update Play services + - Google Play services auth from `18.0.0` to `19.2.0` + - Google Cloud Messaging from `12.0.1` to `17.0.0` + - Firebase Messaging from `20.1.5` to `22.0.0` + - Update jacoco and fixed reporting of test coverage + - Migrate deprecated dependency repository from `jcenter()` to `mavenCentral()` + +### CI +- Migrate from Travis CI to GitHub Actions (Asen Lekov) [#1095](https://github.com/parse-community/Parse-SDK-Android/pull/1095) + +# 1.26.0 +- fix TypeCastException when unlinking google account [#1076](https://github.com/parse-community/Parse-SDK-Android/pull/1076) +- feature: KTX property delegation custom labels [#1066](https://github.com/parse-community/Parse-SDK-Android/pull/1066) +- feature: Coroutine Task Wrapper [#1064](https://github.com/parse-community/Parse-SDK-Android/pull/1064) +- Rename functions that cause shadow members [#1054](https://github.com/parse-community/Parse-SDK-Android/pull/1054) + +# 1.25.0 > __BREAKING CHANGES__ > > - FIX: Corrected the `Installation` property `appVersion` to be the build version instead of the version name. This aligns the property with its equivalent in the Parse iOS SDK. See [#902](https://github.com/parse-community/Parse-SDK-Android/issues/902) for details. Thanks to [Manuel Trezza](https://github.com/mtrezza). - Added RxJava module to transform `Task`s into RxJava types. -### 1.24.2 +# 1.24.2 - FIX: Fixed naming collission bug due to integration of bolts-tasks module. See [#1028](https://github.com/parse-community/Parse-SDK-Android/issues/1028) for details. Thanks to [Manuel Trezza](https://github.com/mtrezza) -### 1.24.1 +# 1.24.1 > __WARNING__ > > Avoid using this release as it contains a [naming collission bug](https://github.com/parse-community/Parse-SDK-Android/issues/1028) that has been introduced in release `1.24.0` and fixed in release `1.24.2`. The bug causes the project compliation to fail due to duplicate class names for the `bolts-tasks` module when using the Facebook Android SDK or the Parse Android SDK Facebook module. - Resolves issue around missing bolts-tasks dependency thanks to @rogerhu (#1025) -### 1.24.0 +# 1.24.0 > __WARNING__ > > Avoid using this release as it contains a [naming collission bug](https://github.com/parse-community/Parse-SDK-Android/issues/1028) that has been introduced in release `1.24.0` and fixed in release `1.24.2`. The bug causes the project compliation to fail due to duplicate class names for the `bolts-tasks` module when using the Facebook Android SDK or the Parse Android SDK Facebook module. @@ -28,55 +57,55 @@ - Set to unknown name if version name is null (#1014) thanks to @Jawnnypoo - Fix signup method name (#1017) thanks to @Jawnnypoo -### 1.23.1 +# 1.23.1 - Correction to OkHttp version thanks to @mtrezza -### 1.23.0 +# 1.23.0 - Add Google login/signup support - Move Facebook and Twitter libraries to be modules within this library - Update Facebook login to use AndroidX - Add ability to update the server without having to reinitialize the client thanks to @mtrezza -### 1.22.1 +# 1.22.1 Re-releasing since Jitpack failed. Same as 1.22.0 -### 1.22.0 +# 1.22.0 - Expose client destroy - Enhancement to ParseQuery kt operations -### 1.21.0 +# 1.21.0 - Add coroutines support module - Fix bug in save user in batch -### 1.20.0 +# 1.20.0 - Fix fetchAllIfNeeded and fetchAllIfNeededInBackground limit #939 - Expose useful constants #930 - ParseQuery extensions #929 - Change to non-deprecated methods for FCM #927. If you are using FCM and updating to 1.20.0, be sure to take a look at the FCM README for the updated steps on usage. -### 1.19.0 +# 1.19.0 - SDK now uses AndroidX and API 28 - Kotlin Delegates - Fix StackOverflowError when merging ParseObject from JSON #896 -### 1.18.5 +# 1.18.5 - Fix for issue #886 -### 1.18.4 +# 1.18.4 - Fix issue with returning { "result": null } in cloud function (deserialized as JSONObject instead of null) - Remove deprecated methods in ParseAnalytics and ParsePush - Add findAll() method to ParseQuery which iterates and finds all ParseObjects for a query (no limit) -### 1.18.3 +# 1.18.3 - Add ktx module and dependency, which adds some Kotlin extensions for easier Parse SDK usage. -### 1.18.2 +# 1.18.2 - More things made public for LiveQuery support -### 1.18.1 +# 1.18.1 - Make things public for LiveQuery support -### 1.18.0 +# 1.18.0 - Annotate ParseObject with nullability thanks to @kurtisnelson and @Jawnnypoo - Remove deprecated refresh() method from ParseObject - Partial string match thanks to @rogerhu diff --git a/bolts-tasks/build.gradle b/bolts-tasks/build.gradle index 22bcb8bdb..b86e9794a 100644 --- a/bolts-tasks/build.gradle +++ b/bolts-tasks/build.gradle @@ -6,22 +6,11 @@ apply plugin: 'java' apply plugin: 'maven' -configurations { - provided -} - -sourceSets { - main { - compileClasspath += configurations.provided - } -} - dependencies { - provided 'com.google.android:android:4.1.1.4' - testImplementation 'junit:junit:4.12' + compileOnly 'com.google.android:android:4.1.1.4' + testImplementation 'junit:junit:4.13.2' } - javadoc.options.addStringOption('Xdoclint:none', '-quiet') task sourcesJar(type: Jar) { @@ -29,7 +18,7 @@ task sourcesJar(type: Jar) { from sourceSets.main.allJava } -task javadocJar (type: Jar, dependsOn: javadoc) { +task javadocJar(type: Jar, dependsOn: javadoc) { classifier = 'javadoc' from javadoc.destinationDir } @@ -45,10 +34,6 @@ artifacts { apply plugin: 'jacoco' -jacoco { - toolVersion = '0.7.1.201405082137' -} - jacocoTestReport { group = "Reporting" description = "Generate Jacoco coverage reports after running tests." @@ -59,3 +44,8 @@ jacocoTestReport { } //endregion + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} \ No newline at end of file diff --git a/bolts-tasks/src/main/java/com/parse/boltsinternal/AggregateException.java b/bolts-tasks/src/main/java/com/parse/boltsinternal/AggregateException.java index 8535c1ca5..bb8c9c77d 100644 --- a/bolts-tasks/src/main/java/com/parse/boltsinternal/AggregateException.java +++ b/bolts-tasks/src/main/java/com/parse/boltsinternal/AggregateException.java @@ -23,7 +23,7 @@ public class AggregateException extends Exception { private static final String DEFAULT_MESSAGE = "There were multiple errors."; - private List innerThrowables; + private final List innerThrowables; /** * Constructs a new {@code AggregateException} with the current stack trace, the specified detail @@ -103,7 +103,7 @@ public void printStackTrace(PrintWriter err) { */ @Deprecated public List getErrors() { - List errors = new ArrayList(); + List errors = new ArrayList<>(); if (innerThrowables == null) { return errors; } @@ -123,7 +123,7 @@ public List getErrors() { */ @Deprecated public Throwable[] getCauses() { - return innerThrowables.toArray(new Throwable[innerThrowables.size()]); + return innerThrowables.toArray(new Throwable[0]); } } diff --git a/bolts-tasks/src/main/java/com/parse/boltsinternal/AndroidExecutors.java b/bolts-tasks/src/main/java/com/parse/boltsinternal/AndroidExecutors.java index 45ee7769a..19612f42c 100644 --- a/bolts-tasks/src/main/java/com/parse/boltsinternal/AndroidExecutors.java +++ b/bolts-tasks/src/main/java/com/parse/boltsinternal/AndroidExecutors.java @@ -34,14 +34,8 @@ */ /* package */ final class AndroidExecutors { + /* package */ static final long KEEP_ALIVE_TIME = 1L; private static final AndroidExecutors INSTANCE = new AndroidExecutors(); - - private final Executor uiThread; - - private AndroidExecutors() { - uiThread = new UIThreadExecutor(); - } - /** * Nexus 5: Quad-Core * Moto X: Dual-Core @@ -55,7 +49,11 @@ private AndroidExecutors() { private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); /* package */ static final int CORE_POOL_SIZE = CPU_COUNT + 1; /* package */ static final int MAX_POOL_SIZE = CPU_COUNT * 2 + 1; - /* package */ static final long KEEP_ALIVE_TIME = 1L; + private final Executor uiThread; + + private AndroidExecutors() { + uiThread = new UIThreadExecutor(); + } /** * Creates a proper Cached Thread Pool. Tasks will reuse cached threads if available @@ -72,7 +70,7 @@ public static ExecutorService newCachedThreadPool() { CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, - new LinkedBlockingQueue()); + new LinkedBlockingQueue<>()); allowCoreThreadTimeout(executor, true); @@ -95,7 +93,7 @@ public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, - new LinkedBlockingQueue(), + new LinkedBlockingQueue<>(), threadFactory); allowCoreThreadTimeout(executor, true); diff --git a/bolts-tasks/src/main/java/com/parse/boltsinternal/BoltsExecutors.java b/bolts-tasks/src/main/java/com/parse/boltsinternal/BoltsExecutors.java index 866013cbd..5b9e7b04d 100644 --- a/bolts-tasks/src/main/java/com/parse/boltsinternal/BoltsExecutors.java +++ b/bolts-tasks/src/main/java/com/parse/boltsinternal/BoltsExecutors.java @@ -18,15 +18,6 @@ /* package */ final class BoltsExecutors { private static final BoltsExecutors INSTANCE = new BoltsExecutors(); - - private static boolean isAndroidRuntime() { - String javaRuntimeName = System.getProperty("java.runtime.name"); - if (javaRuntimeName == null) { - return false; - } - return javaRuntimeName.toLowerCase(Locale.US).contains("android"); - } - private final ExecutorService background; private final ScheduledExecutorService scheduled; private final Executor immediate; @@ -39,6 +30,14 @@ private BoltsExecutors() { immediate = new ImmediateExecutor(); } + private static boolean isAndroidRuntime() { + String javaRuntimeName = System.getProperty("java.runtime.name"); + if (javaRuntimeName == null) { + return false; + } + return javaRuntimeName.toLowerCase(Locale.US).contains("android"); + } + /** * An {@link java.util.concurrent.Executor} that executes tasks in parallel. */ @@ -69,7 +68,7 @@ static Executor immediate() { */ private static class ImmediateExecutor implements Executor { private static final int MAX_DEPTH = 15; - private ThreadLocal executionDepth = new ThreadLocal<>(); + private final ThreadLocal executionDepth = new ThreadLocal<>(); /** * Increments the depth. diff --git a/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationToken.java b/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationToken.java index d9214f86c..e23d79040 100644 --- a/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationToken.java +++ b/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationToken.java @@ -64,6 +64,6 @@ public String toString() { return String.format(Locale.US, "%s@%s[cancellationRequested=%s]", getClass().getName(), Integer.toHexString(hashCode()), - Boolean.toString(tokenSource.isCancellationRequested())); + tokenSource.isCancellationRequested()); } } diff --git a/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationTokenSource.java b/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationTokenSource.java index b654a33f0..9db6c82b3 100644 --- a/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationTokenSource.java +++ b/bolts-tasks/src/main/java/com/parse/boltsinternal/CancellationTokenSource.java @@ -105,14 +105,11 @@ private void cancelAfter(long delay, TimeUnit timeUnit) { cancelScheduledCancellation(); if (delay != -1) { - scheduledCancellation = executor.schedule(new Runnable() { - @Override - public void run() { - synchronized (lock) { - scheduledCancellation = null; - } - cancel(); + scheduledCancellation = executor.schedule(() -> { + synchronized (lock) { + scheduledCancellation = null; } + cancel(); }, delay, timeUnit); } } @@ -187,7 +184,7 @@ public String toString() { return String.format(Locale.US, "%s@%s[cancellationRequested=%s]", getClass().getName(), Integer.toHexString(hashCode()), - Boolean.toString(isCancellationRequested())); + isCancellationRequested()); } // This method makes no attempt to perform any synchronization itself - you should ensure diff --git a/bolts-tasks/src/main/java/com/parse/boltsinternal/Task.java b/bolts-tasks/src/main/java/com/parse/boltsinternal/Task.java index 25732908d..e51f9cf6c 100644 --- a/bolts-tasks/src/main/java/com/parse/boltsinternal/Task.java +++ b/bolts-tasks/src/main/java/com/parse/boltsinternal/Task.java @@ -30,62 +30,22 @@ public class Task { * An {@link java.util.concurrent.Executor} that executes tasks in parallel. */ public static final ExecutorService BACKGROUND_EXECUTOR = BoltsExecutors.background(); - - /** - * An {@link java.util.concurrent.Executor} that executes tasks in the current thread unless - * the stack runs too deep, at which point it will delegate to {@link Task#BACKGROUND_EXECUTOR} in - * order to trim the stack. - */ - private static final Executor IMMEDIATE_EXECUTOR = BoltsExecutors.immediate(); - /** * An {@link java.util.concurrent.Executor} that executes tasks on the UI thread. */ public static final Executor UI_THREAD_EXECUTOR = AndroidExecutors.uiThread(); - /** - * Interface for handlers invoked when a failed {@code Task} is about to be - * finalized, but the exception has not been consumed. - * - *

The handler will execute in the GC thread, so if the handler needs to do - * anything time consuming or complex it is a good idea to fire off a {@code Task} - * to handle the exception. - * - * @see #getUnobservedExceptionHandler - * @see #setUnobservedExceptionHandler + * An {@link java.util.concurrent.Executor} that executes tasks in the current thread unless + * the stack runs too deep, at which point it will delegate to {@link Task#BACKGROUND_EXECUTOR} in + * order to trim the stack. */ - public interface UnobservedExceptionHandler { - /** - * Method invoked when the given task has an unobserved exception. - *

Any exception thrown by this method will be ignored. - * - * @param t the task - * @param e the exception - */ - void unobservedException(Task t, UnobservedTaskException e); - } - + private static final Executor IMMEDIATE_EXECUTOR = BoltsExecutors.immediate(); + private static final Task TASK_NULL = new Task<>(null); + private static final Task TASK_TRUE = new Task<>((Boolean) true); + private static final Task TASK_FALSE = new Task<>((Boolean) false); + private static final Task TASK_CANCELLED = new Task<>(true); // null unless explicitly set private static volatile UnobservedExceptionHandler unobservedExceptionHandler; - - /** - * Returns the handler invoked when a task has an unobserved - * exception or {@code null}. - */ - public static UnobservedExceptionHandler getUnobservedExceptionHandler() { - return unobservedExceptionHandler; - } - - /** - * Set the handler invoked when a task has an unobserved exception. - * - * @param eh the object to use as an unobserved exception handler. If - * null then unobserved exceptions will be ignored. - */ - public static void setUnobservedExceptionHandler(UnobservedExceptionHandler eh) { - unobservedExceptionHandler = eh; - } - private final Object lock = new Object(); private boolean complete; private boolean cancelled; @@ -111,90 +71,29 @@ private Task(boolean cancelled) { } /** - * @deprecated Please use {@link com.parse.boltsinternal.TaskCompletionSource ()} instead. - */ - public static Task.TaskCompletionSource create() { - Task task = new Task<>(); - return task.new TaskCompletionSource(); - } - - /** - * @return {@code true} if the task completed (has a result, an error, or was cancelled. - * {@code false} otherwise. - */ - public boolean isCompleted() { - synchronized (lock) { - return complete; - } - } - - /** - * @return {@code true} if the task was cancelled, {@code false} otherwise. - */ - public boolean isCancelled() { - synchronized (lock) { - return cancelled; - } - } - - /** - * @return {@code true} if the task has an error, {@code false} otherwise. - */ - public boolean isFaulted() { - synchronized (lock) { - return getError() != null; - } - } - - /** - * @return The result of the task, if set. {@code null} otherwise. - */ - public TResult getResult() { - synchronized (lock) { - return result; - } - } - - /** - * @return The error for the task, if set. {@code null} otherwise. + * Returns the handler invoked when a task has an unobserved + * exception or {@code null}. */ - public Exception getError() { - synchronized (lock) { - if (error != null) { - errorHasBeenObserved = true; - if (unobservedErrorNotifier != null) { - unobservedErrorNotifier.setObserved(); - unobservedErrorNotifier = null; - } - } - return error; - } + public static UnobservedExceptionHandler getUnobservedExceptionHandler() { + return unobservedExceptionHandler; } /** - * Blocks until the task is complete. + * Set the handler invoked when a task has an unobserved exception. + * + * @param eh the object to use as an unobserved exception handler. If + * null then unobserved exceptions will be ignored. */ - public void waitForCompletion() throws InterruptedException { - synchronized (lock) { - if (!isCompleted()) { - lock.wait(); - } - } + public static void setUnobservedExceptionHandler(UnobservedExceptionHandler eh) { + unobservedExceptionHandler = eh; } /** - * Blocks until the task is complete or times out. - * - * @return {@code true} if the task completed (has a result, an error, or was cancelled). - * {@code false} otherwise. + * @deprecated Please use {@link com.parse.boltsinternal.TaskCompletionSource ()} instead. */ - public boolean waitForCompletion(long duration, TimeUnit timeUnit) throws InterruptedException { - synchronized (lock) { - if (!isCompleted()) { - lock.wait(timeUnit.toMillis(duration)); - } - return isCompleted(); - } + public static Task.TaskCompletionSource create() { + Task task = new Task<>(); + return task.new TaskCompletionSource(); } /** @@ -263,54 +162,20 @@ static Task delay(long delay, ScheduledExecutorService executor, final Can } final com.parse.boltsinternal.TaskCompletionSource tcs = new com.parse.boltsinternal.TaskCompletionSource<>(); - final ScheduledFuture scheduled = executor.schedule(new Runnable() { - @Override - public void run() { - tcs.trySetResult(null); - } + final ScheduledFuture scheduled = executor.schedule(() -> { + tcs.trySetResult(null); }, delay, TimeUnit.MILLISECONDS); if (cancellationToken != null) { - cancellationToken.register(new Runnable() { - @Override - public void run() { - scheduled.cancel(true); - tcs.trySetCancelled(); - } + cancellationToken.register(() -> { + scheduled.cancel(true); + tcs.trySetCancelled(); }); } return tcs.getTask(); } - /** - * Makes a fluent cast of a Task's result possible, avoiding an extra continuation just to cast - * the type of the result. - */ - public Task cast() { - @SuppressWarnings("unchecked") - Task task = (Task) this; - return task; - } - - /** - * Turns a Task into a Task, dropping any result. - */ - public Task makeVoid() { - return this.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - if (task.isCancelled()) { - return Task.cancelled(); - } - if (task.isFaulted()) { - return Task.forError(task.getError()); - } - return Task.forResult(null); - } - }); - } - /** * Invokes the callable on a background thread, returning a Task to represent the operation. *

@@ -345,21 +210,18 @@ public static Task call(final Callable callable, Exe final CancellationToken ct) { final com.parse.boltsinternal.TaskCompletionSource tcs = new com.parse.boltsinternal.TaskCompletionSource<>(); try { - executor.execute(new Runnable() { - @Override - public void run() { - if (ct != null && ct.isCancellationRequested()) { - tcs.setCancelled(); - return; - } + executor.execute(() -> { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return; + } - try { - tcs.setResult(callable.call()); - } catch (CancellationException e) { - tcs.setCancelled(); - } catch (Exception e) { - tcs.setError(e); - } + try { + tcs.setResult(callable.call()); + } catch (CancellationException e) { + tcs.setCancelled(); + } catch (Exception e) { + tcs.setError(e); } }); } catch (Exception e) { @@ -406,16 +268,13 @@ public static Task> whenAnyResult(Collection task : tasks) { - task.continueWith(new Continuation() { - @Override - public Void then(Task task) { - if (isAnyTaskComplete.compareAndSet(false, true)) { - firstCompleted.setResult(task); - } else { - Throwable ensureObserved = task.getError(); - } - return null; + task.continueWith((Continuation) task1 -> { + if (isAnyTaskComplete.compareAndSet(false, true)) { + firstCompleted.setResult(task1); + } else { + Throwable ensureObserved = task1.getError(); } + return null; }); } return firstCompleted.getTask(); @@ -442,16 +301,13 @@ public static Task> whenAny(Collection> tasks) { final AtomicBoolean isAnyTaskComplete = new AtomicBoolean(false); for (Task task : tasks) { - ((Task) task).continueWith(new Continuation() { - @Override - public Void then(Task task) { - if (isAnyTaskComplete.compareAndSet(false, true)) { - firstCompleted.setResult(task); - } else { - Throwable ensureObserved = task.getError(); - } - return null; + ((Task) task).continueWith((Continuation) task1 -> { + if (isAnyTaskComplete.compareAndSet(false, true)) { + firstCompleted.setResult(task1); + } else { + Throwable ensureObserved = task1.getError(); } + return null; }); } return firstCompleted.getTask(); @@ -483,19 +339,16 @@ public Void then(Task task) { * @return A Task that will resolve to {@code List<TResult>} when all the tasks are resolved. */ public static Task> whenAllResult(final Collection> tasks) { - return whenAll(tasks).onSuccess(new Continuation>() { - @Override - public List then(Task task) throws Exception { - if (tasks.size() == 0) { - return Collections.emptyList(); - } + return whenAll(tasks).onSuccess(task -> { + if (tasks.size() == 0) { + return Collections.emptyList(); + } - List results = new ArrayList<>(); - for (Task individualTask : tasks) { - results.add(individualTask.getResult()); - } - return results; + List results = new ArrayList<>(); + for (Task individualTask : tasks) { + results.add(individualTask.getResult()); } + return results; }); } @@ -533,43 +386,236 @@ public static Task whenAll(Collection> tasks) { for (Task task : tasks) { @SuppressWarnings("unchecked") Task t = (Task) task; - t.continueWith(new Continuation() { - @Override - public Void then(Task task) { - if (task.isFaulted()) { - synchronized (errorLock) { - causes.add(task.getError()); - } + t.continueWith((Continuation) task1 -> { + if (task1.isFaulted()) { + synchronized (errorLock) { + causes.add(task1.getError()); } + } - if (task.isCancelled()) { - isCancelled.set(true); - } + if (task1.isCancelled()) { + isCancelled.set(true); + } - if (count.decrementAndGet() == 0) { - if (causes.size() != 0) { - if (causes.size() == 1) { - allFinished.setError(causes.get(0)); - } else { - Exception error = new AggregateException( - String.format("There were %d exceptions.", causes.size()), - causes); - allFinished.setError(error); - } - } else if (isCancelled.get()) { - allFinished.setCancelled(); + if (count.decrementAndGet() == 0) { + if (causes.size() != 0) { + if (causes.size() == 1) { + allFinished.setError(causes.get(0)); } else { - allFinished.setResult(null); + Exception error = new AggregateException( + String.format("There were %d exceptions.", causes.size()), + causes); + allFinished.setError(error); } + } else if (isCancelled.get()) { + allFinished.setCancelled(); + } else { + allFinished.setResult(null); } - return null; } + return null; }); } return allFinished.getTask(); } + /** + * Handles the non-async (i.e. the continuation doesn't return a Task) continuation case, passing + * the results of the given Task through to the given continuation and using the results of that + * call to set the result of the TaskContinuationSource. + * + * @param tcs The TaskContinuationSource that will be orchestrated by this call. + * @param continuation The non-async continuation. + * @param task The task being completed. + * @param executor The executor to use when running the continuation (allowing the continuation to be + * scheduled on a different thread). + */ + private static void completeImmediately( + final com.parse.boltsinternal.TaskCompletionSource tcs, + final Continuation continuation, final Task task, + Executor executor, final CancellationToken ct) { + try { + executor.execute(() -> { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return; + } + + try { + TContinuationResult result = continuation.then(task); + tcs.setResult(result); + } catch (CancellationException e) { + tcs.setCancelled(); + } catch (Exception e) { + tcs.setError(e); + } + }); + } catch (Exception e) { + tcs.setError(new ExecutorException(e)); + } + } + + /** + * Handles the async (i.e. the continuation does return a Task) continuation case, passing the + * results of the given Task through to the given continuation to get a new Task. The + * TaskCompletionSource's results are only set when the new Task has completed, unwrapping the + * results of the task returned by the continuation. + * + * @param tcs The TaskContinuationSource that will be orchestrated by this call. + * @param continuation The async continuation. + * @param task The task being completed. + * @param executor The executor to use when running the continuation (allowing the continuation to be + * scheduled on a different thread). + */ + private static void completeAfterTask( + final com.parse.boltsinternal.TaskCompletionSource tcs, + final Continuation> continuation, + final Task task, final Executor executor, + final CancellationToken ct) { + try { + executor.execute(() -> { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return; + } + + try { + Task result = continuation.then(task); + if (result == null) { + tcs.setResult(null); + } else { + result.continueWith((Continuation) task1 -> { + if (ct != null && ct.isCancellationRequested()) { + tcs.setCancelled(); + return null; + } + + if (task1.isCancelled()) { + tcs.setCancelled(); + } else if (task1.isFaulted()) { + tcs.setError(task1.getError()); + } else { + tcs.setResult(task1.getResult()); + } + return null; + }); + } + } catch (CancellationException e) { + tcs.setCancelled(); + } catch (Exception e) { + tcs.setError(e); + } + }); + } catch (Exception e) { + tcs.setError(new ExecutorException(e)); + } + } + + /** + * @return {@code true} if the task completed (has a result, an error, or was cancelled. + * {@code false} otherwise. + */ + public boolean isCompleted() { + synchronized (lock) { + return complete; + } + } + + /** + * @return {@code true} if the task was cancelled, {@code false} otherwise. + */ + public boolean isCancelled() { + synchronized (lock) { + return cancelled; + } + } + + /** + * @return {@code true} if the task has an error, {@code false} otherwise. + */ + public boolean isFaulted() { + synchronized (lock) { + return getError() != null; + } + } + + /** + * @return The result of the task, if set. {@code null} otherwise. + */ + public TResult getResult() { + synchronized (lock) { + return result; + } + } + + /** + * @return The error for the task, if set. {@code null} otherwise. + */ + public Exception getError() { + synchronized (lock) { + if (error != null) { + errorHasBeenObserved = true; + if (unobservedErrorNotifier != null) { + unobservedErrorNotifier.setObserved(); + unobservedErrorNotifier = null; + } + } + return error; + } + } + + /** + * Blocks until the task is complete. + */ + public void waitForCompletion() throws InterruptedException { + synchronized (lock) { + if (!isCompleted()) { + lock.wait(); + } + } + } + + /** + * Blocks until the task is complete or times out. + * + * @return {@code true} if the task completed (has a result, an error, or was cancelled). + * {@code false} otherwise. + */ + public boolean waitForCompletion(long duration, TimeUnit timeUnit) throws InterruptedException { + synchronized (lock) { + if (!isCompleted()) { + lock.wait(timeUnit.toMillis(duration)); + } + return isCompleted(); + } + } + + /** + * Makes a fluent cast of a Task's result possible, avoiding an extra continuation just to cast + * the type of the result. + */ + public Task cast() { + @SuppressWarnings("unchecked") + Task task = (Task) this; + return task; + } + + /** + * Turns a Task into a Task, dropping any result. + */ + public Task makeVoid() { + return this.continueWithTask(task -> { + if (task.isCancelled()) { + return Task.cancelled(); + } + if (task.isFaulted()) { + return Task.forError(task.getError()); + } + return Task.forResult(null); + }); + } + /** * Continues a task with the equivalent of a Task-based while loop, where the body of the loop is * a task continuation. @@ -606,19 +652,16 @@ public Task continueWhile(final Callable predicate, final CancellationToken ct) { final Capture>> predicateContinuation = new Capture<>(); - predicateContinuation.set(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - if (ct != null && ct.isCancellationRequested()) { - return Task.cancelled(); - } + predicateContinuation.set(task -> { + if (ct != null && ct.isCancellationRequested()) { + return Task.cancelled(); + } - if (predicate.call()) { - return Task.forResult(null).onSuccessTask(continuation, executor) - .onSuccessTask(predicateContinuation.get(), executor); - } - return Task.forResult(null); + if (predicate.call()) { + return Task.forResult(null).onSuccessTask(continuation, executor) + .onSuccessTask(predicateContinuation.get(), executor); } + return Task.forResult(null); }); return makeVoid().continueWithTask(predicateContinuation.get(), executor); } @@ -646,12 +689,9 @@ public Task continueWith( synchronized (lock) { completed = this.isCompleted(); if (!completed) { - this.continuations.add(new Continuation() { - @Override - public Void then(Task task) { - completeImmediately(tcs, continuation, task, executor, ct); - return null; - } + this.continuations.add(task -> { + completeImmediately(tcs, continuation, task, executor, ct); + return null; }); } } @@ -700,12 +740,9 @@ public Task continueWithTask( synchronized (lock) { completed = this.isCompleted(); if (!completed) { - this.continuations.add(new Continuation() { - @Override - public Void then(Task task) { - completeAfterTask(tcs, continuation, task, executor, ct); - return null; - } + this.continuations.add(task -> { + completeAfterTask(tcs, continuation, task, executor, ct); + return null; }); } } @@ -749,20 +786,17 @@ public Task onSuccess( public Task onSuccess( final Continuation continuation, Executor executor, final CancellationToken ct) { - return continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (ct != null && ct.isCancellationRequested()) { - return Task.cancelled(); - } + return continueWithTask(task -> { + if (ct != null && ct.isCancellationRequested()) { + return Task.cancelled(); + } - if (task.isFaulted()) { - return Task.forError(task.getError()); - } else if (task.isCancelled()) { - return Task.cancelled(); - } else { - return task.continueWith(continuation); - } + if (task.isFaulted()) { + return Task.forError(task.getError()); + } else if (task.isCancelled()) { + return Task.cancelled(); + } else { + return task.continueWith(continuation); } }, executor); } @@ -801,20 +835,17 @@ public Task onSuccessTask( public Task onSuccessTask( final Continuation> continuation, Executor executor, final CancellationToken ct) { - return continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (ct != null && ct.isCancellationRequested()) { - return Task.cancelled(); - } + return continueWithTask(task -> { + if (ct != null && ct.isCancellationRequested()) { + return Task.cancelled(); + } - if (task.isFaulted()) { - return Task.forError(task.getError()); - } else if (task.isCancelled()) { - return Task.cancelled(); - } else { - return task.continueWithTask(continuation); - } + if (task.isFaulted()) { + return Task.forError(task.getError()); + } else if (task.isCancelled()) { + return Task.cancelled(); + } else { + return task.continueWithTask(continuation); } }, executor); } @@ -838,107 +869,6 @@ public Task onSuccessTask( return onSuccessTask(continuation, IMMEDIATE_EXECUTOR, ct); } - /** - * Handles the non-async (i.e. the continuation doesn't return a Task) continuation case, passing - * the results of the given Task through to the given continuation and using the results of that - * call to set the result of the TaskContinuationSource. - * - * @param tcs The TaskContinuationSource that will be orchestrated by this call. - * @param continuation The non-async continuation. - * @param task The task being completed. - * @param executor The executor to use when running the continuation (allowing the continuation to be - * scheduled on a different thread). - */ - private static void completeImmediately( - final com.parse.boltsinternal.TaskCompletionSource tcs, - final Continuation continuation, final Task task, - Executor executor, final CancellationToken ct) { - try { - executor.execute(new Runnable() { - @Override - public void run() { - if (ct != null && ct.isCancellationRequested()) { - tcs.setCancelled(); - return; - } - - try { - TContinuationResult result = continuation.then(task); - tcs.setResult(result); - } catch (CancellationException e) { - tcs.setCancelled(); - } catch (Exception e) { - tcs.setError(e); - } - } - }); - } catch (Exception e) { - tcs.setError(new ExecutorException(e)); - } - } - - /** - * Handles the async (i.e. the continuation does return a Task) continuation case, passing the - * results of the given Task through to the given continuation to get a new Task. The - * TaskCompletionSource's results are only set when the new Task has completed, unwrapping the - * results of the task returned by the continuation. - * - * @param tcs The TaskContinuationSource that will be orchestrated by this call. - * @param continuation The async continuation. - * @param task The task being completed. - * @param executor The executor to use when running the continuation (allowing the continuation to be - * scheduled on a different thread). - */ - private static void completeAfterTask( - final com.parse.boltsinternal.TaskCompletionSource tcs, - final Continuation> continuation, - final Task task, final Executor executor, - final CancellationToken ct) { - try { - executor.execute(new Runnable() { - @Override - public void run() { - if (ct != null && ct.isCancellationRequested()) { - tcs.setCancelled(); - return; - } - - try { - Task result = continuation.then(task); - if (result == null) { - tcs.setResult(null); - } else { - result.continueWith(new Continuation() { - @Override - public Void then(Task task) { - if (ct != null && ct.isCancellationRequested()) { - tcs.setCancelled(); - return null; - } - - if (task.isCancelled()) { - tcs.setCancelled(); - } else if (task.isFaulted()) { - tcs.setError(task.getError()); - } else { - tcs.setResult(task.getResult()); - } - return null; - } - }); - } - } catch (CancellationException e) { - tcs.setCancelled(); - } catch (Exception e) { - tcs.setError(e); - } - } - }); - } catch (Exception e) { - tcs.setError(new ExecutorException(e)); - } - } - private void runContinuations() { synchronized (lock) { for (Continuation continuation : continuations) { @@ -1005,6 +935,28 @@ private void runContinuations() { } } + /** + * Interface for handlers invoked when a failed {@code Task} is about to be + * finalized, but the exception has not been consumed. + * + *

The handler will execute in the GC thread, so if the handler needs to do + * anything time consuming or complex it is a good idea to fire off a {@code Task} + * to handle the exception. + * + * @see #getUnobservedExceptionHandler + * @see #setUnobservedExceptionHandler + */ + public interface UnobservedExceptionHandler { + /** + * Method invoked when the given task has an unobserved exception. + *

Any exception thrown by this method will be ignored. + * + * @param t the task + * @param e the exception + */ + void unobservedException(Task t, UnobservedTaskException e); + } + /** * @deprecated Please use {@link com.parse.boltsinternal.TaskCompletionSource} instead. */ @@ -1013,9 +965,4 @@ public class TaskCompletionSource extends com.parse.boltsinternal.TaskCompletion /* package */ TaskCompletionSource() { } } - - private static Task TASK_NULL = new Task<>(null); - private static Task TASK_TRUE = new Task<>((Boolean) true); - private static Task TASK_FALSE = new Task<>((Boolean) false); - private static Task TASK_CANCELLED = new Task(true); } diff --git a/bolts-tasks/src/test/java/com/parse/boltsinternal/CancellationTest.java b/bolts-tasks/src/test/java/com/parse/boltsinternal/CancellationTest.java index bc390acbe..68c2a5115 100644 --- a/bolts-tasks/src/test/java/com/parse/boltsinternal/CancellationTest.java +++ b/bolts-tasks/src/test/java/com/parse/boltsinternal/CancellationTest.java @@ -6,16 +6,16 @@ */ package com.parse.boltsinternal; -import org.junit.Test; - -import java.util.concurrent.CancellationException; - import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.junit.Test; + +import java.util.concurrent.CancellationException; + public class CancellationTest { @Test @@ -111,12 +111,7 @@ public void testTokenCallsRegisteredActionWhenCancelled() { CancellationToken token = cts.getToken(); final Capture result = new Capture<>(); - token.register(new Runnable() { - @Override - public void run() { - result.set("Run!"); - } - }); + token.register(() -> result.set("Run!")); assertNull(result.get()); @@ -133,12 +128,7 @@ public void testCancelledTokenCallsRegisteredActionImmediately() { cts.cancel(); - token.register(new Runnable() { - @Override - public void run() { - result.set("Run!"); - } - }); + token.register(() -> result.set("Run!")); assertNotNull(result.get()); } @@ -150,18 +140,8 @@ public void testTokenDoesNotCallUnregisteredAction() { final Capture result1 = new Capture<>(); final Capture result2 = new Capture<>(); - CancellationTokenRegistration registration1 = token.register(new Runnable() { - @Override - public void run() { - result1.set("Run!"); - } - }); - token.register(new Runnable() { - @Override - public void run() { - result2.set("Run!"); - } - }); + CancellationTokenRegistration registration1 = token.register(() -> result1.set("Run!")); + token.register(() -> result2.set("Run!")); registration1.close(); @@ -176,11 +156,8 @@ public void testCloseCancellationTokenSource() { CancellationTokenSource cts = new CancellationTokenSource(); CancellationToken token = cts.getToken(); - token.register(new Runnable() { - @Override - public void run() { - // Do nothing - } + token.register(() -> { + // Do nothing }); cts.close(); diff --git a/bolts-tasks/src/test/java/com/parse/boltsinternal/TaskTest.java b/bolts-tasks/src/test/java/com/parse/boltsinternal/TaskTest.java index 8d096dd46..e07b9c807 100644 --- a/bolts-tasks/src/test/java/com/parse/boltsinternal/TaskTest.java +++ b/bolts-tasks/src/test/java/com/parse/boltsinternal/TaskTest.java @@ -6,6 +6,12 @@ */ package com.parse.boltsinternal; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -16,20 +22,13 @@ import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.Executors; -import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - public class TaskTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); private void runTaskTest(Callable> callable) { try { @@ -117,52 +116,38 @@ public void testSynchronousContinuation() { final Task error = Task.forError(new RuntimeException()); final Task cancelled = Task.cancelled(); - complete.continueWith(new Continuation() { - public Void then(Task task) { - assertEquals(complete, task); - assertTrue(task.isCompleted()); - assertEquals(5, task.getResult().intValue()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - return null; - } + complete.continueWith((Continuation) task -> { + assertEquals(complete, task); + assertTrue(task.isCompleted()); + assertEquals(5, task.getResult().intValue()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + return null; }); - error.continueWith(new Continuation() { - public Void then(Task task) { - assertEquals(error, task); - assertTrue(task.isCompleted()); - assertTrue(task.getError() instanceof RuntimeException); - assertTrue(task.isFaulted()); - assertFalse(task.isCancelled()); - return null; - } + error.continueWith((Continuation) task -> { + assertEquals(error, task); + assertTrue(task.isCompleted()); + assertTrue(task.getError() instanceof RuntimeException); + assertTrue(task.isFaulted()); + assertFalse(task.isCancelled()); + return null; }); - cancelled.continueWith(new Continuation() { - public Void then(Task task) { - assertEquals(cancelled, task); - assertTrue(cancelled.isCompleted()); - assertFalse(cancelled.isFaulted()); - assertTrue(cancelled.isCancelled()); - return null; - } + cancelled.continueWith((Continuation) task -> { + assertEquals(cancelled, task); + assertTrue(cancelled.isCompleted()); + assertFalse(cancelled.isFaulted()); + assertTrue(cancelled.isCancelled()); + return null; }); } @Test public void testSynchronousChaining() { Task first = Task.forResult(1); - Task second = first.continueWith(new Continuation() { - public Integer then(Task task) { - return 2; - } - }); - Task third = second.continueWithTask(new Continuation>() { - public Task then(Task task) { - return Task.forResult(3); - } - }); + Task second = first.continueWith(task -> 2); + Task third = second.continueWithTask(task -> Task.forResult(3)); assertTrue(first.isCompleted()); assertTrue(second.isCompleted()); assertTrue(third.isCompleted()); @@ -174,10 +159,8 @@ public Task then(Task task) { @Test public void testSynchronousCancellation() { Task first = Task.forResult(1); - Task second = first.continueWith(new Continuation() { - public Integer then(Task task) { - throw new CancellationException(); - } + Task second = first.continueWith(task -> { + throw new CancellationException(); }); assertTrue(first.isCompleted()); assertTrue(second.isCancelled()); @@ -189,11 +172,9 @@ public void testSynchronousContinuationTokenAlreadyCancelled() { final Capture continuationRun = new Capture<>(false); cts.cancel(); Task first = Task.forResult(1); - Task second = first.continueWith(new Continuation() { - public Integer then(Task task) { - continuationRun.set(true); - return 2; - } + Task second = first.continueWith(task -> { + continuationRun.set(true); + return 2; }, cts.getToken()); assertTrue(first.isCompleted()); assertTrue(second.isCancelled()); @@ -203,10 +184,8 @@ public Integer then(Task task) { @Test public void testSynchronousTaskCancellation() { Task first = Task.forResult(1); - Task second = first.continueWithTask(new Continuation>() { - public Task then(Task task) { - throw new CancellationException(); - } + Task second = first.continueWithTask(task -> { + throw new CancellationException(); }); assertTrue(first.isCompleted()); assertTrue(second.isCancelled()); @@ -214,21 +193,13 @@ public Task then(Task task) { @Test public void testBackgroundCall() { - runTaskTest(new Callable>() { - public Task call() throws Exception { - return Task.callInBackground(new Callable() { - public Integer call() throws Exception { - Thread.sleep(100); - return 5; - } - }).continueWith(new Continuation() { - public Void then(Task task) { - assertEquals(5, task.getResult().intValue()); - return null; - } - }); - } - }); + runTaskTest(() -> Task.callInBackground(() -> { + Thread.sleep(100); + return 5; + }).continueWith((Continuation) task -> { + assertEquals(5, task.getResult().intValue()); + return null; + })); } @Test @@ -238,16 +209,13 @@ public void testBackgroundCallTokenCancellation() { final Capture waitingToBeCancelled = new Capture<>(false); final Object cancelLock = new Object(); - Task task = Task.callInBackground(new Callable() { - @Override - public Integer call() throws Exception { - synchronized (cancelLock) { - waitingToBeCancelled.set(true); - cancelLock.wait(); - } - ct.throwIfCancellationRequested(); - return 5; + Task task = Task.callInBackground(() -> { + synchronized (cancelLock) { + waitingToBeCancelled.set(true); + cancelLock.wait(); } + ct.throwIfCancellationRequested(); + return 5; }); while (true) { @@ -279,30 +247,20 @@ public void testBackgroundCallTokenAlreadyCancelled() { final CancellationTokenSource cts = new CancellationTokenSource(); cts.cancel(); - runTaskTest(new Callable>() { - public Task call() throws Exception { - return Task.callInBackground(new Callable() { - public Integer call() throws Exception { - Thread.sleep(100); - return 5; - } - }, cts.getToken()).continueWith(new Continuation() { - public Void then(Task task) { - assertTrue(task.isCancelled()); - return null; - } - }); - } - }); + runTaskTest(() -> Task.callInBackground(() -> { + Thread.sleep(100); + return 5; + }, cts.getToken()).continueWith((Continuation) task -> { + assertTrue(task.isCancelled()); + return null; + })); } @Test public void testBackgroundCallWaiting() throws Exception { - Task task = Task.callInBackground(new Callable() { - public Integer call() throws Exception { - Thread.sleep(100); - return 5; - } + Task task = Task.callInBackground(() -> { + Thread.sleep(100); + return 5; }); task.waitForCompletion(); assertTrue(task.isCompleted()); @@ -313,14 +271,12 @@ public Integer call() throws Exception { public void testBackgroundCallWaitingWithTimeouts() throws Exception { final Object sync = new Object(); - Task task = Task.callInBackground(new Callable() { - public Integer call() throws Exception { - synchronized (sync) { - sync.wait(); - Thread.sleep(100); - } - return 5; + Task task = Task.callInBackground(() -> { + synchronized (sync) { + sync.wait(); + Thread.sleep(100); } + return 5; }); // wait -> timeout assertFalse(task.waitForCompletion(100, TimeUnit.MILLISECONDS)); @@ -336,11 +292,9 @@ public Integer call() throws Exception { @Test public void testBackgroundCallWaitingOnError() throws Exception { - Task task = Task.callInBackground(new Callable() { - public Integer call() throws Exception { - Thread.sleep(100); - throw new RuntimeException(); - } + Task task = Task.callInBackground(() -> { + Thread.sleep(100); + throw new RuntimeException(); }); task.waitForCompletion(); assertTrue(task.isCompleted()); @@ -349,17 +303,10 @@ public Integer call() throws Exception { @Test public void testBackgroundCallWaitOnCancellation() throws Exception { - Task task = Task.callInBackground(new Callable() { - public Integer call() throws Exception { - Thread.sleep(100); - return 5; - } - }).continueWithTask(new Continuation>() { - - public Task then(Task task) { - return Task.cancelled(); - } - }); + Task task = Task.callInBackground(() -> { + Thread.sleep(100); + return 5; + }).continueWithTask(task1 -> Task.cancelled()); task.waitForCompletion(); assertTrue(task.isCompleted()); assertTrue(task.isCancelled()); @@ -367,51 +314,32 @@ public Task then(Task task) { @Test public void testBackgroundError() { - runTaskTest(new Callable>() { - public Task call() throws Exception { - return Task.callInBackground(new Callable() { - public Integer call() throws Exception { - throw new IllegalStateException(); - } - }).continueWith(new Continuation() { - public Void then(Task task) { - assertTrue(task.isFaulted()); - assertTrue(task.getError() instanceof IllegalStateException); - return null; - } - }); - } - }); + runTaskTest(() -> Task.callInBackground((Callable) () -> { + throw new IllegalStateException(); + }).continueWith((Continuation) task -> { + assertTrue(task.isFaulted()); + assertTrue(task.getError() instanceof IllegalStateException); + return null; + })); } @Test public void testBackgroundCancellation() { - runTaskTest(new Callable>() { - public Task call() throws Exception { - return Task.callInBackground(new Callable() { - public Void call() throws Exception { - throw new CancellationException(); - } - }).continueWith(new Continuation() { - public Void then(Task task) { - assertTrue(task.isCancelled()); - return null; - } - }); - } - }); + runTaskTest(() -> Task.callInBackground((Callable) () -> { + throw new CancellationException(); + }).continueWith((Continuation) task -> { + assertTrue(task.isCancelled()); + return null; + })); } @Test public void testUnobservedError() throws InterruptedException { try { final Object sync = new Object(); - Task.setUnobservedExceptionHandler(new Task.UnobservedExceptionHandler() { - @Override - public void unobservedException(Task t, UnobservedTaskException e) { - synchronized (sync) { - sync.notify(); - } + Task.setUnobservedExceptionHandler((t, e) -> { + synchronized (sync) { + sync.notify(); } }); @@ -428,11 +356,8 @@ public void unobservedException(Task t, UnobservedTaskException e) { // runs in a separate method to ensure it is out of scope. private void startFailedTask() throws InterruptedException { - Task.call(new Callable() { - @Override - public Object call() throws Exception { - throw new RuntimeException(); - } + Task.call(() -> { + throw new RuntimeException(); }).waitForCompletion(); } @@ -447,206 +372,152 @@ public void testWhenAllNoTasks() { @Test public void testWhenAnyResultFirstSuccess() { - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - final Task firstToCompleteSuccess = Task.callInBackground(new Callable() { - @Override - public Integer call() throws Exception { - Thread.sleep(50); - return 10; - } - }); - tasks.addAll(launchTasksWithRandomCompletions(5)); - tasks.add(firstToCompleteSuccess); - tasks.addAll(launchTasksWithRandomCompletions(5)); - return Task.whenAnyResult(tasks).continueWith(new Continuation, Void>() { - @Override - public Void then(Task> task) throws Exception { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - assertEquals(firstToCompleteSuccess, task.getResult()); - assertTrue(task.getResult().isCompleted()); - assertFalse(task.getResult().isCancelled()); - assertFalse(task.getResult().isFaulted()); - assertEquals(10, (int) task.getResult().getResult()); - return null; - } - }); - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + final Task firstToCompleteSuccess = Task.callInBackground(() -> { + Thread.sleep(50); + return 10; + }); + tasks.addAll(launchTasksWithRandomCompletions(5)); + tasks.add(firstToCompleteSuccess); + tasks.addAll(launchTasksWithRandomCompletions(5)); + return Task.whenAnyResult(tasks).continueWith((Continuation, Void>) task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + assertEquals(firstToCompleteSuccess, task.getResult()); + assertTrue(task.getResult().isCompleted()); + assertFalse(task.getResult().isCancelled()); + assertFalse(task.getResult().isFaulted()); + assertEquals(10, (int) task.getResult().getResult()); + return null; + }); }); } @Test public void testWhenAnyFirstSuccess() { - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - final Task firstToCompleteSuccess = Task.callInBackground(new Callable() { - @Override - public String call() throws Exception { - Thread.sleep(50); - return "SUCCESS"; - } - }); - tasks.addAll(launchTasksWithRandomCompletions(5)); - tasks.add(firstToCompleteSuccess); - tasks.addAll(launchTasksWithRandomCompletions(5)); - return Task.whenAny(tasks).continueWith(new Continuation, Object>() { - @Override - public Object then(Task> task) throws Exception { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - assertEquals(firstToCompleteSuccess, task.getResult()); - assertTrue(task.getResult().isCompleted()); - assertFalse(task.getResult().isCancelled()); - assertFalse(task.getResult().isFaulted()); - assertEquals("SUCCESS", task.getResult().getResult()); - return null; - } - }); - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + final Task firstToCompleteSuccess = Task.callInBackground(() -> { + Thread.sleep(50); + return "SUCCESS"; + }); + tasks.addAll(launchTasksWithRandomCompletions(5)); + tasks.add(firstToCompleteSuccess); + tasks.addAll(launchTasksWithRandomCompletions(5)); + return Task.whenAny(tasks).continueWith(task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + assertEquals(firstToCompleteSuccess, task.getResult()); + assertTrue(task.getResult().isCompleted()); + assertFalse(task.getResult().isCancelled()); + assertFalse(task.getResult().isFaulted()); + assertEquals("SUCCESS", task.getResult().getResult()); + return null; + }); }); } @Test public void testWhenAnyResultFirstError() { final Exception error = new RuntimeException("This task failed."); - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - final Task firstToCompleteError = Task.callInBackground(new Callable() { - @Override - public Integer call() throws Exception { - Thread.sleep(50); - throw error; - } - }); - tasks.addAll(launchTasksWithRandomCompletions(5)); - tasks.add(firstToCompleteError); - tasks.addAll(launchTasksWithRandomCompletions(5)); - return Task.whenAnyResult(tasks).continueWith(new Continuation, Object>() { - @Override - public Object then(Task> task) throws Exception { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - assertEquals(firstToCompleteError, task.getResult()); - assertTrue(task.getResult().isCompleted()); - assertFalse(task.getResult().isCancelled()); - assertTrue(task.getResult().isFaulted()); - assertEquals(error, task.getResult().getError()); - return null; - } - }); - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + final Task firstToCompleteError = Task.callInBackground(() -> { + Thread.sleep(50); + throw error; + }); + tasks.addAll(launchTasksWithRandomCompletions(5)); + tasks.add(firstToCompleteError); + tasks.addAll(launchTasksWithRandomCompletions(5)); + return Task.whenAnyResult(tasks).continueWith(task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + assertEquals(firstToCompleteError, task.getResult()); + assertTrue(task.getResult().isCompleted()); + assertFalse(task.getResult().isCancelled()); + assertTrue(task.getResult().isFaulted()); + assertEquals(error, task.getResult().getError()); + return null; + }); }); } @Test public void testWhenAnyFirstError() { final Exception error = new RuntimeException("This task failed."); - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - final Task firstToCompleteError = Task.callInBackground(new Callable() { - @Override - public String call() throws Exception { - Thread.sleep(50); - throw error; - } - }); - tasks.addAll(launchTasksWithRandomCompletions(5)); - tasks.add(firstToCompleteError); - tasks.addAll(launchTasksWithRandomCompletions(5)); - return Task.whenAny(tasks).continueWith(new Continuation, Object>() { - @Override - public Object then(Task> task) throws Exception { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - assertEquals(firstToCompleteError, task.getResult()); - assertTrue(task.getResult().isCompleted()); - assertFalse(task.getResult().isCancelled()); - assertTrue(task.getResult().isFaulted()); - assertEquals(error, task.getResult().getError()); - return null; - } - }); - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + final Task firstToCompleteError = Task.callInBackground(() -> { + Thread.sleep(50); + throw error; + }); + tasks.addAll(launchTasksWithRandomCompletions(5)); + tasks.add(firstToCompleteError); + tasks.addAll(launchTasksWithRandomCompletions(5)); + return Task.whenAny(tasks).continueWith(task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + assertEquals(firstToCompleteError, task.getResult()); + assertTrue(task.getResult().isCompleted()); + assertFalse(task.getResult().isCancelled()); + assertTrue(task.getResult().isFaulted()); + assertEquals(error, task.getResult().getError()); + return null; + }); }); } @Test public void testWhenAnyResultFirstCancelled() { - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - final Task firstToCompleteCancelled = Task.callInBackground(new Callable() { - @Override - public Integer call() throws Exception { - Thread.sleep(50); - throw new CancellationException(); - } - }); + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + final Task firstToCompleteCancelled = Task.callInBackground(() -> { + Thread.sleep(50); + throw new CancellationException(); + }); - tasks.addAll(launchTasksWithRandomCompletions(5)); - tasks.add(firstToCompleteCancelled); - tasks.addAll(launchTasksWithRandomCompletions(5)); - return Task.whenAnyResult(tasks).continueWith(new Continuation, Object>() { - @Override - public Object then(Task> task) throws Exception { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - assertEquals(firstToCompleteCancelled, task.getResult()); - assertTrue(task.getResult().isCompleted()); - assertTrue(task.getResult().isCancelled()); - assertFalse(task.getResult().isFaulted()); - return null; - } - }); - } + tasks.addAll(launchTasksWithRandomCompletions(5)); + tasks.add(firstToCompleteCancelled); + tasks.addAll(launchTasksWithRandomCompletions(5)); + return Task.whenAnyResult(tasks).continueWith(task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + assertEquals(firstToCompleteCancelled, task.getResult()); + assertTrue(task.getResult().isCompleted()); + assertTrue(task.getResult().isCancelled()); + assertFalse(task.getResult().isFaulted()); + return null; + }); }); } @Test public void testWhenAnyFirstCancelled() { - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - final Task firstToCompleteCancelled = Task.callInBackground(new Callable() { - @Override - public String call() throws Exception { - Thread.sleep(50); - throw new CancellationException(); - } - }); - tasks.addAll(launchTasksWithRandomCompletions(5)); - tasks.add(firstToCompleteCancelled); - tasks.addAll(launchTasksWithRandomCompletions(5)); - return Task.whenAny(tasks).continueWith(new Continuation, Object>() { - @Override - public Object then(Task> task) throws Exception { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - assertEquals(firstToCompleteCancelled, task.getResult()); - assertTrue(task.getResult().isCompleted()); - assertTrue(task.getResult().isCancelled()); - assertFalse(task.getResult().isFaulted()); - return null; - } - }); - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + final Task firstToCompleteCancelled = Task.callInBackground(() -> { + Thread.sleep(50); + throw new CancellationException(); + }); + tasks.addAll(launchTasksWithRandomCompletions(5)); + tasks.add(firstToCompleteCancelled); + tasks.addAll(launchTasksWithRandomCompletions(5)); + return Task.whenAny(tasks).continueWith(task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + assertEquals(firstToCompleteCancelled, task.getResult()); + assertTrue(task.getResult().isCompleted()); + assertTrue(task.getResult().isCancelled()); + assertFalse(task.getResult().isFaulted()); + return null; + }); }); } @@ -663,18 +534,15 @@ public Object then(Task> task) throws Exception { private Collection> launchTasksWithRandomCompletions(int numberOfTasksToLaunch) { final ArrayList> tasks = new ArrayList<>(); for (int i = 0; i < numberOfTasksToLaunch; i++) { - Task task = Task.callInBackground(new Callable() { - @Override - public Integer call() throws Exception { - Thread.sleep((long) (500 + (Math.random() * 100))); - double rand = Math.random(); - if (rand >= 0.7) { - throw new RuntimeException("This task failed."); - } else if (rand >= 0.4) { - throw new CancellationException(); - } - return (int) (Math.random() * 1000); + Task task = Task.callInBackground(() -> { + Thread.sleep((long) (500 + (Math.random() * 100))); + double rand = Math.random(); + if (rand >= 0.7) { + throw new RuntimeException("This task failed."); + } else if (rand >= 0.4) { + throw new CancellationException(); } + return (int) (Math.random() * 1000); }); tasks.add(task); } @@ -683,34 +551,25 @@ public Integer call() throws Exception { @Test public void testWhenAllSuccess() { - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - Task task = Task.callInBackground(new Callable() { - @Override - public Void call() throws Exception { - Thread.sleep((long) (Math.random() * 100)); - return null; - } - }); - tasks.add(task); - } - return Task.whenAll(tasks).continueWith(new Continuation() { - @Override - public Void then(Task task) { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - - for (Task t : tasks) { - assertTrue(t.isCompleted()); - } - return null; - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + Task task = Task.callInBackground(() -> { + Thread.sleep((long) (Math.random() * 100)); + return null; }); + tasks.add(task); } + return Task.whenAll(tasks).continueWith((Continuation) task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + + for (Task t : tasks) { + assertTrue(t.isCompleted()); + } + return null; + }); }); } @@ -718,41 +577,32 @@ public Void then(Task task) { public void testWhenAllOneError() { final Exception error = new RuntimeException("This task failed."); - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - final int number = i; - Task task = Task.callInBackground(new Callable() { - @Override - public Void call() throws Exception { - Thread.sleep((long) (Math.random() * 100)); - if (number == 10) { - throw error; - } - return null; - } - }); - tasks.add(task); - } - return Task.whenAll(tasks).continueWith(new Continuation() { - @Override - public Void then(Task task) { - assertTrue(task.isCompleted()); - assertTrue(task.isFaulted()); - assertFalse(task.isCancelled()); - - assertFalse(task.getError() instanceof AggregateException); - assertEquals(error, task.getError()); - - for (Task t : tasks) { - assertTrue(t.isCompleted()); - } - return null; + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + final int number = i; + Task task = Task.callInBackground(() -> { + Thread.sleep((long) (Math.random() * 100)); + if (number == 10) { + throw error; } + return null; }); + tasks.add(task); } + return Task.whenAll(tasks).continueWith((Continuation) task -> { + assertTrue(task.isCompleted()); + assertTrue(task.isFaulted()); + assertFalse(task.isCancelled()); + + assertFalse(task.getError() instanceof AggregateException); + assertEquals(error, task.getError()); + + for (Task t : tasks) { + assertTrue(t.isCompleted()); + } + return null; + }); }); } @@ -761,94 +611,76 @@ public void testWhenAllTwoErrors() { final Exception error0 = new RuntimeException("This task failed (0)."); final Exception error1 = new RuntimeException("This task failed (1)."); - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - final int number = i; - Task task = Task.callInBackground(new Callable() { - @Override - public Void call() throws Exception { - Thread.sleep((long) (number * 10)); - if (number == 10) { - throw error0; - } else if (number == 11) { - throw error1; - } - return null; - } - }); - tasks.add(task); - } - return Task.whenAll(tasks).continueWith(new Continuation() { - @Override - public Void then(Task task) { - assertTrue(task.isCompleted()); - assertTrue(task.isFaulted()); - assertFalse(task.isCancelled()); - - assertTrue(task.getError() instanceof AggregateException); - assertEquals(2, ((AggregateException) task.getError()).getInnerThrowables().size()); - assertEquals(error0, ((AggregateException) task.getError()).getInnerThrowables().get(0)); - assertEquals(error1, ((AggregateException) task.getError()).getInnerThrowables().get(1)); - assertEquals(error0, task.getError().getCause()); - - for (Task t : tasks) { - assertTrue(t.isCompleted()); - } - return null; - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + final int number = i; + Task task = Task.callInBackground(() -> { + Thread.sleep((long) (number * 10)); + if (number == 10) { + throw error0; + } else if (number == 11) { + throw error1; + } + return null; }); + tasks.add(task); } + return Task.whenAll(tasks).continueWith((Continuation) task -> { + assertTrue(task.isCompleted()); + assertTrue(task.isFaulted()); + assertFalse(task.isCancelled()); + + assertTrue(task.getError() instanceof AggregateException); + assertEquals(2, ((AggregateException) task.getError()).getInnerThrowables().size()); + assertEquals(error0, ((AggregateException) task.getError()).getInnerThrowables().get(0)); + assertEquals(error1, ((AggregateException) task.getError()).getInnerThrowables().get(1)); + assertEquals(error0, task.getError().getCause()); + + for (Task t : tasks) { + assertTrue(t.isCompleted()); + } + return null; + }); }); } @Test public void testWhenAllCancel() { - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final ArrayList> tasks = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - final TaskCompletionSource tcs = new TaskCompletionSource<>(); - - final int number = i; - Task.callInBackground(new Callable() { - @Override - public Void call() throws Exception { - Thread.sleep((long) (Math.random() * 100)); - if (number == 10) { - tcs.setCancelled(); - } else { - tcs.setResult(null); - } - return null; - } - }); - - tasks.add(tcs.getTask()); - } - return Task.whenAll(tasks).continueWith(new Continuation() { - @Override - public Void then(Task task) { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertTrue(task.isCancelled()); - - for (Task t : tasks) { - assertTrue(t.isCompleted()); - } - return null; - } + runTaskTest(() -> { + final ArrayList> tasks = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + final TaskCompletionSource tcs = new TaskCompletionSource<>(); + + final int number = i; + Task.callInBackground((Callable) () -> { + Thread.sleep((long) (Math.random() * 100)); + if (number == 10) { + tcs.setCancelled(); + } else { + tcs.setResult(null); + } + return null; }); + + tasks.add(tcs.getTask()); } + return Task.whenAll(tasks).continueWith((Continuation) task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertTrue(task.isCancelled()); + + for (Task t : tasks) { + assertTrue(t.isCompleted()); + } + return null; + }); }); } @Test public void testWhenAllResultNoTasks() { - Task> task = Task.whenAllResult(new ArrayList>()); + Task> task = Task.whenAllResult(new ArrayList<>()); assertTrue(task.isCompleted()); assertFalse(task.isCancelled()); @@ -858,82 +690,59 @@ public void testWhenAllResultNoTasks() { @Test public void testWhenAllResultSuccess() { - runTaskTest(new Callable>() { - @Override - public Task call() throws Exception { - final List> tasks = new ArrayList<>(); - for (int i = 0; i < 20; i++) { - final int number = (i + 1); - Task task = Task.callInBackground(new Callable() { - @Override - public Integer call() throws Exception { - Thread.sleep((long) (Math.random() * 100)); - return number; - } - }); - tasks.add(task); - } - return Task.whenAllResult(tasks).continueWith(new Continuation, Void>() { - @Override - public Void then(Task> task) { - assertTrue(task.isCompleted()); - assertFalse(task.isFaulted()); - assertFalse(task.isCancelled()); - assertEquals(tasks.size(), task.getResult().size()); - - for (int i = 0; i < tasks.size(); i++) { - Task t = tasks.get(i); - assertTrue(t.isCompleted()); - assertEquals(t.getResult(), task.getResult().get(i)); - } - - return null; - } + runTaskTest(() -> { + final List> tasks = new ArrayList<>(); + for (int i = 0; i < 20; i++) { + final int number = (i + 1); + Task task = Task.callInBackground(() -> { + Thread.sleep((long) (Math.random() * 100)); + return number; }); + tasks.add(task); } + return Task.whenAllResult(tasks).continueWith((Continuation, Void>) task -> { + assertTrue(task.isCompleted()); + assertFalse(task.isFaulted()); + assertFalse(task.isCancelled()); + assertEquals(tasks.size(), task.getResult().size()); + + for (int i = 0; i < tasks.size(); i++) { + Task t = tasks.get(i); + assertTrue(t.isCompleted()); + assertEquals(t.getResult(), task.getResult().get(i)); + } + + return null; + }); }); } @Test public void testAsyncChaining() { - runTaskTest(new Callable>() { - public Task call() throws Exception { - final ArrayList sequence = new ArrayList<>(); - Task result = Task.forResult(null); + runTaskTest(() -> { + final ArrayList sequence = new ArrayList<>(); + Task result = Task.forResult(null); + for (int i = 0; i < 20; i++) { + final int taskNumber = i; + result = result.continueWithTask(task -> Task.callInBackground(() -> { + sequence.add(taskNumber); + return null; + })); + } + result = result.continueWith(task -> { + assertEquals(20, sequence.size()); for (int i = 0; i < 20; i++) { - final int taskNumber = i; - result = result.continueWithTask(new Continuation>() { - public Task then(Task task) { - return Task.callInBackground(new Callable() { - public Void call() throws Exception { - sequence.add(taskNumber); - return null; - } - }); - } - }); + assertEquals(i, sequence.get(i).intValue()); } - result = result.continueWith(new Continuation() { - public Void then(Task task) { - assertEquals(20, sequence.size()); - for (int i = 0; i < 20; i++) { - assertEquals(i, sequence.get(i).intValue()); - } - return null; - } - }); - return result; - } + return null; + }); + return result; }); } @Test public void testOnSuccess() { - Continuation continuation = new Continuation() { - public Integer then(Task task) { - return task.getResult() + 1; - } - }; + Continuation continuation = task -> task.getResult() + 1; Task complete = Task.forResult(5).onSuccess(continuation); Task error = Task.forError(new IllegalStateException()).onSuccess( continuation); @@ -956,11 +765,7 @@ public Integer then(Task task) { @Test public void testOnSuccessTask() { - Continuation> continuation = new Continuation>() { - public Task then(Task task) { - return Task.forResult(task.getResult() + 1); - } - }; + Continuation> continuation = task -> Task.forResult(task.getResult() + 1); Task complete = Task.forResult(5).onSuccessTask(continuation); Task error = Task.forError(new IllegalStateException()).onSuccessTask( continuation); @@ -984,103 +789,56 @@ public Task then(Task task) { @Test public void testContinueWhile() { final AtomicInteger count = new AtomicInteger(0); - runTaskTest(new Callable>() { - public Task call() throws Exception { - return Task.forResult(null).continueWhile(new Callable() { - public Boolean call() throws Exception { - return count.get() < 10; - } - }, new Continuation>() { - public Task then(Task task) throws Exception { - count.incrementAndGet(); - return null; - } - }).continueWith(new Continuation() { - public Void then(Task task) throws Exception { - assertEquals(10, count.get()); - return null; - } - }); - } - }); + runTaskTest(() -> Task.forResult(null).continueWhile(() -> count.get() < 10, task -> { + count.incrementAndGet(); + return null; + }).continueWith((Continuation) task -> { + assertEquals(10, count.get()); + return null; + })); } @Test public void testContinueWhileAsync() { final AtomicInteger count = new AtomicInteger(0); - runTaskTest(new Callable>() { - public Task call() throws Exception { - return Task.forResult(null).continueWhile(new Callable() { - public Boolean call() throws Exception { - return count.get() < 10; - } - }, new Continuation>() { - public Task then(Task task) throws Exception { - count.incrementAndGet(); - return null; - } - }, Executors.newCachedThreadPool()).continueWith(new Continuation() { - public Void then(Task task) throws Exception { - assertEquals(10, count.get()); - return null; - } - }); - } - }); + runTaskTest(() -> Task.forResult(null).continueWhile(() -> count.get() < 10, task -> { + count.incrementAndGet(); + return null; + }, Executors.newCachedThreadPool()).continueWith((Continuation) task -> { + assertEquals(10, count.get()); + return null; + })); } @Test public void testContinueWhileAsyncCancellation() { final AtomicInteger count = new AtomicInteger(0); final CancellationTokenSource cts = new CancellationTokenSource(); - runTaskTest(new Callable>() { - public Task call() throws Exception { - return Task.forResult(null).continueWhile(new Callable() { - public Boolean call() throws Exception { - return count.get() < 10; - } - }, new Continuation>() { - public Task then(Task task) - throws Exception { - if (count.incrementAndGet() == 5) { - cts.cancel(); - } - return null; - } - }, Executors.newCachedThreadPool(), - cts.getToken()).continueWith(new Continuation() { - public Void then(Task task) throws Exception { - assertTrue(task.isCancelled()); - assertEquals(5, count.get()); - return null; + runTaskTest(() -> Task.forResult(null).continueWhile(() -> count.get() < 10, task -> { + if (count.incrementAndGet() == 5) { + cts.cancel(); } - }); - } - }); + return null; + }, Executors.newCachedThreadPool(), + cts.getToken()).continueWith((Continuation) task -> { + assertTrue(task.isCancelled()); + assertEquals(5, count.get()); + return null; + })); } @Test public void testCallWithBadExecutor() { final RuntimeException exception = new RuntimeException("BAD EXECUTORS"); - Task.call(new Callable() { - public Integer call() throws Exception { - return 1; - } - }, new Executor() { - @Override - public void execute(Runnable command) { - throw exception; - } - }).continueWith(new Continuation() { - @Override - public Object then(Task task) throws Exception { - assertTrue(task.isFaulted()); - assertTrue(task.getError() instanceof ExecutorException); - assertEquals(exception, task.getError().getCause()); + Task.call(() -> 1, command -> { + throw exception; + }).continueWith(task -> { + assertTrue(task.isFaulted()); + assertTrue(task.getError() instanceof ExecutorException); + assertEquals(exception, task.getError().getCause()); - return null; - } + return null; }); } @@ -1088,29 +846,14 @@ public Object then(Task task) throws Exception { public void testContinueWithBadExecutor() { final RuntimeException exception = new RuntimeException("BAD EXECUTORS"); - Task.call(new Callable() { - public Integer call() throws Exception { - return 1; - } - }).continueWith(new Continuation() { - @Override - public Integer then(Task task) throws Exception { - return task.getResult(); - } - }, new Executor() { - @Override - public void execute(Runnable command) { - throw exception; - } - }).continueWith(new Continuation() { - @Override - public Object then(Task task) throws Exception { - assertTrue(task.isFaulted()); - assertTrue(task.getError() instanceof ExecutorException); - assertEquals(exception, task.getError().getCause()); + Task.call(() -> 1).continueWith(Task::getResult, command -> { + throw exception; + }).continueWith(task -> { + assertTrue(task.isFaulted()); + assertTrue(task.getError() instanceof ExecutorException); + assertEquals(exception, task.getError().getCause()); - return null; - } + return null; }); } @@ -1118,29 +861,14 @@ public Object then(Task task) throws Exception { public void testContinueWithTaskAndBadExecutor() { final RuntimeException exception = new RuntimeException("BAD EXECUTORS"); - Task.call(new Callable() { - public Integer call() throws Exception { - return 1; - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - return task; - } - }, new Executor() { - @Override - public void execute(Runnable command) { - throw exception; - } - }).continueWith(new Continuation() { - @Override - public Object then(Task task) throws Exception { - assertTrue(task.isFaulted()); - assertTrue(task.getError() instanceof ExecutorException); - assertEquals(exception, task.getError().getCause()); + Task.call(() -> 1).continueWithTask(task -> task, command -> { + throw exception; + }).continueWith(task -> { + assertTrue(task.isFaulted()); + assertTrue(task.getError() instanceof ExecutorException); + assertEquals(exception, task.getError().getCause()); - return null; - } + return null; }); } diff --git a/build.gradle b/build.gradle index 586f69f2c..bc52b0821 100644 --- a/build.gradle +++ b/build.gradle @@ -1,14 +1,18 @@ buildscript { - ext.kotlin_version = "1.4.10" + ext.kotlin_version = "1.5.31" + ext.jacocoVersion = '0.8.7' repositories { google() - jcenter() + mavenCentral() } dependencies { - classpath "com.android.tools.build:gradle:3.6.2" + classpath "com.android.tools.build:gradle:4.2.2" classpath "org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.8.3" classpath "com.github.dcendents:android-maven-gradle-plugin:2.1" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jacoco:org.jacoco.core:$jacocoVersion" + classpath "com.dicedmelon.gradle:jacoco-android:0.1.5" + classpath "io.freefair.gradle:android-gradle-plugins:4.2.0-m1" } } @@ -19,7 +23,7 @@ plugins { allprojects { repositories { google() - jcenter() + mavenCentral() } } @@ -28,8 +32,8 @@ task clean(type: Delete) { } ext { - compileSdkVersion = 29 + compileSdkVersion = 30 - minSdkVersion = 14 - targetSdkVersion = 29 + minSdkVersion = 16 + targetSdkVersion = 30 } diff --git a/coroutines/build.gradle b/coroutines/build.gradle index 00e93ae2a..91eab0f38 100644 --- a/coroutines/build.gradle +++ b/coroutines/build.gradle @@ -1,5 +1,7 @@ apply plugin: "com.android.library" apply plugin: "kotlin-android" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -26,17 +28,23 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } } ext { - coroutinesVersion = "1.3.9" + coroutinesVersion = "1.5.0" } dependencies { - api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion" api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion" implementation project(":parse") -} - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" +} \ No newline at end of file diff --git a/coroutines/src/main/java/com/parse/coroutines/ParseQueryCoroutinesBuilder.kt b/coroutines/src/main/java/com/parse/coroutines/ParseQueryCoroutinesBuilder.kt index 2030acfc0..8b2d30988 100644 --- a/coroutines/src/main/java/com/parse/coroutines/ParseQueryCoroutinesBuilder.kt +++ b/coroutines/src/main/java/com/parse/coroutines/ParseQueryCoroutinesBuilder.kt @@ -14,7 +14,7 @@ fun CoroutineScope.launchQuery( query: ParseQuery, context: CoroutineContext = EmptyCoroutineContext, block: suspend ParseQueryOperation.() -> Unit -) : Job { +): Job { return launch(context) { block.invoke(ParseQueryOperationImpl(query)) } diff --git a/coroutines/src/main/java/com/parse/coroutines/ParseQueryOperationImpl.kt b/coroutines/src/main/java/com/parse/coroutines/ParseQueryOperationImpl.kt index 4a6a8f53a..cdf41b612 100644 --- a/coroutines/src/main/java/com/parse/coroutines/ParseQueryOperationImpl.kt +++ b/coroutines/src/main/java/com/parse/coroutines/ParseQueryOperationImpl.kt @@ -3,7 +3,8 @@ package com.parse.coroutines import com.parse.ParseObject import com.parse.ParseQuery -class ParseQueryOperationImpl(private val query: ParseQuery) : ParseQueryOperation { +class ParseQueryOperationImpl(private val query: ParseQuery) : + ParseQueryOperation { override suspend fun find(): List = query.findInternal() diff --git a/facebook/build.gradle b/facebook/build.gradle index 08627f308..a62a82720 100644 --- a/facebook/build.gradle +++ b/facebook/build.gradle @@ -1,4 +1,6 @@ apply plugin: "com.android.library" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -17,15 +19,18 @@ android { lintOptions { abortOnError false } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { api "com.facebook.android:facebook-login:6.3.0" implementation project(":parse") - testImplementation "junit:junit:4.13" - testImplementation "org.mockito:mockito-core:1.10.19" - testImplementation "org.robolectric:robolectric:3.8" -} - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" + testImplementation "junit:junit:4.13.2" + testImplementation "org.mockito:mockito-core:3.9.0" + testImplementation "org.robolectric:robolectric:4.6" +} \ No newline at end of file diff --git a/facebook/src/main/java/com/parse/facebook/FacebookController.java b/facebook/src/main/java/com/parse/facebook/FacebookController.java index 8a3b85937..cef2ae3c6 100644 --- a/facebook/src/main/java/com/parse/facebook/FacebookController.java +++ b/facebook/src/main/java/com/parse/facebook/FacebookController.java @@ -23,6 +23,7 @@ import com.facebook.FacebookSdk; import com.facebook.login.LoginManager; import com.facebook.login.LoginResult; +import com.parse.boltsinternal.Task; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -36,10 +37,10 @@ import java.util.Set; import java.util.SimpleTimeZone; -import com.parse.boltsinternal.Task; - class FacebookController { + // Used as default activityCode. From FacebookSdk.java. + public static final int DEFAULT_AUTH_ACTIVITY_CODE = 0xface; /** * Precise date format required for auth expiration data. */ @@ -47,28 +48,18 @@ class FacebookController { new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); private static final DateFormat IMPRECISE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US); - - static { - PRECISE_DATE_FORMAT.setTimeZone(new SimpleTimeZone(0, "GMT")); - IMPRECISE_DATE_FORMAT.setTimeZone(new SimpleTimeZone(0, "GMT")); - } - - // Used as default activityCode. From FacebookSdk.java. - public static final int DEFAULT_AUTH_ACTIVITY_CODE = 0xface; - private static final String KEY_USER_ID = "id"; private static final String KEY_ACCESS_TOKEN = "access_token"; private static final String KEY_EXPIRATION_DATE = "expiration_date"; private static final String KEY_REFRESH_DATE = "last_refresh_date"; private static final String KEY_PERMISSIONS = "permissions"; - // Mirrors com.facebook.internal.LoginAuthorizationType.java - public enum LoginAuthorizationType { - READ, PUBLISH + static { + PRECISE_DATE_FORMAT.setTimeZone(new SimpleTimeZone(0, "GMT")); + IMPRECISE_DATE_FORMAT.setTimeZone(new SimpleTimeZone(0, "GMT")); } private final FacebookSdkDelegate facebookSdkDelegate; - private CallbackManager callbackManager; FacebookController(FacebookSdkDelegate facebookSdkDelegate) { @@ -212,7 +203,7 @@ public void setAuthData(Map authData) String permissionsCommaDelineated = authData.get(KEY_PERMISSIONS); Set permissions = null; if (permissionsCommaDelineated != null && !permissionsCommaDelineated.isEmpty()) { - String permissionsArray[] = permissionsCommaDelineated.split(","); + String[] permissionsArray = permissionsCommaDelineated.split(","); permissions = new HashSet<>(Arrays.asList(permissionsArray)); } @@ -229,20 +220,6 @@ public void setAuthData(Map authData) facebookSdkDelegate.setCurrentAccessToken(accessToken); } - /* package */ interface FacebookSdkDelegate { - void initialize(Context context, int callbackRequestCodeOffset); - - String getApplicationId(); - - AccessToken getCurrentAccessToken(); - - void setCurrentAccessToken(AccessToken token); - - CallbackManager createCallbackManager(); - - LoginManager getLoginManager(); - } - /** * Convert String representation of a date into Date object. *

@@ -262,6 +239,25 @@ private Date parseDateString(String source) throws java.text.ParseException { } } + // Mirrors com.facebook.internal.LoginAuthorizationType.java + public enum LoginAuthorizationType { + READ, PUBLISH + } + + /* package */ interface FacebookSdkDelegate { + void initialize(Context context, int callbackRequestCodeOffset); + + String getApplicationId(); + + AccessToken getCurrentAccessToken(); + + void setCurrentAccessToken(AccessToken token); + + CallbackManager createCallbackManager(); + + LoginManager getLoginManager(); + } + private static class FacebookSdkDelegateImpl implements FacebookSdkDelegate { @Override public void initialize(Context context, int callbackRequestCodeOffset) { diff --git a/facebook/src/main/java/com/parse/facebook/ParseFacebookUtils.java b/facebook/src/main/java/com/parse/facebook/ParseFacebookUtils.java index 354714545..fd152d4a7 100644 --- a/facebook/src/main/java/com/parse/facebook/ParseFacebookUtils.java +++ b/facebook/src/main/java/com/parse/facebook/ParseFacebookUtils.java @@ -20,14 +20,13 @@ import com.parse.ParseException; import com.parse.ParseUser; import com.parse.SaveCallback; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; import java.util.Collection; import java.util.Collections; import java.util.Map; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * Provides a set of utilities for using Parse with Facebook. *

@@ -80,6 +79,10 @@ public final class ParseFacebookUtils { static FacebookController controller; static ParseUserDelegate userDelegate = new ParseUserDelegateImpl(); + private ParseFacebookUtils() { + // do nothing + } + /** * @param user A {@link com.parse.ParseUser} object. * @return {@code true} if the user is linked to a Facebook account. @@ -113,15 +116,12 @@ public static void initialize(Context context) { public static void initialize(Context context, int callbackRequestCodeOffset) { synchronized (lock) { getController().initialize(context, callbackRequestCodeOffset); - userDelegate.registerAuthenticationCallback(AUTH_TYPE, new AuthenticationCallback() { - @Override - public boolean onRestore(Map authData) { - try { - getController().setAuthData(authData); - return true; - } catch (Exception e) { - return false; - } + userDelegate.registerAuthenticationCallback(AUTH_TYPE, authData -> { + try { + getController().setAuthData(authData); + return true; + } catch (Exception e) { + return false; } }); isInitialized = true; @@ -146,6 +146,8 @@ private static FacebookController getController() { } } + //region Log In + /** * The method that should be called from the Activity's or Fragment's onActivityResult method. * @@ -163,8 +165,6 @@ public static boolean onActivityResult(int requestCode, int resultCode, Intent d } } - //region Log In - /** * Log in using a Facebook account using authorization credentials that have already been * obtained. @@ -293,6 +293,10 @@ public static Task logInWithPublishPermissionsInBackground(Fragment f logInWithPublishPermissionsInBackground(fragment, permissions), callback, true); } + //endregion + + //region Link + private static Task logInAsync(Activity activity, Fragment fragment, Collection permissions, FacebookController.LoginAuthorizationType authorizationType) { checkInitialization(); @@ -301,18 +305,9 @@ private static Task logInAsync(Activity activity, Fragment fragment, } return getController().authenticateAsync( - activity, fragment, authorizationType, permissions).onSuccessTask(new Continuation, Task>() { - @Override - public Task then(Task> task) throws Exception { - return userDelegate.logInWithInBackground(AUTH_TYPE, task.getResult()); - } - }); + activity, fragment, authorizationType, permissions).onSuccessTask(task -> userDelegate.logInWithInBackground(AUTH_TYPE, task.getResult())); } - //endregion - - //region Link - /** * Link an existing Parse user with a Facebook account using authorization credentials that have * already been obtained. @@ -452,6 +447,10 @@ public static Task linkWithPublishPermissionsInBackground(ParseUser user, linkWithPublishPermissionsInBackground(user, fragment, permissions), callback, true); } + //endregion + + //region Unlink + private static Task linkAsync(final ParseUser user, Activity activity, Fragment fragment, Collection permissions, FacebookController.LoginAuthorizationType authorizationType) { checkInitialization(); @@ -460,18 +459,9 @@ private static Task linkAsync(final ParseUser user, Activity activity, Fra } return getController().authenticateAsync( - activity, fragment, authorizationType, permissions).onSuccessTask(new Continuation, Task>() { - @Override - public Task then(Task> task) throws Exception { - return user.linkWithInBackground(AUTH_TYPE, task.getResult()); - } - }); + activity, fragment, authorizationType, permissions).onSuccessTask(task -> user.linkWithInBackground(AUTH_TYPE, task.getResult())); } - //endregion - - //region Unlink - /** * Unlink a user from a Facebook account. This will save the user's data. * @@ -483,6 +473,10 @@ public static Task unlinkInBackground(ParseUser user) { return user.unlinkFromInBackground(AUTH_TYPE); } + //endregion + + //region TaskUtils + /** * Unlink a user from a Facebook account. This will save the user's data. * @@ -494,10 +488,6 @@ public static Task unlinkInBackground(ParseUser user, SaveCallback callbac return callbackOnMainThreadAsync(unlinkInBackground(user), callback, false); } - //endregion - - //region TaskUtils - /** * Calls the callback after a task completes on the main thread, returning a Task that completes * with the same result as the input task after the callback has been run. @@ -516,6 +506,8 @@ private static Task callbackOnMainThreadAsync( return callbackOnMainThreadInternalAsync(task, callback, reportCancellation); } + //endregion + /** * Calls the callback after a task completes on the main thread, returning a Task that completes * with the same result as the input task after the callback has been run. If reportCancellation @@ -527,50 +519,38 @@ private static Task callbackOnMainThreadInternalAsync( return task; } final Task.TaskCompletionSource tcs = Task.create(); - task.continueWith(new Continuation() { - @Override - public Void then(final Task task) throws Exception { - if (task.isCancelled() && !reportCancellation) { - tcs.setCancelled(); - return null; - } - Task.UI_THREAD_EXECUTOR.execute(new Runnable() { - @Override - public void run() { - try { - Exception error = task.getError(); - if (error != null && !(error instanceof ParseException)) { - error = new ParseException(error); - } - if (callback instanceof SaveCallback) { - ((SaveCallback) callback).done((ParseException) error); - } else if (callback instanceof LogInCallback) { - ((LogInCallback) callback).done( - (ParseUser) task.getResult(), (ParseException) error); - } - } finally { - if (task.isCancelled()) { - tcs.setCancelled(); - } else if (task.isFaulted()) { - tcs.setError(task.getError()); - } else { - tcs.setResult(task.getResult()); - } - } - } - }); + task.continueWith((Continuation) task1 -> { + if (task1.isCancelled() && !reportCancellation) { + tcs.setCancelled(); return null; } + Task.UI_THREAD_EXECUTOR.execute(() -> { + try { + Exception error = task1.getError(); + if (error != null && !(error instanceof ParseException)) { + error = new ParseException(error); + } + if (callback instanceof SaveCallback) { + ((SaveCallback) callback).done((ParseException) error); + } else if (callback instanceof LogInCallback) { + ((LogInCallback) callback).done( + (ParseUser) task1.getResult(), (ParseException) error); + } + } finally { + if (task1.isCancelled()) { + tcs.setCancelled(); + } else if (task1.isFaulted()) { + tcs.setError(task1.getError()); + } else { + tcs.setResult(task1.getResult()); + } + } + }); + return null; }); return tcs.getTask(); } - //endregion - - private ParseFacebookUtils() { - // do nothing - } - interface ParseUserDelegate { void registerAuthenticationCallback(String authType, AuthenticationCallback callback); diff --git a/facebook/src/test/java/com/parse/facebook/FacebookControllerTest.java b/facebook/src/test/java/com/parse/facebook/FacebookControllerTest.java index 5abcf5e34..520e14eda 100644 --- a/facebook/src/test/java/com/parse/facebook/FacebookControllerTest.java +++ b/facebook/src/test/java/com/parse/facebook/FacebookControllerTest.java @@ -8,6 +8,17 @@ */ package com.parse.facebook; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import android.app.Activity; import android.content.Context; @@ -20,6 +31,7 @@ import com.facebook.FacebookException; import com.facebook.login.LoginManager; import com.facebook.login.LoginResult; +import com.parse.boltsinternal.Task; import org.junit.After; import org.junit.Before; @@ -41,20 +53,7 @@ import java.util.Set; import java.util.TimeZone; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -@Config(manifest=Config.NONE) +@Config(manifest = Config.NONE) @RunWith(RobolectricTestRunner.class) public class FacebookControllerTest { @@ -92,7 +91,7 @@ public void testGetAuthData() { FacebookController controller = new FacebookController(null); Calendar calendar = new GregorianCalendar(2015, 6, 3); - Set permissions = new HashSet(); + Set permissions = new HashSet<>(); permissions.add("user_friends"); permissions.add("profile"); diff --git a/facebook/src/test/java/com/parse/facebook/ParseFacebookUtilsTest.java b/facebook/src/test/java/com/parse/facebook/ParseFacebookUtilsTest.java index 058adc7d9..b11217cf1 100644 --- a/facebook/src/test/java/com/parse/facebook/ParseFacebookUtilsTest.java +++ b/facebook/src/test/java/com/parse/facebook/ParseFacebookUtilsTest.java @@ -8,6 +8,23 @@ */ package com.parse.facebook; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -17,6 +34,7 @@ import com.facebook.AccessToken; import com.parse.AuthenticationCallback; import com.parse.ParseUser; +import com.parse.boltsinternal.Task; import org.junit.After; import org.junit.Before; @@ -33,24 +51,7 @@ import java.util.LinkedList; import java.util.Map; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyListOf; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@Config(manifest=Config.NONE) +@Config(manifest = Config.NONE) @RunWith(RobolectricTestRunner.class) public class ParseFacebookUtilsTest { @@ -179,7 +180,7 @@ public void testLogInWithActivityAndReadPermissions() { doLogInWith( mock(Activity.class), null, - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.READ); } @@ -188,7 +189,7 @@ public void testLogInWithFragmentAndReadPermissions() { doLogInWith( null, mock(Fragment.class), - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.READ); } @@ -197,7 +198,7 @@ public void testLogInWithActivityAndPublishPermissions() { doLogInWith( mock(Activity.class), null, - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.PUBLISH); } @@ -206,7 +207,7 @@ public void testLogInWithFragmentAndPublishPermissions() { doLogInWith( null, mock(Fragment.class), - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.PUBLISH); } @@ -220,10 +221,10 @@ private void doLogInWith( Map authData = new HashMap<>(); when(controller.authenticateAsync( - any(Activity.class), - any(Fragment.class), + nullable(Activity.class), + nullable(Fragment.class), any(FacebookController.LoginAuthorizationType.class), - anyListOf(String.class))).thenReturn(Task.forResult(authData)); + anyList())).thenReturn(Task.forResult(authData)); ParseFacebookUtils.isInitialized = true; ParseUser user = mock(ParseUser.class); @@ -261,7 +262,7 @@ public void testLinkWithAccessToken() { ParseUser user = mock(ParseUser.class); when(user.linkWithInBackground(anyString(), anyMapOf(String.class, String.class))) - .thenReturn(Task.forResult(null)); + .thenReturn(Task.forResult(null)); AccessToken token = TestUtils.newAccessToken(); Task task = ParseFacebookUtils.linkInBackground(user, token); verify(controller).getAuthData(token); @@ -274,7 +275,7 @@ public void testLinkWithActivityAndReadPermissions() { doLinkWith( mock(Activity.class), null, - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.READ); } @@ -283,7 +284,7 @@ public void testLinkWithFragmentAndReadPermissions() { doLinkWith( null, mock(Fragment.class), - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.READ); } @@ -292,7 +293,7 @@ public void testLinkWithActivityAndPublishPermissions() { doLinkWith( mock(Activity.class), null, - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.PUBLISH); } @@ -301,7 +302,7 @@ public void testLinkWithFragmentAndPublishPermissions() { doLinkWith( null, mock(Fragment.class), - new LinkedList(), + new LinkedList<>(), FacebookController.LoginAuthorizationType.PUBLISH); } @@ -315,15 +316,15 @@ private void doLinkWith( Map authData = new HashMap<>(); when(controller.authenticateAsync( - any(Activity.class), - any(Fragment.class), + nullable(Activity.class), + nullable(Fragment.class), any(FacebookController.LoginAuthorizationType.class), - anyListOf(String.class))).thenReturn(Task.forResult(authData)); + anyList())).thenReturn(Task.forResult(authData)); ParseFacebookUtils.isInitialized = true; ParseUser user = mock(ParseUser.class); - when(user.linkWithInBackground(anyString(), anyMapOf(String.class, String.class))) - .thenReturn(Task.forResult(null)); + when(user.linkWithInBackground(anyString(), anyMap())) + .thenReturn(Task.forResult(null)); Task task; if (FacebookController.LoginAuthorizationType.PUBLISH.equals(type)) { if (activity != null) { @@ -350,7 +351,7 @@ private void doLinkWith( @Test public void testUnlinkInBackground() { ParseUser user = mock(ParseUser.class); - when(user.unlinkFromInBackground(anyString())).thenReturn(Task.forResult(null)); + when(user.unlinkFromInBackground(anyString())).thenReturn(Task.forResult(null)); ParseFacebookUtils.isInitialized = true; ParseFacebookUtils.unlinkInBackground(user); diff --git a/fcm/build.gradle b/fcm/build.gradle index 48b8ff812..a7f084ee6 100644 --- a/fcm/build.gradle +++ b/fcm/build.gradle @@ -1,4 +1,6 @@ apply plugin: "com.android.library" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -25,11 +27,14 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + } dependencies { - api "com.google.firebase:firebase-messaging:20.1.5" + api "com.google.firebase:firebase-messaging:22.0.0" implementation project(":parse") -} - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" +} \ No newline at end of file diff --git a/fcm/src/main/AndroidManifest.xml b/fcm/src/main/AndroidManifest.xml index cbc863652..2edc06cc3 100644 --- a/fcm/src/main/AndroidManifest.xml +++ b/fcm/src/main/AndroidManifest.xml @@ -1 +1 @@ - + diff --git a/fcm/src/main/java/com/parse/fcm/ParseFCM.java b/fcm/src/main/java/com/parse/fcm/ParseFCM.java index 5efd90bad..47ad16b49 100644 --- a/fcm/src/main/java/com/parse/fcm/ParseFCM.java +++ b/fcm/src/main/java/com/parse/fcm/ParseFCM.java @@ -9,9 +9,7 @@ package com.parse.fcm; import com.parse.PLog; -import com.parse.ParseException; import com.parse.ParseInstallation; -import com.parse.SaveCallback; public class ParseFCM { @@ -32,14 +30,11 @@ public static void register(String token) { installation.setDeviceToken(token); //even though this is FCM, calling it gcm will work on the backend installation.setPushType(PUSH_TYPE); - installation.saveInBackground(new SaveCallback() { - @Override - public void done(ParseException e) { - if (e == null) { - PLog.d(ParseFCM.TAG, "FCM token saved to installation"); - } else { - PLog.e(ParseFCM.TAG, "FCM token upload failed", e); - } + installation.saveInBackground(e -> { + if (e == null) { + PLog.d(ParseFCM.TAG, "FCM token saved to installation"); + } else { + PLog.e(ParseFCM.TAG, "FCM token upload failed", e); } }); } diff --git a/fcm/src/main/java/com/parse/fcm/ParseFirebaseMessagingService.java b/fcm/src/main/java/com/parse/fcm/ParseFirebaseMessagingService.java index 31a74e5e0..82b7bf14a 100644 --- a/fcm/src/main/java/com/parse/fcm/ParseFirebaseMessagingService.java +++ b/fcm/src/main/java/com/parse/fcm/ParseFirebaseMessagingService.java @@ -1,5 +1,7 @@ package com.parse.fcm; +import androidx.annotation.NonNull; + import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; import com.parse.PLog; @@ -11,13 +13,13 @@ public class ParseFirebaseMessagingService extends FirebaseMessagingService { @Override - public void onNewToken(String token) { + public void onNewToken(@NonNull String token) { super.onNewToken(token); ParseFCM.register(token); } @Override - public void onMessageReceived(RemoteMessage remoteMessage) { + public void onMessageReceived(@NonNull RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); PLog.d(ParseFCM.TAG, "onMessageReceived"); diff --git a/gcm/build.gradle b/gcm/build.gradle index 4da70e8f2..791e2c902 100644 --- a/gcm/build.gradle +++ b/gcm/build.gradle @@ -1,4 +1,6 @@ apply plugin: "com.android.library" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -28,13 +30,16 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + } dependencies { // last version for GCM to be supported - api "com.google.android.gms:play-services-gcm:12.0.1" + api "com.google.android.gms:play-services-gcm:17.0.0" api "com.firebase:firebase-jobdispatcher:0.8.6" implementation project(":parse") -} - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" +} \ No newline at end of file diff --git a/gcm/src/main/java/com/parse/gcm/ParseGCM.java b/gcm/src/main/java/com/parse/gcm/ParseGCM.java index 699e5015c..7009bc496 100644 --- a/gcm/src/main/java/com/parse/gcm/ParseGCM.java +++ b/gcm/src/main/java/com/parse/gcm/ParseGCM.java @@ -10,6 +10,7 @@ import android.content.Context; import android.os.Bundle; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -31,7 +32,7 @@ public class ParseGCM { /** * Register your app to start receiving GCM pushes * - * @param context context + * @param context context */ public static void register(@NonNull Context context) { //kicks off the background job diff --git a/gcm/src/main/java/com/parse/gcm/ParseGCMJobService.java b/gcm/src/main/java/com/parse/gcm/ParseGCMJobService.java index 113d935f7..8c5c2e058 100644 --- a/gcm/src/main/java/com/parse/gcm/ParseGCMJobService.java +++ b/gcm/src/main/java/com/parse/gcm/ParseGCMJobService.java @@ -20,11 +20,10 @@ import com.google.android.gms.iid.InstanceID; import com.parse.PLog; import com.parse.ParseInstallation; +import com.parse.boltsinternal.Task; import java.util.concurrent.Callable; -import com.parse.boltsinternal.Task; - /** * Handles saving the GCM token to the Parse Installation */ @@ -56,26 +55,23 @@ static Job createJob(FirebaseJobDispatcher dispatcher, String gcmSenderId) { public boolean onStartJob(final JobParameters job) { PLog.d(ParseGCM.TAG, "Updating GCM token"); - Task.callInBackground(new Callable() { - @Override - public Void call() { - try { - InstanceID instanceID = InstanceID.getInstance(getApplicationContext()); - String senderId = job.getExtras().getString(KEY_GCM_SENDER_ID); - String token = instanceID.getToken(senderId, - GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); - ParseInstallation installation = ParseInstallation.getCurrentInstallation(); - installation.setDeviceToken(token); - //even though this is FCM, calling it gcm will work on the backend - installation.setPushType(PUSH_TYPE); - installation.save(); - PLog.d(ParseGCM.TAG, "GCM registration success"); - } catch (Exception e) { - PLog.e(ParseGCM.TAG, "GCM registration failed", e); - jobFinished(job, true); - } - return null; + Task.callInBackground((Callable) () -> { + try { + InstanceID instanceID = InstanceID.getInstance(getApplicationContext()); + String senderId = job.getExtras().getString(KEY_GCM_SENDER_ID); + String token = instanceID.getToken(senderId, + GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); + ParseInstallation installation = ParseInstallation.getCurrentInstallation(); + installation.setDeviceToken(token); + //even though this is FCM, calling it gcm will work on the backend + installation.setPushType(PUSH_TYPE); + installation.save(); + PLog.d(ParseGCM.TAG, "GCM registration success"); + } catch (Exception e) { + PLog.e(ParseGCM.TAG, "GCM registration failed", e); + jobFinished(job, true); } + return null; }); return true; // Answers the question: "Is there still work going on?" } diff --git a/google/build.gradle b/google/build.gradle index 32a100232..4971ca310 100644 --- a/google/build.gradle +++ b/google/build.gradle @@ -1,5 +1,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -18,12 +20,19 @@ android { lintOptions { abortOnError false } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { - api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - api "com.google.android.gms:play-services-auth:18.0.0" + api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" + api "com.google.android.gms:play-services-auth:19.2.0" implementation project(":parse") -} - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" +} \ No newline at end of file diff --git a/google/src/main/java/com/parse/google/ParseGoogleUtils.kt b/google/src/main/java/com/parse/google/ParseGoogleUtils.kt index fde0bf3a6..69c5b89af 100644 --- a/google/src/main/java/com/parse/google/ParseGoogleUtils.kt +++ b/google/src/main/java/com/parse/google/ParseGoogleUtils.kt @@ -3,8 +3,6 @@ package com.parse.google import android.app.Activity import android.content.Context import android.content.Intent -import com.parse.boltsinternal.Continuation -import com.parse.boltsinternal.Task import com.google.android.gms.auth.api.signin.GoogleSignIn import com.google.android.gms.auth.api.signin.GoogleSignInAccount import com.google.android.gms.auth.api.signin.GoogleSignInClient @@ -13,6 +11,8 @@ import com.parse.LogInCallback import com.parse.ParseException import com.parse.ParseUser import com.parse.SaveCallback +import com.parse.boltsinternal.Continuation +import com.parse.boltsinternal.Task /** * Provides a set of utilities for using Parse with Google. @@ -67,7 +67,10 @@ object ParseGoogleUtils { this.currentCallback = callback val googleSignInClient = buildGoogleSignInClient(activity) this.googleSignInClient = googleSignInClient - activity.startActivityForResult(googleSignInClient.signInIntent, REQUEST_CODE_GOOGLE_SIGN_IN) + activity.startActivityForResult( + googleSignInClient.signInIntent, + REQUEST_CODE_GOOGLE_SIGN_IN + ) } /** @@ -138,32 +141,32 @@ object ParseGoogleUtils { private fun handleSignInResult(result: Intent) { GoogleSignIn.getSignedInAccountFromIntent(result) - .addOnSuccessListener { googleAccount -> - onSignedIn(googleAccount) - } - .addOnFailureListener { exception -> - onSignInCallbackResult(null, exception) - } + .addOnSuccessListener { googleAccount -> + onSignedIn(googleAccount) + } + .addOnFailureListener { exception -> + onSignInCallbackResult(null, exception) + } } private fun onSignedIn(account: GoogleSignInAccount) { googleSignInClient?.signOut()?.addOnCompleteListener {} val authData: Map = getAuthData(account) ParseUser.logInWithInBackground(AUTH_TYPE, authData) - .continueWith { task -> - when { - task.isCompleted -> { - val user = task.result - onSignInCallbackResult(user, null) - } - task.isFaulted -> { - onSignInCallbackResult(null, task.error) - } - else -> { - onSignInCallbackResult(null, null) - } + .continueWith { task -> + when { + task.isCompleted -> { + val user = task.result + onSignInCallbackResult(user, null) + } + task.isFaulted -> { + onSignInCallbackResult(null, task.error) + } + else -> { + onSignInCallbackResult(null, null) } } + } } private fun getAuthData(account: GoogleSignInAccount): Map { @@ -186,10 +189,10 @@ object ParseGoogleUtils { private fun buildGoogleSignInClient(context: Context): GoogleSignInClient { val signInOptions = GoogleSignInOptions.Builder() - .requestId() - .requestEmail() - .requestIdToken(clientId) - .build() + .requestId() + .requestEmail() + .requestIdToken(clientId) + .build() return GoogleSignIn.getClient(context, signInOptions) } @@ -198,7 +201,8 @@ object ParseGoogleUtils { * with the same result as the input task after the callback has been run. */ private fun callbackOnMainThreadAsync( - task: Task, callback: SaveCallback, reportCancellation: Boolean): Task { + task: Task, callback: SaveCallback, reportCancellation: Boolean + ): Task { return callbackOnMainThreadInternalAsync(task, callback, reportCancellation) } @@ -208,7 +212,8 @@ object ParseGoogleUtils { * is false, the callback will not be called if the task was cancelled. */ private fun callbackOnMainThreadInternalAsync( - task: Task, callback: Any?, reportCancellation: Boolean): Task { + task: Task, callback: Any?, reportCancellation: Boolean + ): Task { if (callback == null) { return task } @@ -228,7 +233,8 @@ object ParseGoogleUtils { callback.done(error as? ParseException) } else if (callback is LogInCallback) { callback.done( - task.result as? ParseUser, error as? ParseException) + task.result as? ParseUser, error as? ParseException + ) } } finally { when { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0ebb3108e..68ca99ac4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip diff --git a/ktx/build.gradle b/ktx/build.gradle index b60b1fcd1..a07891442 100644 --- a/ktx/build.gradle +++ b/ktx/build.gradle @@ -1,6 +1,7 @@ apply plugin: "com.android.library" - apply plugin: "kotlin-android" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -30,11 +31,17 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { - api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation project(":parse") -} - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" +} \ No newline at end of file diff --git a/ktx/src/main/java/com/parse/ktx/ParseQuery.kt b/ktx/src/main/java/com/parse/ktx/ParseQuery.kt index 410586838..7aa989f42 100644 --- a/ktx/src/main/java/com/parse/ktx/ParseQuery.kt +++ b/ktx/src/main/java/com/parse/ktx/ParseQuery.kt @@ -2,11 +2,7 @@ package com.parse.ktx -import com.parse.ParseException -import com.parse.ParseGeoPoint -import com.parse.ParseObject -import com.parse.ParsePolygon -import com.parse.ParseQuery +import com.parse.* import kotlin.reflect.KProperty /** @@ -15,7 +11,7 @@ import kotlin.reflect.KProperty * Note that this will modify the current limit of the query */ @Throws(ParseException::class) -inline fun ParseQuery.findAll(): List { +inline fun ParseQuery.findAll(): List { limit = ParseQuery.MAX_LIMIT val list = mutableListOf() try { @@ -29,7 +25,7 @@ inline fun ParseQuery.findAll(): List { } } return list - } catch (ex : ParseException) { + } catch (ex: ParseException) { if (ex.code == ParseException.OBJECT_NOT_FOUND) { return list } @@ -75,28 +71,40 @@ fun ParseQuery.selectKeys(keys: Collection> /** * @see ParseQuery.whereContainedIn */ -inline fun ParseQuery.whereContainedIn(key: KProperty, values: Collection): ParseQuery { +inline fun ParseQuery.whereContainedIn( + key: KProperty, + values: Collection +): ParseQuery { return whereContainedIn(key.name, values) } /** * @see ParseQuery.whereContains */ -inline fun ParseQuery.whereContains(key: KProperty, substring: String): ParseQuery { +inline fun ParseQuery.whereContains( + key: KProperty, + substring: String +): ParseQuery { return whereContains(key.name, substring) } /** * @see ParseQuery.whereContainsAll */ -inline fun ParseQuery.whereContainsAll(key: KProperty, values: Collection): ParseQuery { +inline fun ParseQuery.whereContainsAll( + key: KProperty, + values: Collection +): ParseQuery { return whereContainsAll(key.name, values) } /** * @see ParseQuery.whereContainsAllStartsWith */ -inline fun ParseQuery.whereContainsAllStartsWith(key: KProperty, values: Collection): ParseQuery { +inline fun ParseQuery.whereContainsAllStartsWith( + key: KProperty, + values: Collection +): ParseQuery { return whereContainsAllStartsWith(key.name, values) } @@ -110,28 +118,41 @@ inline fun ParseQuery.whereDoesNotExist(key: KProperty ParseQuery.whereDoesNotMatchKeyInQuery(key: KProperty, keyInQuery: KProperty, query: ParseQuery): ParseQuery { +inline fun ParseQuery.whereDoesNotMatchKeyInQuery( + key: KProperty, + keyInQuery: KProperty, + query: ParseQuery +): ParseQuery { return whereDoesNotMatchKeyInQuery(key.name, keyInQuery.name, query) } /** * @see ParseQuery.whereDoesNotMatchQuery */ -inline fun ParseQuery.whereDoesNotMatchQuery(key: KProperty, query: ParseQuery): ParseQuery { +inline fun ParseQuery.whereDoesNotMatchQuery( + key: KProperty, + query: ParseQuery +): ParseQuery { return whereDoesNotMatchQuery(key.name, query) } /** * @see ParseQuery.whereEndsWith */ -inline fun ParseQuery.whereEndsWith(key: KProperty, suffix: String): ParseQuery { +inline fun ParseQuery.whereEndsWith( + key: KProperty, + suffix: String +): ParseQuery { return whereEndsWith(key.name, suffix) } /** * @see ParseQuery.whereEqualTo */ -inline fun ParseQuery.whereEqualTo(key: KProperty, value: Any?): ParseQuery { +inline fun ParseQuery.whereEqualTo( + key: KProperty, + value: Any? +): ParseQuery { return whereEqualTo(key.name, value) } @@ -145,139 +166,205 @@ inline fun ParseQuery.whereExists(key: KProperty): Pa /** * @see ParseQuery.whereFullText */ -inline fun ParseQuery.whereFullText(key: KProperty, text: String): ParseQuery { +inline fun ParseQuery.whereFullText( + key: KProperty, + text: String +): ParseQuery { return whereFullText(key.name, text) } /** * @see ParseQuery.whereGreaterThan */ -inline fun ParseQuery.whereGreaterThan(key: KProperty, value: Any): ParseQuery { +inline fun ParseQuery.whereGreaterThan( + key: KProperty, + value: Any +): ParseQuery { return whereGreaterThan(key.name, value) } /** * @see ParseQuery.whereGreaterThanOrEqualTo */ -inline fun ParseQuery.whereGreaterThanOrEqualTo(key: KProperty, value: Any): ParseQuery { +inline fun ParseQuery.whereGreaterThanOrEqualTo( + key: KProperty, + value: Any +): ParseQuery { return whereGreaterThanOrEqualTo(key.name, value) } /** * @see ParseQuery.whereLessThan */ -inline fun ParseQuery.whereLessThan(key: KProperty, value: Any): ParseQuery { +inline fun ParseQuery.whereLessThan( + key: KProperty, + value: Any +): ParseQuery { return whereLessThan(key.name, value) } /** * @see ParseQuery.whereLessThanOrEqualTo */ -inline fun ParseQuery.whereLessThanOrEqualTo(key: KProperty, value: Any): ParseQuery { +inline fun ParseQuery.whereLessThanOrEqualTo( + key: KProperty, + value: Any +): ParseQuery { return whereLessThanOrEqualTo(key.name, value) } /** * @see ParseQuery.whereMatches */ -inline fun ParseQuery.whereMatches(key: KProperty, regex: String): ParseQuery { +inline fun ParseQuery.whereMatches( + key: KProperty, + regex: String +): ParseQuery { return whereMatches(key.name, regex) } /** * @see ParseQuery.whereMatches */ -inline fun ParseQuery.whereMatches(key: KProperty, regex: String, modifiers: String): ParseQuery { +inline fun ParseQuery.whereMatches( + key: KProperty, + regex: String, + modifiers: String +): ParseQuery { return whereMatches(key.name, regex, modifiers) } /** * @see ParseQuery.whereMatchesKeyInQuery */ -inline fun ParseQuery.whereMatchesKeyInQuery(key: KProperty, keyInQuery: KProperty, query: ParseQuery): ParseQuery { +inline fun ParseQuery.whereMatchesKeyInQuery( + key: KProperty, + keyInQuery: KProperty, + query: ParseQuery +): ParseQuery { return whereMatchesKeyInQuery(key.name, keyInQuery.name, query) } /** * @see ParseQuery.whereMatchesQuery */ -inline fun ParseQuery.whereMatchesQuery(key: KProperty, query: ParseQuery): ParseQuery { +inline fun ParseQuery.whereMatchesQuery( + key: KProperty, + query: ParseQuery +): ParseQuery { return whereMatchesQuery(key.name, query) } /** * @see ParseQuery.whereNear */ -inline fun ParseQuery.whereNear(key: KProperty, point: ParseGeoPoint): ParseQuery { +inline fun ParseQuery.whereNear( + key: KProperty, + point: ParseGeoPoint +): ParseQuery { return whereNear(key.name, point) } /** * @see ParseQuery.whereNotContainedIn */ -inline fun ParseQuery.whereNotContainedIn(key: KProperty, values: Collection): ParseQuery { +inline fun ParseQuery.whereNotContainedIn( + key: KProperty, + values: Collection +): ParseQuery { return whereNotContainedIn(key.name, values) } /** * @see ParseQuery.whereNotEqualTo */ -inline fun ParseQuery.whereNotEqualTo(key: KProperty, value: Any?): ParseQuery { +inline fun ParseQuery.whereNotEqualTo( + key: KProperty, + value: Any? +): ParseQuery { return whereNotEqualTo(key.name, value) } /** * @see ParseQuery.wherePolygonContains */ -inline fun ParseQuery.wherePolygonContains(key: KProperty, point: ParseGeoPoint): ParseQuery { +inline fun ParseQuery.wherePolygonContains( + key: KProperty, + point: ParseGeoPoint +): ParseQuery { return wherePolygonContains(key.name, point) } /** * @see ParseQuery.whereStartsWith */ -inline fun ParseQuery.whereStartsWith(key: KProperty, prefix: String): ParseQuery { +inline fun ParseQuery.whereStartsWith( + key: KProperty, + prefix: String +): ParseQuery { return whereStartsWith(key.name, prefix) } /** * @see ParseQuery.whereWithinGeoBox */ -inline fun ParseQuery.whereWithinGeoBox(key: KProperty, southwest: ParseGeoPoint, northeast: ParseGeoPoint): ParseQuery { +inline fun ParseQuery.whereWithinGeoBox( + key: KProperty, + southwest: ParseGeoPoint, + northeast: ParseGeoPoint +): ParseQuery { return whereWithinGeoBox(key.name, southwest, northeast) } /** * @see ParseQuery.whereWithinKilometers */ -inline fun ParseQuery.whereWithinKilometers(key: KProperty, point: ParseGeoPoint, maxDistance: Double): ParseQuery { +inline fun ParseQuery.whereWithinKilometers( + key: KProperty, + point: ParseGeoPoint, + maxDistance: Double +): ParseQuery { return whereWithinKilometers(key.name, point, maxDistance) } /** * @see ParseQuery.whereWithinMiles */ -inline fun ParseQuery.whereWithinMiles(key: KProperty, point: ParseGeoPoint, maxDistance: Double): ParseQuery { +inline fun ParseQuery.whereWithinMiles( + key: KProperty, + point: ParseGeoPoint, + maxDistance: Double +): ParseQuery { return whereWithinMiles(key.name, point, maxDistance) } /** * @see ParseQuery.whereWithinPolygon */ -inline fun ParseQuery.whereWithinPolygon(key: KProperty, points: List): ParseQuery { +inline fun ParseQuery.whereWithinPolygon( + key: KProperty, + points: List +): ParseQuery { return whereWithinPolygon(key.name, points) } /** * @see ParseQuery.whereWithinPolygon */ -inline fun ParseQuery.whereWithinPolygon(key: KProperty, polygon: ParsePolygon): ParseQuery { +inline fun ParseQuery.whereWithinPolygon( + key: KProperty, + polygon: ParsePolygon +): ParseQuery { return whereWithinPolygon(key.name, polygon) } /** * @see ParseQuery.whereWithinRadians */ -inline fun ParseQuery.whereWithinRadians(key: KProperty, point: ParseGeoPoint, maxDistance: Double): ParseQuery { +inline fun ParseQuery.whereWithinRadians( + key: KProperty, + point: ParseGeoPoint, + maxDistance: Double +): ParseQuery { return whereWithinRadians(key.name, point, maxDistance) } diff --git a/ktx/src/main/java/com/parse/ktx/delegates/BytesParseDelegate.kt b/ktx/src/main/java/com/parse/ktx/delegates/BytesParseDelegate.kt index d611980d9..c28a46502 100644 --- a/ktx/src/main/java/com/parse/ktx/delegates/BytesParseDelegate.kt +++ b/ktx/src/main/java/com/parse/ktx/delegates/BytesParseDelegate.kt @@ -16,7 +16,7 @@ class BytesParseDelegate(private val name: String?) { } operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: ByteArray?) { - parseObject.putOrIgnore(name ?:property.name, value) + parseObject.putOrIgnore(name ?: property.name, value) } } diff --git a/ktx/src/main/java/com/parse/ktx/delegates/EnumParseDelegate.kt b/ktx/src/main/java/com/parse/ktx/delegates/EnumParseDelegate.kt index 44a17f159..ecc3acc2b 100644 --- a/ktx/src/main/java/com/parse/ktx/delegates/EnumParseDelegate.kt +++ b/ktx/src/main/java/com/parse/ktx/delegates/EnumParseDelegate.kt @@ -12,21 +12,24 @@ import kotlin.reflect.KProperty * convert again to upper case to find correspondent local enum. */ class EnumParseDelegate>( - private val name: String?, - private val default: T?, - private val enumClass: Class + private val name: String?, + private val default: T?, + private val enumClass: Class ) { operator fun getValue(parseObject: ParseObject, property: KProperty<*>): T { return try { - java.lang.Enum.valueOf(enumClass, parseObject.getString(name ?: property.name)!!.toUpperCase()) + java.lang.Enum.valueOf( + enumClass, + parseObject.getString(name ?: property.name)!!.uppercase() + ) } catch (e: Exception) { default ?: throw e } } operator fun setValue(parseObject: ParseObject, property: KProperty<*>, t: T) { - parseObject.put(name ?: property.name, t.name.toLowerCase()) + parseObject.put(name ?: property.name, t.name.lowercase()) } } @@ -35,10 +38,12 @@ class EnumParseDelegate>( * Returns a [Enum] property delegate for [ParseObject]s. This uses custom implementation for get * to retrieve a local version of the your enum and [ParseObject.put]. */ -inline fun > enumAttribute(default: T? = null) = EnumParseDelegate(null, default, T::class.java) +inline fun > enumAttribute(default: T? = null) = + EnumParseDelegate(null, default, T::class.java) /** * Returns a [Enum] property delegate for [ParseObject]s. This uses custom implementation for get * to retrieve a local version of the your enum and [ParseObject.put]. */ -inline fun > enumAttribute(name: String? = null, default: T? = null) = EnumParseDelegate(name, default, T::class.java) +inline fun > enumAttribute(name: String? = null, default: T? = null) = + EnumParseDelegate(name, default, T::class.java) diff --git a/ktx/src/main/java/com/parse/ktx/delegates/IntParseDelegate.kt b/ktx/src/main/java/com/parse/ktx/delegates/IntParseDelegate.kt index 06d9a102e..9b4e517a3 100644 --- a/ktx/src/main/java/com/parse/ktx/delegates/IntParseDelegate.kt +++ b/ktx/src/main/java/com/parse/ktx/delegates/IntParseDelegate.kt @@ -15,7 +15,7 @@ class IntParseDelegate(private val name: String?) { } operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: Int) { - parseObject.put(name ?:property.name, value) + parseObject.put(name ?: property.name, value) } } diff --git a/ktx/src/main/java/com/parse/ktx/delegates/ListParseDelegate.kt b/ktx/src/main/java/com/parse/ktx/delegates/ListParseDelegate.kt index e0d0939bd..f8846c054 100644 --- a/ktx/src/main/java/com/parse/ktx/delegates/ListParseDelegate.kt +++ b/ktx/src/main/java/com/parse/ktx/delegates/ListParseDelegate.kt @@ -15,7 +15,11 @@ class ListParseDelegate(private val name: String?) { return parseObject.getList(name ?: property.name) as? MutableList } - operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: MutableList?) { + operator fun setValue( + parseObject: ParseObject, + property: KProperty<*>, + value: MutableList? + ) { parseObject.putOrIgnore(name ?: property.name, value) } diff --git a/ktx/src/main/java/com/parse/ktx/delegates/MapParseDelegate.kt b/ktx/src/main/java/com/parse/ktx/delegates/MapParseDelegate.kt index 046118dd3..80f851f32 100644 --- a/ktx/src/main/java/com/parse/ktx/delegates/MapParseDelegate.kt +++ b/ktx/src/main/java/com/parse/ktx/delegates/MapParseDelegate.kt @@ -11,11 +11,18 @@ import kotlin.reflect.KProperty */ class MapParseDelegate(private val name: String?) { - operator fun getValue(parseObject: ParseObject, property: KProperty<*>): MutableMap? { + operator fun getValue( + parseObject: ParseObject, + property: KProperty<*> + ): MutableMap? { return parseObject.getMap(name ?: property.name) as? MutableMap } - operator fun setValue(parseObject: ParseObject, property: KProperty<*>, value: MutableMap?) { + operator fun setValue( + parseObject: ParseObject, + property: KProperty<*>, + value: MutableMap? + ) { parseObject.putOrIgnore(name ?: property.name, value) } diff --git a/ktx/src/main/java/com/parse/ktx/delegates/ParseRelationDelegate.kt b/ktx/src/main/java/com/parse/ktx/delegates/ParseRelationDelegate.kt index 2529fc33a..dd7318eaa 100644 --- a/ktx/src/main/java/com/parse/ktx/delegates/ParseRelationDelegate.kt +++ b/ktx/src/main/java/com/parse/ktx/delegates/ParseRelationDelegate.kt @@ -12,7 +12,7 @@ import kotlin.reflect.KProperty class ParseRelationDelegate(private val name: String?) { operator fun getValue(parseObject: ParseObject, property: KProperty<*>): ParseRelation { - return parseObject.getRelation(name ?: property.name) + return parseObject.getRelation(name ?: property.name) } } @@ -21,4 +21,5 @@ class ParseRelationDelegate(private val name: String?) { * Returns a [ParseRelation] property delegate for [ParseObject]s. * This uses [ParseObject.getRelation]. */ -inline fun relationAttribute(name: String? = null) = ParseRelationDelegate(name) +inline fun relationAttribute(name: String? = null) = + ParseRelationDelegate(name) diff --git a/parse/build.gradle b/parse/build.gradle index 303f7a27a..d1003148c 100644 --- a/parse/build.gradle +++ b/parse/build.gradle @@ -1,5 +1,6 @@ apply plugin: "com.android.library" -apply plugin: "com.github.kt3k.coveralls" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -12,6 +13,12 @@ android { consumerProguardFiles "release-proguard.pro" } + testOptions { + unitTests { + includeAndroidResources = true + } + } + packagingOptions { exclude '**/BuildConfig.class' } @@ -25,6 +32,11 @@ android { testCoverageEnabled = true } } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } ext { @@ -33,57 +45,43 @@ ext { } dependencies { - api "androidx.annotation:annotation:1.1.0" - api "androidx.core:core:1.2.0" + api "androidx.annotation:annotation:1.2.0" + api "androidx.core:core:1.6.0" api "com.squareup.okhttp3:okhttp:$okhttpVersion" api project(':bolts-tasks') - testImplementation "org.robolectric:robolectric:3.8" + testImplementation 'junit:junit:4.13.2' + testImplementation "org.robolectric:robolectric:4.6" testImplementation "org.skyscreamer:jsonassert:1.5.0" - testImplementation "org.mockito:mockito-core:1.10.19" + testImplementation "org.mockito:mockito-core:3.9.0" testImplementation "com.squareup.okhttp3:mockwebserver:$okhttpVersion" } //region Code Coverage -apply plugin: "jacoco" +apply plugin: "com.dicedmelon.gradle.jacoco-android" jacoco { - toolVersion "0.7.1.201405082137" + toolVersion = "0.8.7" } -task jacocoTestReport(type: JacocoReport, dependsOn: "testDebugUnitTest") { - group = "Reporting" - description = "Generate Jacoco coverage reports" - - classDirectories = fileTree( - dir: "${buildDir}/intermediates/classes/debug", - excludes: ['**/R.class', - '**/R$*.class', - '**/*$ViewInjector*.*', - '**/BuildConfig.*', - '**/Manifest*.*'] - ) - - sourceDirectories = files("${buildDir.parent}/src/main/java") - additionalSourceDirs = files([ - "${buildDir}/generated/source/buildConfig/debug", - "${buildDir}/generated/source/r/debug" - ]) - executionData = files("${buildDir}/jacoco/testDebugUnitTest.exec") - - reports { - xml.enabled = true - html.enabled = true - } +tasks.withType(Test) { + jacoco.includeNoLocationClasses = true + jacoco.excludes = ['jdk.internal.*'] +} + +jacocoAndroidUnitTestReport { + csv.enabled false + html.enabled true + xml.enabled true } //endregion //region Coveralls -coveralls.jacocoReportPath = "${buildDir}/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" +apply plugin: "com.github.kt3k.coveralls" -//endregion +coveralls.jacocoReportPath = "${buildDir}/jacoco/jacoco.xml" -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" +//endregion \ No newline at end of file diff --git a/parse/src/main/java/com/parse/AbstractQueryController.java b/parse/src/main/java/com/parse/AbstractQueryController.java index 6e54e272b..8f1851c1c 100644 --- a/parse/src/main/java/com/parse/AbstractQueryController.java +++ b/parse/src/main/java/com/parse/AbstractQueryController.java @@ -8,9 +8,6 @@ */ package com.parse; -import java.util.List; - -import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; /** @@ -22,17 +19,14 @@ abstract class AbstractQueryController implements ParseQueryController { @Override public Task getFirstAsync(ParseQuery.State state, ParseUser user, Task cancellationToken) { - return findAsync(state, user, cancellationToken).continueWith(new Continuation, T>() { - @Override - public T then(Task> task) throws Exception { - if (task.isFaulted()) { - throw task.getError(); - } - if (task.getResult() != null && task.getResult().size() > 0) { - return task.getResult().get(0); - } - throw new ParseException(ParseException.OBJECT_NOT_FOUND, "no results found for query"); + return findAsync(state, user, cancellationToken).continueWith(task -> { + if (task.isFaulted()) { + throw task.getError(); + } + if (task.getResult() != null && task.getResult().size() > 0) { + return task.getResult().get(0); } + throw new ParseException(ParseException.OBJECT_NOT_FOUND, "no results found for query"); }); } } diff --git a/parse/src/main/java/com/parse/CacheQueryController.java b/parse/src/main/java/com/parse/CacheQueryController.java index 70cc2cfa9..b3c8e760a 100644 --- a/parse/src/main/java/com/parse/CacheQueryController.java +++ b/parse/src/main/java/com/parse/CacheQueryController.java @@ -8,14 +8,12 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONException; import org.json.JSONObject; import java.util.List; -import java.util.concurrent.Callable; - -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; class CacheQueryController extends AbstractQueryController { @@ -76,18 +74,15 @@ public Task runFromCacheAsync() { private Task> findFromCacheAsync( final ParseQuery.State state, String sessionToken) { final String cacheKey = ParseRESTQueryCommand.findCommand(state, sessionToken).getCacheKey(); - return Task.call(new Callable>() { - @Override - public List call() throws Exception { - JSONObject cached = ParseKeyValueCache.jsonFromKeyValueCache(cacheKey, state.maxCacheAge()); - if (cached == null) { - throw new ParseException(ParseException.CACHE_MISS, "results not cached"); - } - try { - return networkController.convertFindResponse(state, cached); - } catch (JSONException e) { - throw new ParseException(ParseException.CACHE_MISS, "the cache contains corrupted json"); - } + return Task.call(() -> { + JSONObject cached = ParseKeyValueCache.jsonFromKeyValueCache(cacheKey, state.maxCacheAge()); + if (cached == null) { + throw new ParseException(ParseException.CACHE_MISS, "results not cached"); + } + try { + return networkController.convertFindResponse(state, cached); + } catch (JSONException e) { + throw new ParseException(ParseException.CACHE_MISS, "the cache contains corrupted json"); } }, Task.BACKGROUND_EXECUTOR); } @@ -103,18 +98,15 @@ public List call() throws Exception { private Task countFromCacheAsync( final ParseQuery.State state, String sessionToken) { final String cacheKey = ParseRESTQueryCommand.countCommand(state, sessionToken).getCacheKey(); - return Task.call(new Callable() { - @Override - public Integer call() throws Exception { - JSONObject cached = ParseKeyValueCache.jsonFromKeyValueCache(cacheKey, state.maxCacheAge()); - if (cached == null) { - throw new ParseException(ParseException.CACHE_MISS, "results not cached"); - } - try { - return cached.getInt("count"); - } catch (JSONException e) { - throw new ParseException(ParseException.CACHE_MISS, "the cache contains corrupted json"); - } + return Task.call(() -> { + JSONObject cached = ParseKeyValueCache.jsonFromKeyValueCache(cacheKey, state.maxCacheAge()); + if (cached == null) { + throw new ParseException(ParseException.CACHE_MISS, "results not cached"); + } + try { + return cached.getInt("count"); + } catch (JSONException e) { + throw new ParseException(ParseException.CACHE_MISS, "the cache contains corrupted json"); } }, Task.BACKGROUND_EXECUTOR); } @@ -128,30 +120,22 @@ private Task runCommandWithPolicyAsync(final CommandDelegate< case CACHE_ONLY: return c.runFromCacheAsync(); case CACHE_ELSE_NETWORK: - return c.runFromCacheAsync().continueWithTask(new Continuation>() { - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - @Override - public Task then(Task task) { - if (task.getError() instanceof ParseException) { - return c.runOnNetworkAsync(); - } - return task; + return c.runFromCacheAsync().continueWithTask(task -> { + if (task.getError() instanceof ParseException) { + return c.runOnNetworkAsync(); } + return task; }); case NETWORK_ELSE_CACHE: - return c.runOnNetworkAsync().continueWithTask(new Continuation>() { - @SuppressWarnings("ThrowableResultOfMethodCallIgnored") - @Override - public Task then(Task task) { - Exception error = task.getError(); - if (error instanceof ParseException && - ((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) { - return c.runFromCacheAsync(); - } - // Either the query succeeded, or there was an an error with the query, not the - // network - return task; + return c.runOnNetworkAsync().continueWithTask(task -> { + Exception error = task.getError(); + if (error instanceof ParseException && + ((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) { + return c.runFromCacheAsync(); } + // Either the query succeeded, or there was an an error with the query, not the + // network + return task; }); case CACHE_THEN_NETWORK: throw new RuntimeException( diff --git a/parse/src/main/java/com/parse/CachedCurrentInstallationController.java b/parse/src/main/java/com/parse/CachedCurrentInstallationController.java index 350a5154a..faf2ab5b5 100644 --- a/parse/src/main/java/com/parse/CachedCurrentInstallationController.java +++ b/parse/src/main/java/com/parse/CachedCurrentInstallationController.java @@ -8,7 +8,6 @@ */ package com.parse; -import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; class CachedCurrentInstallationController @@ -48,23 +47,10 @@ public Task setAsync(final ParseInstallation installation) { return Task.forResult(null); } - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.setAsync(installation); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - installationId.set(installation.getInstallationId()); - return task; - } - }, ParseExecutors.io()); - } - }); + return taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task -> store.setAsync(installation)).continueWithTask(task -> { + installationId.set(installation.getInstallationId()); + return task; + }, ParseExecutors.io())); } @Override @@ -75,40 +61,29 @@ public Task getAsync() { } } - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (mutex) { - if (currentInstallation != null) { - return Task.forResult(currentInstallation); - } - } - - return store.getAsync().continueWith(new Continuation() { - @Override - public ParseInstallation then(Task task) { - ParseInstallation current = task.getResult(); - if (current == null) { - current = ParseObject.create(ParseInstallation.class); - current.updateDeviceInfo(installationId); - } else { - installationId.set(current.getInstallationId()); - PLog.v(TAG, "Successfully deserialized Installation object"); - } - - synchronized (mutex) { - currentInstallation = current; - } - return current; - } - }, ParseExecutors.io()); - } - }); + return taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task -> { + synchronized (mutex) { + if (currentInstallation != null) { + return Task.forResult(currentInstallation); + } } - }); + + return store.getAsync().continueWith(task1 -> { + ParseInstallation current = task1.getResult(); + if (current == null) { + current = ParseObject.create(ParseInstallation.class); + current.updateDeviceInfo(installationId); + } else { + installationId.set(current.getInstallationId()); + PLog.v(TAG, "Successfully deserialized Installation object"); + } + + synchronized (mutex) { + currentInstallation = current; + } + return current; + }, ParseExecutors.io()); + })); } @Override @@ -119,17 +94,7 @@ public Task existsAsync() { } } - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.existsAsync(); - } - }); - } - }); + return taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task -> store.existsAsync())); } @Override diff --git a/parse/src/main/java/com/parse/CachedCurrentUserController.java b/parse/src/main/java/com/parse/CachedCurrentUserController.java index 2db9f7a36..ce9b5322d 100644 --- a/parse/src/main/java/com/parse/CachedCurrentUserController.java +++ b/parse/src/main/java/com/parse/CachedCurrentUserController.java @@ -8,12 +8,11 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import java.util.Arrays; import java.util.Map; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class CachedCurrentUserController implements ParseCurrentUserController { /** @@ -40,52 +39,30 @@ public CachedCurrentUserController(ParseObjectStore store) { @Override public Task setAsync(final ParseUser user) { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseUser oldCurrentUser; - synchronized (mutex) { - oldCurrentUser = currentUser; - } - - if (oldCurrentUser != null && oldCurrentUser != user) { - // We don't need to revoke the token since we're not explicitly calling logOut - // We don't need to remove persisted files since we're overwriting them - return oldCurrentUser.logOutAsync(false).continueWith(new Continuation() { - @Override - public Void then(Task task) { - return null; // ignore errors - } - }); - } - return task; - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - user.setIsCurrentUser(true); - return user.synchronizeAllAuthDataAsync(); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.setAsync(user).continueWith(new Continuation() { - @Override - public Void then(Task task) { - synchronized (mutex) { - currentUserMatchesDisk = !task.isFaulted(); - currentUser = user; - } - return null; - } - }); - } + return taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task -> { + ParseUser oldCurrentUser; + synchronized (mutex) { + oldCurrentUser = currentUser; + } + + if (oldCurrentUser != null && oldCurrentUser != user) { + // We don't need to revoke the token since we're not explicitly calling logOut + // We don't need to remove persisted files since we're overwriting them + return oldCurrentUser.logOutAsync(false).continueWith(task1 -> { + return null; // ignore errors }); } - }); + return task; + }).onSuccessTask(task -> { + user.setIsCurrentUser(true); + return user.synchronizeAllAuthDataAsync(); + }).onSuccessTask(task -> store.setAsync(user).continueWith(task12 -> { + synchronized (mutex) { + currentUserMatchesDisk = !task12.isFaulted(); + currentUser = user; + } + return null; + }))); } @Override @@ -112,17 +89,7 @@ public Task existsAsync() { } } - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.existsAsync(); - } - }); - } - }); + return taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task -> store.existsAsync())); } @Override @@ -155,52 +122,37 @@ public void clearFromDisk() { @Override public Task getCurrentSessionTokenAsync() { - return getAsync(false).onSuccess(new Continuation() { - @Override - public String then(Task task) { - ParseUser user = task.getResult(); - return user != null ? user.getSessionToken() : null; - } + return getAsync(false).onSuccess(task -> { + ParseUser user = task.getResult(); + return user != null ? user.getSessionToken() : null; }); } @Override public Task logOutAsync() { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - // We can parallelize disk and network work, but only after we restore the current user from - // disk. - final Task userTask = getAsync(false); - return Task.whenAll(Arrays.asList(userTask, toAwait)).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - Task logOutTask = userTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseUser user = task.getResult(); - if (user == null) { - return task.cast(); - } - return user.logOutAsync(); - } - }); - - Task diskTask = store.deleteAsync().continueWith(new Continuation() { - @Override - public Void then(Task task) { - boolean deleted = !task.isFaulted(); - synchronized (mutex) { - currentUserMatchesDisk = deleted; - currentUser = null; - } - return null; - } - }); - return Task.whenAll(Arrays.asList(logOutTask, diskTask)); + return taskQueue.enqueue(toAwait -> { + // We can parallelize disk and network work, but only after we restore the current user from + // disk. + final Task userTask = getAsync(false); + return Task.whenAll(Arrays.asList(userTask, toAwait)).continueWithTask(task -> { + Task logOutTask = userTask.onSuccessTask(task1 -> { + ParseUser user = task1.getResult(); + if (user == null) { + return task1.cast(); } + return user.logOutAsync(); }); - } + + Task diskTask = store.deleteAsync().continueWith(task12 -> { + boolean deleted = !task12.isFaulted(); + synchronized (mutex) { + currentUserMatchesDisk = deleted; + currentUser = null; + } + return null; + }); + return Task.whenAll(Arrays.asList(logOutTask, diskTask)); + }); }); } @@ -212,58 +164,47 @@ public Task getAsync(final boolean shouldAutoCreateUser) { } } - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task ignored) { - ParseUser current; - boolean matchesDisk; - synchronized (mutex) { - current = currentUser; - matchesDisk = currentUserMatchesDisk; - } - - if (current != null) { - return Task.forResult(current); - } - - if (matchesDisk) { - if (shouldAutoCreateUser) { - return Task.forResult(lazyLogIn()); - } - return null; - } - - return store.getAsync().continueWith(new Continuation() { - @Override - public ParseUser then(Task task) { - ParseUser current = task.getResult(); - boolean matchesDisk = !task.isFaulted(); - - synchronized (mutex) { - currentUser = current; - currentUserMatchesDisk = matchesDisk; - } - - if (current != null) { - synchronized (current.mutex) { - current.setIsCurrentUser(true); - } - return current; - } - - if (shouldAutoCreateUser) { - return lazyLogIn(); - } - return null; - } - }); - } - }); + return taskQueue.enqueue(toAwait -> toAwait.continueWithTask(ignored -> { + ParseUser current; + boolean matchesDisk; + synchronized (mutex) { + current = currentUser; + matchesDisk = currentUserMatchesDisk; } - }); + + if (current != null) { + return Task.forResult(current); + } + + if (matchesDisk) { + if (shouldAutoCreateUser) { + return Task.forResult(lazyLogIn()); + } + return null; + } + + return store.getAsync().continueWith(task -> { + ParseUser current1 = task.getResult(); + boolean matchesDisk1 = !task.isFaulted(); + + synchronized (mutex) { + currentUser = current1; + currentUserMatchesDisk = matchesDisk1; + } + + if (current1 != null) { + synchronized (current1.mutex) { + current1.setIsCurrentUser(true); + } + return current1; + } + + if (shouldAutoCreateUser) { + return lazyLogIn(); + } + return null; + }); + })); } private ParseUser lazyLogIn() { diff --git a/parse/src/main/java/com/parse/ConnectivityNotifier.java b/parse/src/main/java/com/parse/ConnectivityNotifier.java index f5c7e8227..9b290fab0 100644 --- a/parse/src/main/java/com/parse/ConnectivityNotifier.java +++ b/parse/src/main/java/com/parse/ConnectivityNotifier.java @@ -25,7 +25,7 @@ class ConnectivityNotifier extends BroadcastReceiver { private static final String TAG = "com.parse.ConnectivityNotifier"; private static final ConnectivityNotifier singleton = new ConnectivityNotifier(); private final Object lock = new Object(); - private Set listeners = new HashSet<>(); + private final Set listeners = new HashSet<>(); private boolean hasRegisteredReceiver = false; public static ConnectivityNotifier getNotifier(Context context) { diff --git a/parse/src/main/java/com/parse/EventuallyPin.java b/parse/src/main/java/com/parse/EventuallyPin.java index d3fdada11..8173baefb 100644 --- a/parse/src/main/java/com/parse/EventuallyPin.java +++ b/parse/src/main/java/com/parse/EventuallyPin.java @@ -8,6 +8,7 @@ */ package com.parse; +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import org.json.JSONException; @@ -19,9 +20,6 @@ import java.util.List; import java.util.UUID; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * Properties * - time @@ -98,12 +96,7 @@ private static Task pinEventuallyCommand(int type, ParseObject ob if (command != null) { pin.put("command", command); } - return pin.pinInBackground(PIN_NAME).continueWith(new Continuation() { - @Override - public EventuallyPin then(Task task) { - return pin; - } - }); + return pin.pinInBackground(PIN_NAME).continueWith(task -> pin); } public static Task> findAllPinned() { @@ -122,26 +115,18 @@ public static Task> findAllPinned(Collection exclude // We need pass in a null user because we don't want the query to fetch the current user // from LDS. - return query.findInBackground().onSuccessTask(new Continuation, Task>>() { - @Override - public Task> then(Task> task) { - final List pins = task.getResult(); - List> tasks = new ArrayList<>(); - - for (EventuallyPin pin : pins) { - ParseObject object = pin.getObject(); - if (object != null) { - tasks.add(object.fetchFromLocalDatastoreAsync().makeVoid()); - } + return query.findInBackground().onSuccessTask(task -> { + final List pins = task.getResult(); + List> tasks = new ArrayList<>(); + + for (EventuallyPin pin : pins) { + ParseObject object = pin.getObject(); + if (object != null) { + tasks.add(object.fetchFromLocalDatastoreAsync().makeVoid()); } - - return Task.whenAll(tasks).continueWithTask(new Continuation>>() { - @Override - public Task> then(Task task) { - return Task.forResult(pins); - } - }); } + + return Task.whenAll(tasks).continueWithTask(task1 -> Task.forResult(pins)); }); } @@ -175,11 +160,10 @@ public ParseRESTCommand getCommand() throws JSONException { ParseRESTCommand command = null; if (ParseRESTCommand.isValidCommandJSONObject(json)) { command = ParseRESTCommand.fromJSONObject(json); - } else if (ParseRESTCommand.isValidOldFormatCommandJSONObject(json)) { - // do nothing - } else { + } else if (!ParseRESTCommand.isValidOldFormatCommandJSONObject(json)) { throw new JSONException("Failed to load command from JSON."); } + return command; } } diff --git a/parse/src/main/java/com/parse/FileObjectStore.java b/parse/src/main/java/com/parse/FileObjectStore.java index 8982434f6..1e3354385 100644 --- a/parse/src/main/java/com/parse/FileObjectStore.java +++ b/parse/src/main/java/com/parse/FileObjectStore.java @@ -8,14 +8,13 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.IOException; -import java.util.concurrent.Callable; - -import com.parse.boltsinternal.Task; class FileObjectStore implements ParseObjectStore { @@ -26,6 +25,7 @@ class FileObjectStore implements ParseObjectStore { public FileObjectStore(Class clazz, File file, ParseObjectCurrentCoder coder) { this(getSubclassingController().getClassName(clazz), file, coder); } + public FileObjectStore(String className, File file, ParseObjectCurrentCoder coder) { this.className = className; this.file = file; @@ -81,50 +81,36 @@ private static T getFromDisk( @Override public Task setAsync(final T object) { - return Task.call(new Callable() { - @Override - public Void call() { - saveToDisk(coder, object, file); - //TODO (grantland): check to see if this failed? We currently don't for legacy reasons. - return null; - } + return Task.call(() -> { + saveToDisk(coder, object, file); + //TODO (grantland): check to see if this failed? We currently don't for legacy reasons. + return null; }, ParseExecutors.io()); } @Override public Task getAsync() { - return Task.call(new Callable() { - @Override - public T call() { - if (!file.exists()) { - return null; - } - return getFromDisk(coder, file, ParseObject.State.newBuilder(className)); + return Task.call(() -> { + if (!file.exists()) { + return null; } + return getFromDisk(coder, file, ParseObject.State.newBuilder(className)); }, ParseExecutors.io()); } @Override public Task existsAsync() { - return Task.call(new Callable() { - @Override - public Boolean call() { - return file.exists(); - } - }, ParseExecutors.io()); + return Task.call(file::exists, ParseExecutors.io()); } @Override public Task deleteAsync() { - return Task.call(new Callable() { - @Override - public Void call() { - if (file.exists() && !ParseFileUtils.deleteQuietly(file)) { - throw new RuntimeException("Unable to delete"); - } - - return null; + return Task.call(() -> { + if (file.exists() && !ParseFileUtils.deleteQuietly(file)) { + throw new RuntimeException("Unable to delete"); } + + return null; }, ParseExecutors.io()); } } diff --git a/parse/src/main/java/com/parse/KnownParseObjectDecoder.java b/parse/src/main/java/com/parse/KnownParseObjectDecoder.java index db86f03d1..9f21c9af7 100644 --- a/parse/src/main/java/com/parse/KnownParseObjectDecoder.java +++ b/parse/src/main/java/com/parse/KnownParseObjectDecoder.java @@ -15,7 +15,7 @@ * has been fetched instead of creating a new instance. */ class KnownParseObjectDecoder extends ParseDecoder { - private Map fetchedObjects; + private final Map fetchedObjects; public KnownParseObjectDecoder(Map fetchedObjects) { super(); diff --git a/parse/src/main/java/com/parse/LocationNotifier.java b/parse/src/main/java/com/parse/LocationNotifier.java index 0db252ac9..ef65b9d8a 100644 --- a/parse/src/main/java/com/parse/LocationNotifier.java +++ b/parse/src/main/java/com/parse/LocationNotifier.java @@ -15,13 +15,13 @@ import android.location.LocationManager; import android.os.Bundle; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; - import com.parse.boltsinternal.Capture; import com.parse.boltsinternal.Task; import com.parse.boltsinternal.TaskCompletionSource; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + /** * LocationNotifier is a wrapper around fetching the current device's location. It looks for the GPS * and Network LocationProviders by default (printStackTrace()'ing if, for example, the app doesn't @@ -86,12 +86,9 @@ public void onStatusChanged(String provider, int status, Bundle extras) { } }; - timeoutFuture.set(ParseExecutors.scheduled().schedule(new Runnable() { - @Override - public void run() { - tcs.trySetError(new ParseException(ParseException.TIMEOUT, "Location fetch timed out.")); - manager.removeUpdates(listener); - } + timeoutFuture.set(ParseExecutors.scheduled().schedule(() -> { + tcs.trySetError(new ParseException(ParseException.TIMEOUT, "Location fetch timed out.")); + manager.removeUpdates(listener); }, timeout, TimeUnit.MILLISECONDS)); String provider = manager.getBestProvider(criteria, true); diff --git a/parse/src/main/java/com/parse/LockSet.java b/parse/src/main/java/com/parse/LockSet.java index 46978e117..dc058a0f2 100644 --- a/parse/src/main/java/com/parse/LockSet.java +++ b/parse/src/main/java/com/parse/LockSet.java @@ -9,7 +9,6 @@ package com.parse; import java.util.Collection; -import java.util.Comparator; import java.util.Set; import java.util.TreeSet; import java.util.WeakHashMap; @@ -22,13 +21,10 @@ class LockSet { private final Set locks; public LockSet(Collection locks) { - this.locks = new TreeSet<>(new Comparator() { - @Override - public int compare(Lock lhs, Lock rhs) { - Long lhsId = getStableId(lhs); - Long rhsId = getStableId(rhs); - return lhsId.compareTo(rhsId); - } + this.locks = new TreeSet<>((lhs, rhs) -> { + Long lhsId = getStableId(lhs); + Long rhsId = getStableId(rhs); + return lhsId.compareTo(rhsId); }); this.locks.addAll(locks); } diff --git a/parse/src/main/java/com/parse/NetworkObjectController.java b/parse/src/main/java/com/parse/NetworkObjectController.java index 0c668a1fd..07e135487 100644 --- a/parse/src/main/java/com/parse/NetworkObjectController.java +++ b/parse/src/main/java/com/parse/NetworkObjectController.java @@ -8,18 +8,17 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import java.util.ArrayList; import java.util.List; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class NetworkObjectController implements ParseObjectController { - private ParseHttpClient client; - private ParseObjectCoder coder; + private final ParseHttpClient client; + private final ParseObjectCoder coder; public NetworkObjectController(ParseHttpClient client) { this.client = client; @@ -34,16 +33,13 @@ public Task fetchAsync( state.className(), sessionToken); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseObject.State then(Task task) { - JSONObject result = task.getResult(); - // Copy and clear to create an new empty instance of the same type as `state` - ParseObject.State.Init builder = state.newBuilder().clear(); - return coder.decode(builder, result, decoder) - .isComplete(true) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + // Copy and clear to create an new empty instance of the same type as `state` + ParseObject.State.Init builder = state.newBuilder().clear(); + return coder.decode(builder, result, decoder) + .isComplete(true) + .build(); }); } @@ -63,16 +59,13 @@ public Task saveAsync( state, objectJSON, sessionToken); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseObject.State then(Task task) { - JSONObject result = task.getResult(); - // Copy and clear to create an new empty instance of the same type as `state` - ParseObject.State.Init builder = state.newBuilder().clear(); - return coder.decode(builder, result, decoder) - .isComplete(false) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + // Copy and clear to create an new empty instance of the same type as `state` + ParseObject.State.Init builder = state.newBuilder().clear(); + return coder.decode(builder, result, decoder) + .isComplete(false) + .build(); }); } @@ -103,16 +96,13 @@ public List> saveAllAsync( for (int i = 0; i < batchSize; i++) { final ParseObject.State state = states.get(i); final ParseDecoder decoder = decoders.get(i); - tasks.add(batchTasks.get(i).onSuccess(new Continuation() { - @Override - public ParseObject.State then(Task task) { - JSONObject result = task.getResult(); - // Copy and clear to create an new empty instance of the same type as `state` - ParseObject.State.Init builder = state.newBuilder().clear(); - return coder.decode(builder, result, decoder) - .isComplete(false) - .build(); - } + tasks.add(batchTasks.get(i).onSuccess(task -> { + JSONObject result = task.getResult(); + // Copy and clear to create an new empty instance of the same type as `state` + ParseObject.State.Init builder = state.newBuilder().clear(); + return coder.decode(builder, result, decoder) + .isComplete(false) + .build(); })); } return tasks; diff --git a/parse/src/main/java/com/parse/NetworkQueryController.java b/parse/src/main/java/com/parse/NetworkQueryController.java index 9721038c7..24f037a21 100644 --- a/parse/src/main/java/com/parse/NetworkQueryController.java +++ b/parse/src/main/java/com/parse/NetworkQueryController.java @@ -8,6 +8,8 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -15,9 +17,6 @@ import java.util.ArrayList; import java.util.List; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class NetworkQueryController extends AbstractQueryController { private static final String TAG = "NetworkQueryController"; @@ -56,34 +55,31 @@ public Task countAsync( final ParseRESTCommand command = ParseRESTQueryCommand.findCommand(state, sessionToken); final long querySent = System.nanoTime(); - return command.executeAsync(restClient, ct).onSuccess(new Continuation>() { - @Override - public List then(Task task) throws Exception { - JSONObject json = task.getResult(); - // Cache the results, unless we are ignoring the cache - ParseQuery.CachePolicy policy = state.cachePolicy(); - if (policy != null && (policy != ParseQuery.CachePolicy.IGNORE_CACHE)) { - ParseKeyValueCache.saveToKeyValueCache(command.getCacheKey(), json.toString()); - } + return command.executeAsync(restClient, ct).onSuccess(task -> { + JSONObject json = task.getResult(); + // Cache the results, unless we are ignoring the cache + ParseQuery.CachePolicy policy = state.cachePolicy(); + if (policy != null && (policy != ParseQuery.CachePolicy.IGNORE_CACHE)) { + ParseKeyValueCache.saveToKeyValueCache(command.getCacheKey(), json.toString()); + } - long queryReceived = System.nanoTime(); + long queryReceived = System.nanoTime(); - List response = convertFindResponse(state, task.getResult()); + List response = convertFindResponse(state, task.getResult()); - long objectsParsed = System.nanoTime(); + long objectsParsed = System.nanoTime(); - if (json.has("trace")) { - Object serverTrace = json.get("trace"); - PLog.d("ParseQuery", - String.format("Query pre-processing took %f seconds\n" + - "%s\n" + - "Client side parsing took %f seconds\n", - (querySent - queryStart) / (1000.0f * 1000.0f), - serverTrace, - (objectsParsed - queryReceived) / (1000.0f * 1000.0f))); - } - return response; + if (json.has("trace")) { + Object serverTrace = json.get("trace"); + PLog.d("ParseQuery", + String.format("Query pre-processing took %f seconds\n" + + "%s\n" + + "Client side parsing took %f seconds\n", + (querySent - queryStart) / (1000.0f * 1000.0f), + serverTrace, + (objectsParsed - queryReceived) / (1000.0f * 1000.0f))); } + return response; }, Task.BACKGROUND_EXECUTOR); } @@ -93,23 +89,17 @@ public List then(Task task) throws Exception { Task ct) { final ParseRESTCommand command = ParseRESTQueryCommand.countCommand(state, sessionToken); - return command.executeAsync(restClient, ct).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - // Cache the results, unless we are ignoring the cache - ParseQuery.CachePolicy policy = state.cachePolicy(); - if (policy != null && policy != ParseQuery.CachePolicy.IGNORE_CACHE) { - JSONObject result = task.getResult(); - ParseKeyValueCache.saveToKeyValueCache(command.getCacheKey(), result.toString()); - } - return task; - } - }, Task.BACKGROUND_EXECUTOR).onSuccess(new Continuation() { - @Override - public Integer then(Task task) { - // Convert response - return task.getResult().optInt("count"); + return command.executeAsync(restClient, ct).onSuccessTask(task -> { + // Cache the results, unless we are ignoring the cache + ParseQuery.CachePolicy policy = state.cachePolicy(); + if (policy != null && policy != ParseQuery.CachePolicy.IGNORE_CACHE) { + JSONObject result = task.getResult(); + ParseKeyValueCache.saveToKeyValueCache(command.getCacheKey(), result.toString()); } + return task; + }, Task.BACKGROUND_EXECUTOR).onSuccess(task -> { + // Convert response + return task.getResult().optInt("count"); }); } @@ -118,7 +108,7 @@ public Integer then(Task task) { /* package */ List convertFindResponse(ParseQuery.State state, JSONObject response) throws JSONException { ArrayList answer = new ArrayList<>(); - JSONArray results = response.getJSONArray("results"); + JSONArray results = response.optJSONArray("results"); if (results == null) { PLog.d(TAG, "null results in find response"); } else { diff --git a/parse/src/main/java/com/parse/NetworkSessionController.java b/parse/src/main/java/com/parse/NetworkSessionController.java index 6a7607c36..9ed09986d 100644 --- a/parse/src/main/java/com/parse/NetworkSessionController.java +++ b/parse/src/main/java/com/parse/NetworkSessionController.java @@ -8,11 +8,10 @@ */ package com.parse; -import org.json.JSONObject; - -import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; +import org.json.JSONObject; + class NetworkSessionController implements ParseSessionController { private final ParseHttpClient client; @@ -28,14 +27,11 @@ public Task getSessionAsync(String sessionToken) { ParseRESTSessionCommand command = ParseRESTSessionCommand.getCurrentSessionCommand(sessionToken); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseObject.State then(Task task) { - JSONObject result = task.getResult(); - return coder.decode(new ParseObject.State.Builder("_Session"), result, ParseDecoder.get()) - .isComplete(true) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + return coder.decode(new ParseObject.State.Builder("_Session"), result, ParseDecoder.get()) + .isComplete(true) + .build(); }); } @@ -50,14 +46,11 @@ public Task revokeAsync(String sessionToken) { public Task upgradeToRevocable(String sessionToken) { ParseRESTSessionCommand command = ParseRESTSessionCommand.upgradeToRevocableSessionCommand(sessionToken); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseObject.State then(Task task) { - JSONObject result = task.getResult(); - return coder.decode(new ParseObject.State.Builder("_Session"), result, ParseDecoder.get()) - .isComplete(true) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + return coder.decode(new ParseObject.State.Builder("_Session"), result, ParseDecoder.get()) + .isComplete(true) + .build(); }); } } diff --git a/parse/src/main/java/com/parse/NetworkUserController.java b/parse/src/main/java/com/parse/NetworkUserController.java index 317fe3eaf..bd1bfa371 100644 --- a/parse/src/main/java/com/parse/NetworkUserController.java +++ b/parse/src/main/java/com/parse/NetworkUserController.java @@ -8,13 +8,12 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import java.util.Map; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class NetworkUserController implements ParseUserController { private static final int STATUS_CODE_CREATED = 201; @@ -42,15 +41,12 @@ public Task signUpAsync( ParseRESTCommand command = ParseRESTUserCommand.signUpUserCommand( objectJSON, sessionToken, revocableSession); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseUser.State then(Task task) { - JSONObject result = task.getResult(); - return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) - .isComplete(false) - .isNew(true) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) + .isComplete(false) + .isNew(true) + .build(); }); } @@ -61,15 +57,12 @@ public Task logInAsync( String username, String password) { ParseRESTCommand command = ParseRESTUserCommand.logInUserCommand( username, password, revocableSession); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseUser.State then(Task task) { - JSONObject result = task.getResult(); - - return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) - .isComplete(true) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + + return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) + .isComplete(true) + .build(); }); } @@ -80,21 +73,18 @@ public Task logInAsync( final ParseRESTUserCommand command = ParseRESTUserCommand.serviceLogInUserCommand( objectJSON, state.sessionToken(), revocableSession); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseUser.State then(Task task) { - JSONObject result = task.getResult(); - - // TODO(grantland): Does the server really respond back with complete object data if the - // object isn't new? - boolean isNew = command.getStatusCode() == STATUS_CODE_CREATED; - boolean isComplete = !isNew; - - return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) - .isComplete(isComplete) - .isNew(isNew) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + + // TODO(grantland): Does the server really respond back with complete object data if the + // object isn't new? + boolean isNew = command.getStatusCode() == STATUS_CODE_CREATED; + boolean isComplete = !isNew; + + return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) + .isComplete(isComplete) + .isNew(isNew) + .build(); }); } @@ -103,17 +93,14 @@ public Task logInAsync( final String authType, final Map authData) { final ParseRESTUserCommand command = ParseRESTUserCommand.serviceLogInUserCommand( authType, authData, revocableSession); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseUser.State then(Task task) { - JSONObject result = task.getResult(); - - return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) - .isComplete(true) - .isNew(command.getStatusCode() == STATUS_CODE_CREATED) - .putAuthData(authType, authData) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + + return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) + .isComplete(true) + .isNew(command.getStatusCode() == STATUS_CODE_CREATED) + .putAuthData(authType, authData) + .build(); }); } @@ -122,15 +109,12 @@ public ParseUser.State then(Task task) { @Override public Task getUserAsync(String sessionToken) { ParseRESTCommand command = ParseRESTUserCommand.getCurrentUserCommand(sessionToken); - return command.executeAsync(client).onSuccess(new Continuation() { - @Override - public ParseUser.State then(Task task) { - JSONObject result = task.getResult(); - - return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) - .isComplete(true) - .build(); - } + return command.executeAsync(client).onSuccess(task -> { + JSONObject result = task.getResult(); + + return coder.decode(new ParseUser.State.Builder(), result, ParseDecoder.get()) + .isComplete(true) + .build(); }); } diff --git a/parse/src/main/java/com/parse/OfflineObjectStore.java b/parse/src/main/java/com/parse/OfflineObjectStore.java index afbd610e9..348aa559f 100644 --- a/parse/src/main/java/com/parse/OfflineObjectStore.java +++ b/parse/src/main/java/com/parse/OfflineObjectStore.java @@ -8,20 +8,21 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import java.util.Arrays; import java.util.List; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class OfflineObjectStore implements ParseObjectStore { private final String className; private final String pinName; private final ParseObjectStore legacy; + public OfflineObjectStore(Class clazz, String pinName, ParseObjectStore legacy) { this(getSubclassingController().getClassName(clazz), pinName, legacy); } + public OfflineObjectStore(String className, String pinName, ParseObjectStore legacy) { this.className = className; this.pinName = pinName; @@ -34,35 +35,22 @@ private static ParseObjectSubclassingController getSubclassingController() { private static Task migrate( final ParseObjectStore from, final ParseObjectStore to) { - return from.getAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final T object = task.getResult(); - if (object == null) { - return task; - } - - return Task.whenAll(Arrays.asList( - from.deleteAsync(), - to.setAsync(object) - )).continueWith(new Continuation() { - @Override - public T then(Task task) { - return object; - } - }); + return from.getAsync().onSuccessTask(task -> { + final T object = task.getResult(); + if (object == null) { + return task; } + + return Task.whenAll(Arrays.asList( + from.deleteAsync(), + to.setAsync(object) + )).continueWith(task1 -> object); }); } @Override public Task setAsync(final T object) { - return ParseObject.unpinAllInBackground(pinName).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return object.pinInBackground(pinName, false); - } - }); + return ParseObject.unpinAllInBackground(pinName).continueWithTask(task -> object.pinInBackground(pinName, false)); } @Override @@ -71,29 +59,23 @@ public Task getAsync() { ParseQuery query = ParseQuery.getQuery(className) .fromPin(pinName) .ignoreACLs(); - return query.findInBackground().onSuccessTask(new Continuation, Task>() { - @Override - public Task then(Task> task) { - List results = task.getResult(); - if (results != null) { - if (results.size() == 1) { - return Task.forResult(results.get(0)); - } else { - return ParseObject.unpinAllInBackground(pinName).cast(); - } + return query.findInBackground().onSuccessTask(task -> { + List results = task.getResult(); + if (results != null) { + if (results.size() == 1) { + return Task.forResult(results.get(0)); + } else { + return ParseObject.unpinAllInBackground(pinName).cast(); } - return Task.forResult(null); } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - T ldsObject = task.getResult(); - if (ldsObject != null) { - return task; - } - - return migrate(legacy, OfflineObjectStore.this).cast(); + return Task.forResult(null); + }).onSuccessTask(task -> { + T ldsObject = task.getResult(); + if (ldsObject != null) { + return task; } + + return migrate(legacy, OfflineObjectStore.this).cast(); }); } @@ -103,15 +85,12 @@ public Task existsAsync() { ParseQuery query = ParseQuery.getQuery(className) .fromPin(pinName) .ignoreACLs(); - return query.countInBackground().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - boolean exists = task.getResult() == 1; - if (exists) { - return Task.forResult(true); - } - return legacy.existsAsync(); + return query.countInBackground().onSuccessTask(task -> { + boolean exists = task.getResult() == 1; + if (exists) { + return Task.forResult(true); } + return legacy.existsAsync(); }); } @@ -121,12 +100,9 @@ public Task deleteAsync() { return Task.whenAll(Arrays.asList( legacy.deleteAsync(), ldsTask - )).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We only really care about the result of unpinning. - return ldsTask; - } + )).continueWithTask(task -> { + // We only really care about the result of unpinning. + return ldsTask; }); } } diff --git a/parse/src/main/java/com/parse/OfflineQueryController.java b/parse/src/main/java/com/parse/OfflineQueryController.java index a678f8130..07140714e 100644 --- a/parse/src/main/java/com/parse/OfflineQueryController.java +++ b/parse/src/main/java/com/parse/OfflineQueryController.java @@ -8,10 +8,10 @@ */ package com.parse; -import java.util.List; - import com.parse.boltsinternal.Task; +import java.util.List; + class OfflineQueryController extends AbstractQueryController { private final OfflineStore offlineStore; diff --git a/parse/src/main/java/com/parse/OfflineQueryLogic.java b/parse/src/main/java/com/parse/OfflineQueryLogic.java index 59e512655..2085ab5ba 100644 --- a/parse/src/main/java/com/parse/OfflineQueryLogic.java +++ b/parse/src/main/java/com/parse/OfflineQueryLogic.java @@ -11,6 +11,7 @@ import com.parse.ParseQuery.KeyConstraints; import com.parse.ParseQuery.QueryConstraints; import com.parse.ParseQuery.RelationConstraint; +import com.parse.boltsinternal.Task; import org.json.JSONArray; import org.json.JSONException; @@ -19,7 +20,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -28,9 +28,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class OfflineQueryLogic { private final OfflineStore store; @@ -214,19 +211,9 @@ private static boolean matchesEqualConstraint(Object constraint, Object value) { Decider decider; if (isStartsWithRegex(constraint)) { - decider = new Decider() { - @Override - public boolean decide(Object constraint, Object value) { - return ((String) value).matches(((KeyConstraints) constraint).get("$regex").toString()); - } - }; + decider = (constraint1, value1) -> ((String) value1).matches(((KeyConstraints) constraint1).get("$regex").toString()); } else { - decider = new Decider() { - @Override - public boolean decide(Object constraint, Object value) { - return constraint.equals(value); - } - }; + decider = Object::equals; } return compare(constraint, value, decider); @@ -243,14 +230,11 @@ private static boolean matchesNotEqualConstraint(Object constraint, Object value * Matches $lt constraints. */ private static boolean matchesLessThanConstraint(Object constraint, Object value) { - return compare(constraint, value, new Decider() { - @Override - public boolean decide(Object constraint, Object value) { - if (value == null || value == JSONObject.NULL) { - return false; - } - return compareTo(constraint, value) > 0; + return compare(constraint, value, (constraint1, value1) -> { + if (value1 == null || value1 == JSONObject.NULL) { + return false; } + return compareTo(constraint1, value1) > 0; }); } @@ -258,14 +242,11 @@ public boolean decide(Object constraint, Object value) { * Matches $lte constraints. */ private static boolean matchesLessThanOrEqualToConstraint(Object constraint, Object value) { - return compare(constraint, value, new Decider() { - @Override - public boolean decide(Object constraint, Object value) { - if (value == null || value == JSONObject.NULL) { - return false; - } - return compareTo(constraint, value) >= 0; + return compare(constraint, value, (constraint1, value1) -> { + if (value1 == null || value1 == JSONObject.NULL) { + return false; } + return compareTo(constraint1, value1) >= 0; }); } @@ -273,14 +254,11 @@ public boolean decide(Object constraint, Object value) { * Matches $gt constraints. */ private static boolean matchesGreaterThanConstraint(Object constraint, Object value) { - return compare(constraint, value, new Decider() { - @Override - public boolean decide(Object constraint, Object value) { - if (value == null || value == JSONObject.NULL) { - return false; - } - return compareTo(constraint, value) < 0; + return compare(constraint, value, (constraint1, value1) -> { + if (value1 == null || value1 == JSONObject.NULL) { + return false; } + return compareTo(constraint1, value1) < 0; }); } @@ -288,14 +266,11 @@ public boolean decide(Object constraint, Object value) { * Matches $gte constraints. */ private static boolean matchesGreaterThanOrEqualToConstraint(Object constraint, Object value) { - return compare(constraint, value, new Decider() { - @Override - public boolean decide(Object constraint, Object value) { - if (value == null || value == JSONObject.NULL) { - return false; - } - return compareTo(constraint, value) <= 0; + return compare(constraint, value, (constraint1, value1) -> { + if (value1 == null || value1 == JSONObject.NULL) { + return false; } + return compareTo(constraint1, value1) <= 0; }); } @@ -711,55 +686,52 @@ static void sort(List results, ParseQuery.State st * TODO(klimt): Test whether we allow dotting into objects for sorting. */ - Collections.sort(results, new Comparator() { - @Override - public int compare(T lhs, T rhs) { - if (nearSphereKey != null) { - ParseGeoPoint lhsPoint; - ParseGeoPoint rhsPoint; - try { - lhsPoint = (ParseGeoPoint) getValue(lhs, nearSphereKey); - rhsPoint = (ParseGeoPoint) getValue(rhs, nearSphereKey); - } catch (ParseException e) { - throw new RuntimeException(e); - } + Collections.sort(results, (lhs, rhs) -> { + if (nearSphereKey != null) { + ParseGeoPoint lhsPoint; + ParseGeoPoint rhsPoint; + try { + lhsPoint = (ParseGeoPoint) getValue(lhs, nearSphereKey); + rhsPoint = (ParseGeoPoint) getValue(rhs, nearSphereKey); + } catch (ParseException e) { + throw new RuntimeException(e); + } - // GeoPoints can't be null if there's a $nearSphere. - double lhsDistance = lhsPoint.distanceInRadiansTo(nearSphereValue); - double rhsDistance = rhsPoint.distanceInRadiansTo(nearSphereValue); - if (lhsDistance != rhsDistance) { - return (lhsDistance - rhsDistance > 0) ? 1 : -1; - } + // GeoPoints can't be null if there's a $nearSphere. + double lhsDistance = lhsPoint.distanceInRadiansTo(nearSphereValue); + double rhsDistance = rhsPoint.distanceInRadiansTo(nearSphereValue); + if (lhsDistance != rhsDistance) { + return (lhsDistance - rhsDistance > 0) ? 1 : -1; } + } - for (String key : keys) { - boolean descending = false; - if (key.startsWith("-")) { - descending = true; - key = key.substring(1); - } + for (String key : keys) { + boolean descending = false; + if (key.startsWith("-")) { + descending = true; + key = key.substring(1); + } - Object lhsValue; - Object rhsValue; - try { - lhsValue = getValue(lhs, key); - rhsValue = getValue(rhs, key); - } catch (ParseException e) { - throw new RuntimeException(e); - } + Object lhsValue; + Object rhsValue; + try { + lhsValue = getValue(lhs, key); + rhsValue = getValue(rhs, key); + } catch (ParseException e) { + throw new RuntimeException(e); + } - int result; - try { - result = compareTo(lhsValue, rhsValue); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException(String.format("Unable to sort by key %s.", key), e); - } - if (result != 0) { - return descending ? -result : result; - } + int result; + try { + result = compareTo(lhsValue, rhsValue); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(String.format("Unable to sort by key %s.", key), e); + } + if (result != 0) { + return descending ? -result : result; } - return 0; } + return 0; }); } @@ -782,12 +754,7 @@ private static Task fetchIncludeAsync( // We do the fetches in series because it makes it easier to fail on the first error. Task task = Task.forResult(null); for (final Object item : collection) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return fetchIncludeAsync(store, item, path, db); - } - }); + task = task.onSuccessTask(task1 -> fetchIncludeAsync(store, item, path, db)); } return task; } else if (container instanceof JSONArray) { @@ -796,12 +763,7 @@ public Task then(Task task) { Task task = Task.forResult(null); for (int i = 0; i < array.length(); ++i) { final int index = i; - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - return fetchIncludeAsync(store, array.get(index), path, db); - } - }); + task = task.onSuccessTask(task12 -> fetchIncludeAsync(store, array.get(index), path, db)); } return task; } @@ -828,35 +790,22 @@ public Task then(Task task) throws Exception { final String rest = (parts.length > 1 ? parts[1] : null); // Make sure the container is fetched. - return Task.forResult(null).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (container instanceof ParseObject) { - // Make sure this object is fetched before descending into it. - return fetchIncludeAsync(store, container, null, db).onSuccess(new Continuation() { - @Override - public Object then(Task task) { - return ((ParseObject) container).get(key); - } - }); - } else if (container instanceof Map) { - return Task.forResult(((Map) container).get(key)); - } else if (container instanceof JSONObject) { - return Task.forResult(((JSONObject) container).opt(key)); - } else if (JSONObject.NULL.equals(container)) { - // Accept JSONObject.NULL value in included field. We swallow it silently instead of - // throwing an exception. - return null; - } else { - return Task.forError(new IllegalStateException("include is invalid")); - } - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return fetchIncludeAsync(store, task.getResult(), rest, db); + return Task.forResult(null).continueWithTask(task -> { + if (container instanceof ParseObject) { + // Make sure this object is fetched before descending into it. + return fetchIncludeAsync(store, container, null, db).onSuccess(task13 -> ((ParseObject) container).get(key)); + } else if (container instanceof Map) { + return Task.forResult(((Map) container).get(key)); + } else if (container instanceof JSONObject) { + return Task.forResult(((JSONObject) container).opt(key)); + } else if (JSONObject.NULL.equals(container)) { + // Accept JSONObject.NULL value in included field. We swallow it silently instead of + // throwing an exception. + return null; + } else { + return Task.forError(new IllegalStateException("include is invalid")); } - }); + }).onSuccessTask(task -> fetchIncludeAsync(store, task.getResult(), rest, db)); } /** @@ -872,12 +821,7 @@ static Task fetchIncludesAsync( // We do the fetches in series because it makes it easier to fail on the first error. Task task = Task.forResult(null); for (final String include : includes) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return fetchIncludeAsync(store, object, include, db); - } - }); + task = task.onSuccessTask(task1 -> fetchIncludeAsync(store, object, include, db)); } return task; } @@ -908,12 +852,7 @@ private ConstraintMatcher createNotInQueryMatcher(Par return new ConstraintMatcher(user) { @Override public Task matchesAsync(T object, ParseSQLiteDatabase db) { - return inQueryMatcher.matchesAsync(object, db).onSuccess(new Continuation() { - @Override - public Boolean then(Task task) { - return !task.getResult(); - } - }); + return inQueryMatcher.matchesAsync(object, db).onSuccess(task -> !task.getResult()); } }; } @@ -952,12 +891,7 @@ private ConstraintMatcher createDontSelectMatcher(Par return new ConstraintMatcher(user) { @Override public Task matchesAsync(T object, ParseSQLiteDatabase db) { - return selectMatcher.matchesAsync(object, db).onSuccess(new Continuation() { - @Override - public Boolean then(Task task) { - return !task.getResult(); - } - }); + return selectMatcher.matchesAsync(object, db).onSuccess(task -> !task.getResult()); } }; } @@ -1019,14 +953,11 @@ private ConstraintMatcher createOrMatcher(ParseUser u public Task matchesAsync(final T object, final ParseSQLiteDatabase db) { Task task = Task.forResult(false); for (final ConstraintMatcher matcher : matchers) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.getResult()) { - return task; - } - return matcher.matchesAsync(object, db); + task = task.onSuccessTask(task1 -> { + if (task1.getResult()) { + return task1; } + return matcher.matchesAsync(object, db); }); } return task; @@ -1107,14 +1038,11 @@ public Task matchesAsync(T object, ParseSQLiteDatabase db) { public Task matchesAsync(final T object, final ParseSQLiteDatabase db) { Task task = Task.forResult(true); for (final ConstraintMatcher matcher : matchers) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - if (!task.getResult()) { - return task; - } - return matcher.matchesAsync(object, db); + task = task.onSuccessTask(task1 -> { + if (!task1.getResult()) { + return task1; } + return matcher.matchesAsync(object, db); }); } return task; @@ -1161,7 +1089,7 @@ private interface Decider { * as $inQuery) are much more efficient if we can do some preprocessing. This makes some parts of * the query matching stateful. */ - /* package */ abstract class ConstraintMatcher { + /* package */ abstract static class ConstraintMatcher { /* package */ final ParseUser user; @@ -1193,12 +1121,7 @@ public Task matchesAsync(final T object, ParseSQLiteDatabase db) { // query on. subQueryResults = store.findAsync(subQuery, user, null, db); } - return subQueryResults.onSuccess(new Continuation, Boolean>() { - @Override - public Boolean then(Task> task) throws ParseException { - return matches(object, task.getResult()); - } - }); + return subQueryResults.onSuccess(task -> matches(object, task.getResult())); } protected abstract boolean matches(T object, List results) throws ParseException; diff --git a/parse/src/main/java/com/parse/OfflineStore.java b/parse/src/main/java/com/parse/OfflineStore.java index 1dd23be15..465144f78 100644 --- a/parse/src/main/java/com/parse/OfflineStore.java +++ b/parse/src/main/java/com/parse/OfflineStore.java @@ -16,6 +16,10 @@ import android.util.Pair; import com.parse.OfflineQueryLogic.ConstraintMatcher; +import com.parse.boltsinternal.Capture; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; import org.json.JSONException; import org.json.JSONObject; @@ -28,11 +32,6 @@ import java.util.UUID; import java.util.WeakHashMap; -import com.parse.boltsinternal.Capture; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - class OfflineStore { /** @@ -97,12 +96,7 @@ private Task getOrCreateUUIDAsync(final ParseObject object, ParseSQLiteD // The object doesn't have a UUID yet, so we're gonna have to make one. objectToUuidMap.put(object, tcs.getTask()); uuidToObjectMap.put(newUUID, object); - fetchedObjects.put(object, tcs.getTask().onSuccess(new Continuation() { - @Override - public ParseObject then(Task task) { - return object; - } - })); + fetchedObjects.put(object, tcs.getTask().onSuccess(task -> object)); } /* @@ -114,13 +108,10 @@ public ParseObject then(Task task) { values.put(OfflineSQLiteOpenHelper.KEY_UUID, newUUID); values.put(OfflineSQLiteOpenHelper.KEY_CLASS_NAME, object.getClassName()); db.insertOrThrowAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, values).continueWith( - new Continuation() { - @Override - public Void then(Task task) { - // This will signal that the UUID does represent a row in the database. - tcs.setResult(newUUID); - return null; - } + (Continuation) task -> { + // This will signal that the UUID does represent a row in the database. + tcs.setResult(newUUID); + return null; }); return tcs.getTask(); @@ -155,42 +146,39 @@ private Task getPointerAsync(final String uuid, String where = OfflineSQLiteOpenHelper.KEY_UUID + " = ?"; String[] args = {uuid}; return db.queryAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, select, where, args).onSuccess( - new Continuation() { - @Override - public T then(Task task) { - Cursor cursor = task.getResult(); - cursor.moveToFirst(); - if (cursor.isAfterLast()) { - cursor.close(); - throw new IllegalStateException("Attempted to find non-existent uuid " + uuid); + task -> { + Cursor cursor = task.getResult(); + cursor.moveToFirst(); + if (cursor.isAfterLast()) { + cursor.close(); + throw new IllegalStateException("Attempted to find non-existent uuid " + uuid); + } + + synchronized (lock) { + // We need to check again since another task might have come around and added it to + // the map. + //TODO (grantland): Maybe we should insert a Task that is resolved when the query + // completes like we do in getOrCreateUUIDAsync? + @SuppressWarnings("unchecked") + T existing = (T) uuidToObjectMap.get(uuid); + if (existing != null) { + return existing; } - synchronized (lock) { - // We need to check again since another task might have come around and added it to - // the map. - //TODO (grantland): Maybe we should insert a Task that is resolved when the query - // completes like we do in getOrCreateUUIDAsync? - @SuppressWarnings("unchecked") - T existing = (T) uuidToObjectMap.get(uuid); - if (existing != null) { - return existing; - } - - String className = cursor.getString(0); - String objectId = cursor.getString(1); - cursor.close(); - @SuppressWarnings("unchecked") - T pointer = (T) ParseObject.createWithoutData(className, objectId); - /* - * If it doesn't have an objectId, we don't really need the UUID, and this simplifies - * some other logic elsewhere if we only update the map for new objects. - */ - if (objectId == null) { - uuidToObjectMap.put(uuid, pointer); - objectToUuidMap.put(pointer, Task.forResult(uuid)); - } - return pointer; + String className = cursor.getString(0); + String objectId = cursor.getString(1); + cursor.close(); + @SuppressWarnings("unchecked") + T pointer = (T) ParseObject.createWithoutData(className, objectId); + /* + * If it doesn't have an objectId, we don't really need the UUID, and this simplifies + * some other logic elsewhere if we only update the map for new objects. + */ + if (objectId == null) { + uuidToObjectMap.put(uuid, pointer); + objectToUuidMap.put(pointer, Task.forResult(uuid)); } + return pointer; } }); } @@ -255,115 +243,82 @@ private Task> findAsync( return Task.forResult(results); } - queryTask = uuidTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String uuid = task.getResult(); - - String table = OfflineSQLiteOpenHelper.TABLE_OBJECTS + " A " + - " INNER JOIN " + OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES + " B " + - " ON A." + OfflineSQLiteOpenHelper.KEY_UUID + "=B." + OfflineSQLiteOpenHelper.KEY_UUID; - String[] select = {"A." + OfflineSQLiteOpenHelper.KEY_UUID}; - String where = OfflineSQLiteOpenHelper.KEY_CLASS_NAME + "=?" + - " AND " + OfflineSQLiteOpenHelper.KEY_KEY + "=?"; - if (!includeIsDeletingEventually) { - where += " AND " + OfflineSQLiteOpenHelper.KEY_IS_DELETING_EVENTUALLY + "=0"; - } - String[] args = {query.className(), uuid}; + queryTask = uuidTask.onSuccessTask(task -> { + String uuid = task.getResult(); - return db.queryAsync(table, select, where, args); + String table = OfflineSQLiteOpenHelper.TABLE_OBJECTS + " A " + + " INNER JOIN " + OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES + " B " + + " ON A." + OfflineSQLiteOpenHelper.KEY_UUID + "=B." + OfflineSQLiteOpenHelper.KEY_UUID; + String[] select = {"A." + OfflineSQLiteOpenHelper.KEY_UUID}; + String where = OfflineSQLiteOpenHelper.KEY_CLASS_NAME + "=?" + + " AND " + OfflineSQLiteOpenHelper.KEY_KEY + "=?"; + if (!includeIsDeletingEventually) { + where += " AND " + OfflineSQLiteOpenHelper.KEY_IS_DELETING_EVENTUALLY + "=0"; } + String[] args = {query.className(), uuid}; + + return db.queryAsync(table, select, where, args); }); } - return queryTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - Cursor cursor = task.getResult(); - List uuids = new ArrayList<>(); - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - uuids.add(cursor.getString(0)); - } - cursor.close(); - - // Find objects that match the where clause. - final ConstraintMatcher matcher = queryLogic.createMatcher(query, user); + return queryTask.onSuccessTask(task -> { + Cursor cursor = task.getResult(); + List uuids = new ArrayList<>(); + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + uuids.add(cursor.getString(0)); + } + cursor.close(); - Task checkedAllObjects = Task.forResult(null); - for (final String uuid : uuids) { - final Capture object = new Capture<>(); + // Find objects that match the where clause. + final ConstraintMatcher matcher = queryLogic.createMatcher(query, user); - checkedAllObjects = checkedAllObjects.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return getPointerAsync(uuid, db); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - object.set(task.getResult()); - return fetchLocallyAsync(object.get(), db); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - if (!object.get().isDataAvailable()) { - return Task.forResult(false); - } - return matcher.matchesAsync(object.get(), db); - } - }).onSuccess(new Continuation() { - @Override - public Void then(Task task) { - if (task.getResult()) { - results.add(object.get()); - } - return null; - } - }); - } + Task checkedAllObjects = Task.forResult(null); + for (final String uuid : uuids) { + final Capture object = new Capture<>(); - return checkedAllObjects; + checkedAllObjects = checkedAllObjects.onSuccessTask((Continuation>) task16 -> getPointerAsync(uuid, db)).onSuccessTask(task15 -> { + object.set(task15.getResult()); + return fetchLocallyAsync(object.get(), db); + }).onSuccessTask(task14 -> { + if (!object.get().isDataAvailable()) { + return Task.forResult(false); + } + return matcher.matchesAsync(object.get(), db); + }).onSuccess(task13 -> { + if (task13.getResult()) { + results.add(object.get()); + } + return null; + }); } - }).onSuccessTask(new Continuation>>() { - @Override - public Task> then(Task task) throws Exception { - // Sort by any sort operators. - OfflineQueryLogic.sort(results, query); - - // Apply the skip. - List trimmedResults = results; - int skip = query.skip(); - if (!isCount && skip >= 0) { - skip = Math.min(query.skip(), trimmedResults.size()); - trimmedResults = trimmedResults.subList(skip, trimmedResults.size()); - } - // Trim to the limit. - int limit = query.limit(); - if (!isCount && limit >= 0 && trimmedResults.size() > limit) { - trimmedResults = trimmedResults.subList(0, limit); - } + return checkedAllObjects; + }).onSuccessTask(task -> { + // Sort by any sort operators. + OfflineQueryLogic.sort(results, query); + + // Apply the skip. + List trimmedResults = results; + int skip = query.skip(); + if (!isCount && skip >= 0) { + skip = Math.min(query.skip(), trimmedResults.size()); + trimmedResults = trimmedResults.subList(skip, trimmedResults.size()); + } - // Fetch the includes. - Task fetchedIncludesTask = Task.forResult(null); - for (final T object : trimmedResults) { - fetchedIncludesTask = fetchedIncludesTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return OfflineQueryLogic.fetchIncludesAsync(OfflineStore.this, object, query, db); - } - }); - } + // Trim to the limit. + int limit = query.limit(); + if (!isCount && limit >= 0 && trimmedResults.size() > limit) { + trimmedResults = trimmedResults.subList(0, limit); + } - final List finalTrimmedResults = trimmedResults; - return fetchedIncludesTask.onSuccess(new Continuation>() { - @Override - public List then(Task task) { - return finalTrimmedResults; - } - }); + // Fetch the includes. + Task fetchedIncludesTask = Task.forResult(null); + for (final T object : trimmedResults) { + fetchedIncludesTask = fetchedIncludesTask.onSuccessTask(task12 -> OfflineQueryLogic.fetchIncludesAsync(OfflineStore.this, object, query, db)); } + + final List finalTrimmedResults = trimmedResults; + return fetchedIncludesTask.onSuccess(task1 -> finalTrimmedResults); }); } @@ -429,27 +384,21 @@ public List then(Task task) { final String[] select = {OfflineSQLiteOpenHelper.KEY_JSON}; final String where = OfflineSQLiteOpenHelper.KEY_UUID + " = ?"; final Capture uuid = new Capture<>(); - jsonStringTask = uuidTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - uuid.set(task.getResult()); - String[] args = {uuid.get()}; - return db.queryAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, select, where, args); - } - }).onSuccess(new Continuation() { - @Override - public String then(Task task) { - Cursor cursor = task.getResult(); - cursor.moveToFirst(); - if (cursor.isAfterLast()) { - cursor.close(); - throw new IllegalStateException("Attempted to find non-existent uuid " + uuid.get()); - } - String json = cursor.getString(0); + jsonStringTask = uuidTask.onSuccessTask(task -> { + uuid.set(task.getResult()); + String[] args = {uuid.get()}; + return db.queryAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, select, where, args); + }).onSuccess(task -> { + Cursor cursor = task.getResult(); + cursor.moveToFirst(); + if (cursor.isAfterLast()) { cursor.close(); - - return json; + throw new IllegalStateException("Attempted to find non-existent uuid " + uuid.get()); } + String json = cursor.getString(0); + cursor.close(); + + return json; }); } } else { @@ -480,102 +429,90 @@ public String then(Task task) { String[] args = {className, objectId}; jsonStringTask = db.queryAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, select, where, args).onSuccess( - new Continuation() { - @Override - public String then(Task task) throws Exception { - Cursor cursor = task.getResult(); - cursor.moveToFirst(); - if (cursor.isAfterLast()) { - /* - * This is a pointer that came from Parse that references an object that has - * never been saved in the offline store before. This just means there's no data - * in the store that needs to be merged into the object. - */ - cursor.close(); - throw new ParseException(ParseException.CACHE_MISS, - "This object is not available in the offline cache."); - } - - // we should fetch its data and record its UUID for future reference. - String jsonString = cursor.getString(0); - String newUUID = cursor.getString(1); + task -> { + Cursor cursor = task.getResult(); + cursor.moveToFirst(); + if (cursor.isAfterLast()) { + /* + * This is a pointer that came from Parse that references an object that has + * never been saved in the offline store before. This just means there's no data + * in the store that needs to be merged into the object. + */ cursor.close(); + throw new ParseException(ParseException.CACHE_MISS, + "This object is not available in the offline cache."); + } - synchronized (lock) { - /* - * It's okay to put this object into the uuid map. No one will try to fetch - * it, because it's already in the fetchedObjects map. And no one will try to - * save to it without fetching it first, so everything should be just fine. - */ - objectToUuidMap.put(object, Task.forResult(newUUID)); - uuidToObjectMap.put(newUUID, object); - } - - return jsonString; + // we should fetch its data and record its UUID for future reference. + String jsonString = cursor.getString(0); + String newUUID = cursor.getString(1); + cursor.close(); + + synchronized (lock) { + /* + * It's okay to put this object into the uuid map. No one will try to fetch + * it, because it's already in the fetchedObjects map. And no one will try to + * save to it without fetching it first, so everything should be just fine. + */ + objectToUuidMap.put(object, Task.forResult(newUUID)); + uuidToObjectMap.put(newUUID, object); } + + return jsonString; }); } - return jsonStringTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String jsonString = task.getResult(); - if (jsonString == null) { - /* - * This means we tried to fetch an object from the database that was never actually saved - * locally. This probably means that its parent object was saved locally and we just - * created a pointer to this object. This should be considered a cache miss. - */ - return Task.forError(new ParseException(ParseException.CACHE_MISS, - "Attempted to fetch an object offline which was never saved to the offline cache.")); - } - final JSONObject json; - try { - /* - * We can assume that whatever is in the database is the last known server state. The only - * things to maintain from the in-memory object are any changes since the object was last - * put in the database. - */ - json = new JSONObject(jsonString); - } catch (JSONException e) { - return Task.forError(e); - } - - // Fetch all the offline objects before we decode. - final Map> offlineObjects = new HashMap<>(); + return jsonStringTask.onSuccessTask((Continuation>) task -> { + String jsonString = task.getResult(); + if (jsonString == null) { + /* + * This means we tried to fetch an object from the database that was never actually saved + * locally. This probably means that its parent object was saved locally and we just + * created a pointer to this object. This should be considered a cache miss. + */ + return Task.forError(new ParseException(ParseException.CACHE_MISS, + "Attempted to fetch an object offline which was never saved to the offline cache.")); + } + final JSONObject json; + try { + /* + * We can assume that whatever is in the database is the last known server state. The only + * things to maintain from the in-memory object are any changes since the object was last + * put in the database. + */ + json = new JSONObject(jsonString); + } catch (JSONException e) { + return Task.forError(e); + } - (new ParseTraverser() { - @Override - protected boolean visit(Object object) { - if (object instanceof JSONObject - && ((JSONObject) object).optString("__type").equals("OfflineObject")) { - String uuid = ((JSONObject) object).optString("uuid"); - offlineObjects.put(uuid, getPointerAsync(uuid, db)); - } - return true; - } - }).setTraverseParseObjects(false).setYieldRoot(false).traverse(json); + // Fetch all the offline objects before we decode. + final Map> offlineObjects = new HashMap<>(); - return Task.whenAll(offlineObjects.values()).onSuccess(new Continuation() { - @Override - public Void then(Task task) { - object.mergeREST(object.getState(), json, new OfflineDecoder(offlineObjects)); - return null; + (new ParseTraverser() { + @Override + protected boolean visit(Object object1) { + if (object1 instanceof JSONObject + && ((JSONObject) object1).optString("__type").equals("OfflineObject")) { + String uuid = ((JSONObject) object1).optString("uuid"); + offlineObjects.put(uuid, getPointerAsync(uuid, db)); } - }); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isCancelled()) { - tcs.setCancelled(); - } else if (task.isFaulted()) { - tcs.setError(task.getError()); - } else { - tcs.setResult(object); + return true; } - return tcs.getTask(); + }).setTraverseParseObjects(false).setYieldRoot(false).traverse(json); + + return Task.whenAll(offlineObjects.values()).onSuccess(task1 -> { + object.mergeREST(object.getState(), json, new OfflineDecoder(offlineObjects)); + return null; + }); + }).continueWithTask(task -> { + if (task.isCancelled()) { + tcs.setCancelled(); + } else if (task.isFaulted()) { + tcs.setError(task.getError()); + } else { + tcs.setResult(object); } + return tcs.getTask(); }); } @@ -587,12 +524,7 @@ public Task then(Task task) { * @param object The object to fetch. */ /* package */ Task fetchLocallyAsync(final T object) { - return runWithManagedConnection(new SQLiteDatabaseCallable>() { - @Override - public Task call(ParseSQLiteDatabase db) { - return fetchLocallyAsync(object, db); - } - }); + return runWithManagedConnection(db -> fetchLocallyAsync(object, db)); } /** @@ -613,22 +545,16 @@ private Task saveLocallyAsync( final Capture uuidCapture = new Capture<>(); // Make sure we have a UUID for the object to be saved. - return getOrCreateUUIDAsync(object, db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String uuid = task.getResult(); - uuidCapture.set(uuid); - return updateDataForObjectAsync(uuid, object, db); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ContentValues values = new ContentValues(); - values.put(OfflineSQLiteOpenHelper.KEY_KEY, key); - values.put(OfflineSQLiteOpenHelper.KEY_UUID, uuidCapture.get()); - return db.insertWithOnConflict(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, values, - SQLiteDatabase.CONFLICT_IGNORE); - } + return getOrCreateUUIDAsync(object, db).onSuccessTask(task -> { + String uuid = task.getResult(); + uuidCapture.set(uuid); + return updateDataForObjectAsync(uuid, object, db); + }).onSuccessTask(task -> { + final ContentValues values = new ContentValues(); + values.put(OfflineSQLiteOpenHelper.KEY_KEY, key); + values.put(OfflineSQLiteOpenHelper.KEY_UUID, uuidCapture.get()); + return db.insertWithOnConflict(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, values, + SQLiteDatabase.CONFLICT_IGNORE); }); } @@ -673,7 +599,7 @@ private Task saveLocallyAsync( final ParseObject object, List children, final ParseSQLiteDatabase db) { final List objects = children != null ? new ArrayList<>(children) - : new ArrayList(); + : new ArrayList<>(); if (!objects.contains(object)) { objects.add(object); } @@ -684,42 +610,26 @@ private Task saveLocallyAsync( tasks.add(fetchLocallyAsync(obj, db).makeVoid()); } - return Task.whenAll(tasks).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return objectToUuidMap.get(object); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String uuid = task.getResult(); - if (uuid == null) { - // The root object was never stored in the offline store, so nothing to unpin. - return null; - } - - // Delete all objects locally corresponding to the key we're trying to use in case it was - // used before (overwrite) - return unpinAsync(uuid, db); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return getOrCreateUUIDAsync(object, db); + return Task.whenAll(tasks).continueWithTask(task -> objectToUuidMap.get(object)).onSuccessTask(task -> { + String uuid = task.getResult(); + if (uuid == null) { + // The root object was never stored in the offline store, so nothing to unpin. + return null; } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String uuid = task.getResult(); - // Call saveLocallyAsync for each of them individually. - final List> tasks = new ArrayList<>(); - for (ParseObject obj : objects) { - tasks.add(saveLocallyAsync(uuid, obj, db)); - } + // Delete all objects locally corresponding to the key we're trying to use in case it was + // used before (overwrite) + return unpinAsync(uuid, db); + }).onSuccessTask(task -> getOrCreateUUIDAsync(object, db)).onSuccessTask(task -> { + String uuid = task.getResult(); - return Task.whenAll(tasks); + // Call saveLocallyAsync for each of them individually. + final List> tasks1 = new ArrayList<>(); + for (ParseObject obj : objects) { + tasks1.add(saveLocallyAsync(uuid, obj, db)); } + + return Task.whenAll(tasks1); }); } @@ -729,71 +639,56 @@ private Task unpinAsync(final ParseObject object, final ParseSQLiteDatabas // The root object was never stored in the offline store, so nothing to unpin. return Task.forResult(null); } - return uuidTask.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - final String uuid = task.getResult(); - if (uuid == null) { - // The root object was never stored in the offline store, so nothing to unpin. - return Task.forResult(null); - } - return unpinAsync(uuid, db); + return uuidTask.continueWithTask(task -> { + final String uuid = task.getResult(); + if (uuid == null) { + // The root object was never stored in the offline store, so nothing to unpin. + return Task.forResult(null); } + return unpinAsync(uuid, db); }); } private Task unpinAsync(final String key, final ParseSQLiteDatabase db) { final List uuidsToDelete = new LinkedList<>(); // A continueWithTask that ends with "return task" is essentially a try-finally. - return Task.forResult((Void) null).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // Fetch all uuids from Dependencies for key=? grouped by uuid having a count of 1 - String sql = "SELECT " + OfflineSQLiteOpenHelper.KEY_UUID + " FROM " + OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES + - " WHERE " + OfflineSQLiteOpenHelper.KEY_KEY + "=? AND " + OfflineSQLiteOpenHelper.KEY_UUID + " IN (" + - " SELECT " + OfflineSQLiteOpenHelper.KEY_UUID + " FROM " + OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES + - " GROUP BY " + OfflineSQLiteOpenHelper.KEY_UUID + - " HAVING COUNT(" + OfflineSQLiteOpenHelper.KEY_UUID + ")=1" + - ")"; - String[] args = {key}; - return db.rawQueryAsync(sql, args); + return Task.forResult((Void) null).continueWithTask(task -> { + // Fetch all uuids from Dependencies for key=? grouped by uuid having a count of 1 + String sql = "SELECT " + OfflineSQLiteOpenHelper.KEY_UUID + " FROM " + OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES + + " WHERE " + OfflineSQLiteOpenHelper.KEY_KEY + "=? AND " + OfflineSQLiteOpenHelper.KEY_UUID + " IN (" + + " SELECT " + OfflineSQLiteOpenHelper.KEY_UUID + " FROM " + OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES + + " GROUP BY " + OfflineSQLiteOpenHelper.KEY_UUID + + " HAVING COUNT(" + OfflineSQLiteOpenHelper.KEY_UUID + ")=1" + + ")"; + String[] args = {key}; + return db.rawQueryAsync(sql, args); + }).onSuccessTask(task -> { + // DELETE FROM Objects + + Cursor cursor = task.getResult(); + while (cursor.moveToNext()) { + uuidsToDelete.add(cursor.getString(0)); } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - // DELETE FROM Objects - - Cursor cursor = task.getResult(); - while (cursor.moveToNext()) { - uuidsToDelete.add(cursor.getString(0)); - } - cursor.close(); - - return deleteObjects(uuidsToDelete, db); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - // DELETE FROM Dependencies - String where = OfflineSQLiteOpenHelper.KEY_KEY + "=?"; - String[] args = {key}; - return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, where, args); - } - }).onSuccess(new Continuation() { - @Override - public Void then(Task task) { - synchronized (lock) { - // Remove uuids from memory - for (String uuid : uuidsToDelete) { - ParseObject object = uuidToObjectMap.get(uuid); - if (object != null) { - objectToUuidMap.remove(object); - uuidToObjectMap.remove(uuid); - } + cursor.close(); + + return deleteObjects(uuidsToDelete, db); + }).onSuccessTask(task -> { + // DELETE FROM Dependencies + String where = OfflineSQLiteOpenHelper.KEY_KEY + "=?"; + String[] args = {key}; + return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, where, args); + }).onSuccess(task -> { + synchronized (lock) { + // Remove uuids from memory + for (String uuid : uuidsToDelete) { + ParseObject object = uuidToObjectMap.get(uuid); + if (object != null) { + objectToUuidMap.remove(object); + uuidToObjectMap.remove(uuid); } } - return null; } + return null; }); } @@ -805,12 +700,7 @@ private Task deleteObjects(final List uuids, final ParseSQLiteData // SQLite has a max 999 SQL variables in a statement, so we need to split it up into manageable // chunks. We can do this because we're already in a transaction. if (uuids.size() > MAX_SQL_VARIABLES) { - return deleteObjects(uuids.subList(0, MAX_SQL_VARIABLES), db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return deleteObjects(uuids.subList(MAX_SQL_VARIABLES, uuids.size()), db); - } - }); + return deleteObjects(uuids.subList(0, MAX_SQL_VARIABLES), db).onSuccessTask(task -> deleteObjects(uuids.subList(MAX_SQL_VARIABLES, uuids.size()), db)); } String[] placeholders = new String[uuids.size()]; @@ -819,7 +709,7 @@ public Task then(Task task) { } String where = OfflineSQLiteOpenHelper.KEY_UUID + " IN (" + TextUtils.join(",", placeholders) + ")"; // dynamic args - String[] args = uuids.toArray(new String[uuids.size()]); + String[] args = uuids.toArray(new String[0]); return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, where, args); } @@ -838,45 +728,28 @@ public Task then(Task task) { "An object cannot be updated if it wasn't fetched.")); } } - return fetched.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isFaulted()) { - // Catch CACHE_MISS - //noinspection ThrowableResultOfMethodCallIgnored - if (task.getError() instanceof ParseException - && ((ParseException) task.getError()).getCode() == ParseException.CACHE_MISS) { - return Task.forResult(null); - } - return task.makeVoid(); + return fetched.continueWithTask(task -> { + if (task.isFaulted()) { + // Catch CACHE_MISS + //noinspection ThrowableResultOfMethodCallIgnored + if (task.getError() instanceof ParseException + && ((ParseException) task.getError()).getCode() == ParseException.CACHE_MISS) { + return Task.forResult(null); } + return task.makeVoid(); + } - return helper.getWritableDatabaseAsync().continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseSQLiteDatabase db = task.getResult(); - return db.beginTransactionAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return updateDataForObjectAsync(object, db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return db.setTransactionSuccessfulAsync(); - } - }).continueWithTask(new Continuation>() { - // } finally { - @Override - public Task then(Task task) { - db.endTransactionAsync(); - db.closeAsync(); - return task; - } - }); - } - }); - } + return helper.getWritableDatabaseAsync().continueWithTask(task14 -> { + final ParseSQLiteDatabase db = task14.getResult(); + return db.beginTransactionAsync().onSuccessTask(task13 -> { + // } finally { + return updateDataForObjectAsync(object, db).onSuccessTask(task12 -> db.setTransactionSuccessfulAsync()).continueWithTask(task1 -> { + db.endTransactionAsync(); + db.closeAsync(); + return task1; + }); }); - } + }); }); } @@ -892,12 +765,9 @@ private Task updateDataForObjectAsync( return Task.forResult(null); } } - return uuidTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String uuid = task.getResult(); - return updateDataForObjectAsync(uuid, object, db); - } + return uuidTask.onSuccessTask(task -> { + String uuid = task.getResult(); + return updateDataForObjectAsync(uuid, object, db); }); } @@ -909,53 +779,36 @@ private Task updateDataForObjectAsync( OfflineEncoder encoder = new OfflineEncoder(db); final JSONObject json = object.toRest(encoder); - return encoder.whenFinished().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - // Put the JSON in the database. - String className = object.getClassName(); - String objectId = object.getObjectId(); - int isDeletingEventually = json.getInt(ParseObject.KEY_IS_DELETING_EVENTUALLY); - - final ContentValues values = new ContentValues(); - values.put(OfflineSQLiteOpenHelper.KEY_CLASS_NAME, className); - values.put(OfflineSQLiteOpenHelper.KEY_JSON, json.toString()); - if (objectId != null) { - values.put(OfflineSQLiteOpenHelper.KEY_OBJECT_ID, objectId); - } - values.put(OfflineSQLiteOpenHelper.KEY_IS_DELETING_EVENTUALLY, isDeletingEventually); - String where = OfflineSQLiteOpenHelper.KEY_UUID + " = ?"; - String[] args = {uuid}; - return db.updateAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, values, where, args).makeVoid(); + return encoder.whenFinished().onSuccessTask(task -> { + // Put the JSON in the database. + String className = object.getClassName(); + String objectId = object.getObjectId(); + int isDeletingEventually = json.getInt(ParseObject.KEY_IS_DELETING_EVENTUALLY); + + final ContentValues values = new ContentValues(); + values.put(OfflineSQLiteOpenHelper.KEY_CLASS_NAME, className); + values.put(OfflineSQLiteOpenHelper.KEY_JSON, json.toString()); + if (objectId != null) { + values.put(OfflineSQLiteOpenHelper.KEY_OBJECT_ID, objectId); } + values.put(OfflineSQLiteOpenHelper.KEY_IS_DELETING_EVENTUALLY, isDeletingEventually); + String where = OfflineSQLiteOpenHelper.KEY_UUID + " = ?"; + String[] args = {uuid}; + return db.updateAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, values, where, args).makeVoid(); }); } /* package */ Task deleteDataForObjectAsync(final ParseObject object) { - return helper.getWritableDatabaseAsync().continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseSQLiteDatabase db = task.getResult(); - return db.beginTransactionAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return deleteDataForObjectAsync(object, db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return db.setTransactionSuccessfulAsync(); - } - }).continueWithTask(new Continuation>() { - // } finally { - @Override - public Task then(Task task) { - db.endTransactionAsync(); - db.closeAsync(); - return task; - } - }); - } + return helper.getWritableDatabaseAsync().continueWithTask(task -> { + final ParseSQLiteDatabase db = task.getResult(); + return db.beginTransactionAsync().onSuccessTask(task13 -> { + // } finally { + return deleteDataForObjectAsync(object, db).onSuccessTask(task12 -> db.setTransactionSuccessfulAsync()).continueWithTask(task1 -> { + db.endTransactionAsync(); + db.closeAsync(); + return task1; }); - } + }); }); } @@ -971,95 +824,71 @@ private Task deleteDataForObjectAsync(final ParseObject object, final Pars return Task.forResult(null); } } - uuidTask = uuidTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - uuid.set(task.getResult()); - return task; - } + uuidTask = uuidTask.onSuccessTask(task -> { + uuid.set(task.getResult()); + return task; }); // If the object was the root of a pin, unpin it. - Task unpinTask = uuidTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - // Find all the roots for this object. - String[] select = {OfflineSQLiteOpenHelper.KEY_KEY}; - String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?"; - String[] args = {uuid.get()}; - return db.queryAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, select, where, args); + Task unpinTask = uuidTask.onSuccessTask(task -> { + // Find all the roots for this object. + String[] select = {OfflineSQLiteOpenHelper.KEY_KEY}; + String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?"; + String[] args = {uuid.get()}; + return db.queryAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, select, where, args); + }).onSuccessTask(task -> { + // Try to unpin this object from the pin label if it's a root of the ParsePin. + Cursor cursor = task.getResult(); + List uuids = new ArrayList<>(); + for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { + uuids.add(cursor.getString(0)); } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - // Try to unpin this object from the pin label if it's a root of the ParsePin. - Cursor cursor = task.getResult(); - List uuids = new ArrayList<>(); - for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { - uuids.add(cursor.getString(0)); - } - cursor.close(); - - List> tasks = new ArrayList<>(); - for (final String uuid : uuids) { - Task unpinTask = getPointerAsync(uuid, db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParsePin pin = (ParsePin) task.getResult(); - return fetchLocallyAsync(pin, db); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - ParsePin pin = task.getResult(); - - List modified = pin.getObjects(); - if (modified == null || !modified.contains(object)) { - return task.makeVoid(); - } - - modified.remove(object); - if (modified.size() == 0) { - return unpinAsync(uuid, db); - } - - pin.setObjects(modified); - return saveLocallyAsync(pin, true, db); - } - }); - tasks.add(unpinTask); - } + cursor.close(); + + List> tasks = new ArrayList<>(); + for (final String uuid1 : uuids) { + Task unpinTask1 = getPointerAsync(uuid1, db).onSuccessTask(task12 -> { + ParsePin pin = (ParsePin) task12.getResult(); + return fetchLocallyAsync(pin, db); + }).continueWithTask(task1 -> { + ParsePin pin = task1.getResult(); + + List modified = pin.getObjects(); + if (modified == null || !modified.contains(object)) { + return task1.makeVoid(); + } - return Task.whenAll(tasks); + modified.remove(object); + if (modified.size() == 0) { + return unpinAsync(uuid1, db); + } + + pin.setObjects(modified); + return saveLocallyAsync(pin, true, db); + }); + tasks.add(unpinTask1); } + + return Task.whenAll(tasks); }); // Delete the object from the Local Datastore in case it wasn't the root of a pin. - return unpinTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?"; - String[] args = {uuid.get()}; - return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, where, args); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?"; - String[] args = {uuid.get()}; - return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, where, args); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (lock) { - // Clean up - //TODO (grantland): we should probably clean up uuidToObjectMap and objectToUuidMap, but - // getting the uuid requires a task and things might get a little funky... - fetchedObjects.remove(object); - } - return task; + return unpinTask.onSuccessTask(task -> { + String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?"; + String[] args = {uuid.get()}; + return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, where, args); + }).onSuccessTask(task -> { + String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?"; + String[] args = {uuid.get()}; + return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, where, args); + }).onSuccessTask(task -> { + synchronized (lock) { + // Clean up + //TODO (grantland): we should probably clean up uuidToObjectMap and objectToUuidMap, but + // getting the uuid requires a task and things might get a little funky... + fetchedObjects.remove(object); } + return task; }); } @@ -1071,22 +900,19 @@ private Task getParsePin(final String name, ParseSQLiteDatabase db) { /* We need to call directly to the OfflineStore since we don't want/need a user to query for * ParsePins */ - return findAsync(query, null, null, db).onSuccess(new Continuation, ParsePin>() { - @Override - public ParsePin then(Task> task) { - ParsePin pin = null; - if (task.getResult() != null && task.getResult().size() > 0) { - pin = task.getResult().get(0); - } + return findAsync(query, null, null, db).onSuccess(task -> { + ParsePin pin = null; + if (task.getResult() != null && task.getResult().size() > 0) { + pin = task.getResult().get(0); + } - //TODO (grantland): What do we do if there are more than 1 result? + //TODO (grantland): What do we do if there are more than 1 result? - if (pin == null) { - pin = ParseObject.create(ParsePin.class); - pin.setName(name); - } - return pin; + if (pin == null) { + pin = ParseObject.create(ParsePin.class); + pin.setName(name); } + return pin; }); } @@ -1096,12 +922,7 @@ public ParsePin then(Task> task) { final String name, final List objects, final boolean includeChildren) { - return runWithManagedTransaction(new SQLiteDatabaseCallable>() { - @Override - public Task call(ParseSQLiteDatabase db) { - return pinAllObjectsAsync(name, objects, includeChildren, db); - } - }); + return runWithManagedTransaction(db -> pinAllObjectsAsync(name, objects, includeChildren, db)); } private Task pinAllObjectsAsync( @@ -1113,46 +934,38 @@ private Task pinAllObjectsAsync( return Task.forResult(null); } - return getParsePin(name, db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParsePin pin = task.getResult(); + return getParsePin(name, db).onSuccessTask(task -> { + ParsePin pin = task.getResult(); - //TODO (grantland): change to use relations. currently the related PO are only getting saved - // offline as pointers. + //TODO (grantland): change to use relations. currently the related PO are only getting saved + // offline as pointers. // ParseRelation relation = pin.getRelation(KEY_OBJECTS); // relation.add(object); - // Hack to store collections in a pin - List modified = pin.getObjects(); - if (modified == null) { - modified = new ArrayList(objects); - } else { - for (ParseObject object : objects) { - if (!modified.contains(object)) { - modified.add(object); - } + // Hack to store collections in a pin + List modified = pin.getObjects(); + if (modified == null) { + modified = new ArrayList<>(objects); + } else { + for (ParseObject object : objects) { + if (!modified.contains(object)) { + modified.add(object); } } - pin.setObjects(modified); + } + pin.setObjects(modified); - if (includeChildren) { - return saveLocallyAsync(pin, true, db); - } - return saveLocallyAsync(pin, pin.getObjects(), db); + if (includeChildren) { + return saveLocallyAsync(pin, true, db); } + return saveLocallyAsync(pin, pin.getObjects(), db); }); } /* package */ Task unpinAllObjectsAsync( final String name, final List objects) { - return runWithManagedTransaction(new SQLiteDatabaseCallable>() { - @Override - public Task call(ParseSQLiteDatabase db) { - return unpinAllObjectsAsync(name, objects, db); - } - }); + return runWithManagedTransaction(db -> unpinAllObjectsAsync(name, objects, db)); } private Task unpinAllObjectsAsync( @@ -1163,53 +976,42 @@ private Task unpinAllObjectsAsync( return Task.forResult(null); } - return getParsePin(name, db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParsePin pin = task.getResult(); + return getParsePin(name, db).onSuccessTask(task -> { + ParsePin pin = task.getResult(); - //TODO (grantland): change to use relations. currently the related PO are only getting saved - // offline as pointers. + //TODO (grantland): change to use relations. currently the related PO are only getting saved + // offline as pointers. // ParseRelation relation = pin.getRelation(KEY_OBJECTS); // relation.remove(object); - // Hack to store collections in a pin - List modified = pin.getObjects(); - if (modified == null) { - // Unpin a pin that doesn't exist. Wat? - return Task.forResult(null); - } - - modified.removeAll(objects); - if (modified.size() == 0) { - return unpinAsync(pin, db); - } - pin.setObjects(modified); + // Hack to store collections in a pin + List modified = pin.getObjects(); + if (modified == null) { + // Unpin a pin that doesn't exist. Wat? + return Task.forResult(null); + } - return saveLocallyAsync(pin, true, db); + modified.removeAll(objects); + if (modified.size() == 0) { + return unpinAsync(pin, db); } + pin.setObjects(modified); + + return saveLocallyAsync(pin, true, db); }); } /* package */ Task unpinAllObjectsAsync(final String name) { - return runWithManagedTransaction(new SQLiteDatabaseCallable>() { - @Override - public Task call(ParseSQLiteDatabase db) { - return unpinAllObjectsAsync(name, db); - } - }); + return runWithManagedTransaction(db -> unpinAllObjectsAsync(name, db)); } private Task unpinAllObjectsAsync(final String name, final ParseSQLiteDatabase db) { - return getParsePin(name, db).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isFaulted()) { - return task.makeVoid(); - } - ParsePin pin = task.getResult(); - return unpinAsync(pin, db); + return getParsePin(name, db).continueWithTask(task -> { + if (task.isFaulted()) { + return task.makeVoid(); } + ParsePin pin = task.getResult(); + return unpinAsync(pin, db); }); } @@ -1217,12 +1019,7 @@ public Task then(Task task) { final String name, final ParseQuery.State state, final ParseUser user) { - return runWithManagedConnection(new SQLiteDatabaseCallable>>() { - @Override - public Task> call(ParseSQLiteDatabase db) { - return findFromPinAsync(name, state, user, db); - } - }); + return runWithManagedConnection(db -> findFromPinAsync(name, state, user, db)); } private Task> findFromPinAsync( @@ -1236,12 +1033,9 @@ private Task> findFromPinAsync( } else { task = Task.forResult(null); } - return task.onSuccessTask(new Continuation>>() { - @Override - public Task> then(Task task) { - ParsePin pin = task.getResult(); - return findAsync(state, user, pin, false, db); - } + return task.onSuccessTask(task1 -> { + ParsePin pin = task1.getResult(); + return findAsync(state, user, pin, false, db); }); } @@ -1249,12 +1043,7 @@ public Task> then(Task task) { final String name, final ParseQuery.State state, final ParseUser user) { - return runWithManagedConnection(new SQLiteDatabaseCallable>() { - @Override - public Task call(ParseSQLiteDatabase db) { - return countFromPinAsync(name, state, user, db); - } - }); + return runWithManagedConnection(db -> countFromPinAsync(name, state, user, db)); } private Task countFromPinAsync( @@ -1268,17 +1057,9 @@ private Task countFromPinAsync( } else { task = Task.forResult(null); } - return task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParsePin pin = task.getResult(); - return findAsync(state, user, pin, true, db).onSuccess(new Continuation, Integer>() { - @Override - public Integer then(Task> task) { - return task.getResult().size(); - } - }); - } + return task.onSuccessTask(task12 -> { + ParsePin pin = task12.getResult(); + return findAsync(state, user, pin, true, db).onSuccess(task1 -> task1.getResult().size()); }); } @@ -1372,18 +1153,12 @@ public Integer then(Task> task) { * Wraps SQLite operations with a managed SQLite connection. */ private Task runWithManagedConnection(final SQLiteDatabaseCallable> callable) { - return helper.getWritableDatabaseAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseSQLiteDatabase db = task.getResult(); - return callable.call(db).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - db.closeAsync(); - return task; - } - }); - } + return helper.getWritableDatabaseAsync().onSuccessTask(task -> { + final ParseSQLiteDatabase db = task.getResult(); + return callable.call(db).continueWithTask(task1 -> { + db.closeAsync(); + return task1; + }); }); } @@ -1391,29 +1166,13 @@ public Task then(Task task) { * Wraps SQLite operations with a managed SQLite connection and transaction. */ private Task runWithManagedTransaction(final SQLiteDatabaseCallable> callable) { - return helper.getWritableDatabaseAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseSQLiteDatabase db = task.getResult(); - return db.beginTransactionAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return callable.call(db).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return db.setTransactionSuccessfulAsync(); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - db.endTransactionAsync(); - db.closeAsync(); - return task; - } - }); - } - }); - } + return helper.getWritableDatabaseAsync().onSuccessTask(task -> { + final ParseSQLiteDatabase db = task.getResult(); + return db.beginTransactionAsync().onSuccessTask(task13 -> callable.call(db).onSuccessTask(task12 -> db.setTransactionSuccessfulAsync()).continueWithTask(task1 -> { + db.endTransactionAsync(); + db.closeAsync(); + return task1; + })); }); } @@ -1450,10 +1209,10 @@ private interface SQLiteDatabaseCallable { * Extends the normal JSON -> ParseObject decoding to also deal with placeholders for new objects * that have been saved offline. */ - private class OfflineDecoder extends ParseDecoder { + private static class OfflineDecoder extends ParseDecoder { // A map of UUID -> Task that will be finished once the given ParseObject is loaded. // The Tasks should all be finished before decode is called. - private Map> offlineObjects; + private final Map> offlineObjects; private OfflineDecoder(Map> offlineObjects) { this.offlineObjects = offlineObjects; @@ -1483,8 +1242,8 @@ public Object decode(Object object) { */ private class OfflineEncoder extends ParseEncoder { private final Object tasksLock = new Object(); - private ParseSQLiteDatabase db; - private ArrayList> tasks = new ArrayList<>(); + private final ParseSQLiteDatabase db; + private final ArrayList> tasks = new ArrayList<>(); /** * Creates an encoder. @@ -1500,19 +1259,16 @@ public OfflineEncoder(ParseSQLiteDatabase db) { * by this method is finished. */ public Task whenFinished() { - return Task.whenAll(tasks).continueWithTask(new Continuation>() { - @Override - public Task then(Task ignore) { - synchronized (tasksLock) { - // It might be better to return an aggregate error here. - for (Task task : tasks) { - if (task.isFaulted() || task.isCancelled()) { - return task; - } + return Task.whenAll(tasks).continueWithTask(ignore -> { + synchronized (tasksLock) { + // It might be better to return an aggregate error here. + for (Task task : tasks) { + if (task.isFaulted() || task.isCancelled()) { + return task; } - tasks.clear(); - return Task.forResult(null); } + tasks.clear(); + return Task.forResult(null); } }); } @@ -1534,12 +1290,9 @@ public JSONObject encodeRelatedObject(ParseObject object) { final JSONObject result = new JSONObject(); result.put("__type", "OfflineObject"); synchronized (tasksLock) { - tasks.add(getOrCreateUUIDAsync(object, db).onSuccess(new Continuation() { - @Override - public Void then(Task task) throws Exception { - result.put("uuid", task.getResult()); - return null; - } + tasks.add(getOrCreateUUIDAsync(object, db).onSuccess(task -> { + result.put("uuid", task.getResult()); + return null; })); } return result; diff --git a/parse/src/main/java/com/parse/Parse.java b/parse/src/main/java/com/parse/Parse.java index 903d56722..c412978df 100644 --- a/parse/src/main/java/com/parse/Parse.java +++ b/parse/src/main/java/com/parse/Parse.java @@ -11,10 +11,13 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import android.util.Log; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; import java.io.File; import java.io.FileOutputStream; @@ -27,8 +30,6 @@ import java.util.Set; import java.util.concurrent.Callable; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; import okhttp3.OkHttpClient; /** @@ -160,12 +161,9 @@ static void initialize(Configuration configuration, ParsePlugins parsePlugins) { // application. checkCacheApplicationId(); final Context context = configuration.context; - Task.callInBackground(new Callable() { - @Override - public Void call() { - getEventuallyQueue(context); - return null; - } + Task.callInBackground((Callable) () -> { + getEventuallyQueue(context); + return null; }); ParseFieldOperations.registerDefaultDecoders(); @@ -177,13 +175,10 @@ public Void call() { "com.parse.push.intent.OPEN, com.parse.push.intent.DELETE"); } - ParseUser.getCurrentUserAsync().makeVoid().continueWith(new Continuation() { - @Override - public Void then(Task task) { - // Prime config in the background - ParseConfig.getCurrentConfig(); - return null; - } + ParseUser.getCurrentUserAsync().makeVoid().continueWith((Continuation) task -> { + // Prime config in the background + ParseConfig.getCurrentConfig(); + return null; }, Task.BACKGROUND_EXECUTOR); dispatchOnParseInitialized(); @@ -196,6 +191,15 @@ public Void then(Task task) { //region Server URL + /** + * Returns the current server URL. + */ + public static @Nullable + String getServer() { + URL server = ParseRESTCommand.server; + return server == null ? null : server.toString(); + } + /** * Sets the server URL. The local client cache is not cleared. *

@@ -207,6 +211,7 @@ public Void then(Task task) { * The new server URL must point to a Parse Server that connects to the same database. * Otherwise, issues may arise related to locally cached data or delayed methods such as * {@link ParseObject#saveEventually()}. + * * @param server The server URL to set. */ public static void setServer(@NonNull String server) { @@ -217,20 +222,14 @@ public static void setServer(@NonNull String server) { } } - /** - * Returns the current server URL. - */ - public static @Nullable String getServer() { - URL server = ParseRESTCommand.server; - return server == null ? null : server.toString(); - } - /** * Validates the server URL. + * * @param server The server URL to validate. * @return The validated server URL. */ - private static @Nullable String validateServerUrl(@Nullable String server) { + private static @Nullable + String validateServerUrl(@Nullable String server) { // Add an extra trailing slash so that Parse REST commands include // the path as part of the server URL (i.e. http://api.myhost.com/parse) @@ -567,6 +566,7 @@ public static final class Configuration { final boolean localDataStoreEnabled; final OkHttpClient.Builder clientBuilder; final int maxRetries; + private Configuration(Builder builder) { this.context = builder.context; this.applicationId = builder.applicationId; @@ -581,7 +581,7 @@ private Configuration(Builder builder) { * Allows for simple constructing of a {@code Configuration} object. */ public static final class Builder { - private Context context; + private final Context context; private String applicationId; private String clientKey; private String server; diff --git a/parse/src/main/java/com/parse/ParseACL.java b/parse/src/main/java/com/parse/ParseACL.java index b68d48a1b..74420a0bf 100644 --- a/parse/src/main/java/com/parse/ParseACL.java +++ b/parse/src/main/java/com/parse/ParseACL.java @@ -57,6 +57,7 @@ public ParseACL[] newArray(int size) { public ParseACL() { // do nothing } + /** * Creates a copy of {@code acl}. * diff --git a/parse/src/main/java/com/parse/ParseAnalytics.java b/parse/src/main/java/com/parse/ParseAnalytics.java index b153b46c7..04d76ca2f 100644 --- a/parse/src/main/java/com/parse/ParseAnalytics.java +++ b/parse/src/main/java/com/parse/ParseAnalytics.java @@ -10,6 +10,9 @@ import android.content.Intent; +import com.parse.boltsinternal.Capture; +import com.parse.boltsinternal.Task; + import org.json.JSONException; import org.json.JSONObject; @@ -18,10 +21,6 @@ import java.util.LinkedHashMap; import java.util.Map; -import com.parse.boltsinternal.Capture; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * The {@code ParseAnalytics} class provides an interface to Parse's logging and analytics backend. * Methods will return immediately and cache requests (+ timestamps) to be handled "eventually." @@ -66,12 +65,9 @@ public static Task trackAppOpenedInBackground(Intent intent) { } } } - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String sessionToken = task.getResult(); - return getAnalyticsController().trackAppOpenedInBackground(pushHash.get(), sessionToken); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + String sessionToken = task.getResult(); + return getAnalyticsController().trackAppOpenedInBackground(pushHash.get(), sessionToken); }); } @@ -171,12 +167,9 @@ public static Task trackEventInBackground(final String name, ? Collections.unmodifiableMap(new HashMap<>(dimensions)) : null; - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String sessionToken = task.getResult(); - return getAnalyticsController().trackEventInBackground(name, dimensionsCopy, sessionToken); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + String sessionToken = task.getResult(); + return getAnalyticsController().trackEventInBackground(name, dimensionsCopy, sessionToken); }); } diff --git a/parse/src/main/java/com/parse/ParseAnalyticsController.java b/parse/src/main/java/com/parse/ParseAnalyticsController.java index 61c180a23..5533779e7 100644 --- a/parse/src/main/java/com/parse/ParseAnalyticsController.java +++ b/parse/src/main/java/com/parse/ParseAnalyticsController.java @@ -8,15 +8,15 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import java.util.Map; -import com.parse.boltsinternal.Task; - class ParseAnalyticsController { - /* package for test */ ParseEventuallyQueue eventuallyQueue; + /* package for test */ final ParseEventuallyQueue eventuallyQueue; public ParseAnalyticsController(ParseEventuallyQueue eventuallyQueue) { this.eventuallyQueue = eventuallyQueue; diff --git a/parse/src/main/java/com/parse/ParseAnonymousUtils.java b/parse/src/main/java/com/parse/ParseAnonymousUtils.java index 10be8cc42..6634bbb73 100644 --- a/parse/src/main/java/com/parse/ParseAnonymousUtils.java +++ b/parse/src/main/java/com/parse/ParseAnonymousUtils.java @@ -8,12 +8,12 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import java.util.HashMap; import java.util.Map; import java.util.UUID; -import com.parse.boltsinternal.Task; - /** * Provides utility functions for working with Anonymously logged-in users. Anonymous users have * some unique characteristics: diff --git a/parse/src/main/java/com/parse/ParseAuthenticationManager.java b/parse/src/main/java/com/parse/ParseAuthenticationManager.java index f145a148f..9b0dc1ba7 100644 --- a/parse/src/main/java/com/parse/ParseAuthenticationManager.java +++ b/parse/src/main/java/com/parse/ParseAuthenticationManager.java @@ -8,12 +8,10 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import java.util.HashMap; import java.util.Map; -import java.util.concurrent.Callable; - -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; class ParseAuthenticationManager { @@ -44,15 +42,12 @@ public void register(final String authType, AuthenticationCallback callback) { } // Synchronize the current user with the auth callback. - controller.getAsync(false).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseUser user = task.getResult(); - if (user != null) { - return user.synchronizeAuthDataAsync(authType); - } - return null; + controller.getAsync(false).onSuccessTask(task -> { + ParseUser user = task.getResult(); + if (user != null) { + return user.synchronizeAuthDataAsync(authType); } + return null; }); } @@ -64,12 +59,7 @@ public Task restoreAuthenticationAsync(String authType, final Map() { - @Override - public Boolean call() { - return callback.onRestore(authData); - } - }, ParseExecutors.io()); + return Task.call(() -> callback.onRestore(authData), ParseExecutors.io()); } public Task deauthenticateAsync(String authType) { @@ -78,12 +68,9 @@ public Task deauthenticateAsync(String authType) { callback = this.callbacks.get(authType); } if (callback != null) { - return Task.call(new Callable() { - @Override - public Void call() { - callback.onRestore(null); - return null; - } + return Task.call(() -> { + callback.onRestore(null); + return null; }, ParseExecutors.io()); } return Task.forResult(null); diff --git a/parse/src/main/java/com/parse/ParseCloud.java b/parse/src/main/java/com/parse/ParseCloud.java index 05dd315bd..4a24bf77a 100644 --- a/parse/src/main/java/com/parse/ParseCloud.java +++ b/parse/src/main/java/com/parse/ParseCloud.java @@ -10,12 +10,11 @@ import androidx.annotation.NonNull; +import com.parse.boltsinternal.Task; + import java.util.List; import java.util.Map; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * The ParseCloud class defines provides methods for interacting with Parse Cloud Functions. A Cloud * Function can be called with {@link #callFunctionInBackground(String, Map, FunctionCallback)} @@ -61,12 +60,9 @@ static ParseCloudCodeController getCloudCodeController() { */ public static Task callFunctionInBackground(@NonNull final String name, @NonNull final Map params) { - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String sessionToken = task.getResult(); - return getCloudCodeController().callFunctionInBackground(name, params, sessionToken); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + String sessionToken = task.getResult(); + return getCloudCodeController().callFunctionInBackground(name, params, sessionToken); }); } diff --git a/parse/src/main/java/com/parse/ParseCloudCodeController.java b/parse/src/main/java/com/parse/ParseCloudCodeController.java index 3703178f7..0b7078346 100644 --- a/parse/src/main/java/com/parse/ParseCloudCodeController.java +++ b/parse/src/main/java/com/parse/ParseCloudCodeController.java @@ -8,13 +8,12 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import java.util.Map; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class ParseCloudCodeController { /* package for test */ final ParseHttpClient restClient; @@ -29,13 +28,10 @@ public Task callFunctionInBackground(final String name, name, params, sessionToken); - return command.executeAsync(restClient).onSuccess(new Continuation() { - @Override - public T then(Task task) { - @SuppressWarnings("unchecked") - T result = (T) convertCloudResponse(task.getResult()); - return result; - } + return command.executeAsync(restClient).onSuccess(task -> { + @SuppressWarnings("unchecked") + T result = (T) convertCloudResponse(task.getResult()); + return result; }); } diff --git a/parse/src/main/java/com/parse/ParseCommandCache.java b/parse/src/main/java/com/parse/ParseCommandCache.java index 17e4412cc..b94d51945 100644 --- a/parse/src/main/java/com/parse/ParseCommandCache.java +++ b/parse/src/main/java/com/parse/ParseCommandCache.java @@ -10,9 +10,13 @@ import android.Manifest; import android.content.Context; -import android.content.Intent; import android.net.ConnectivityManager; +import com.parse.boltsinternal.Capture; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + import org.json.JSONException; import org.json.JSONObject; @@ -26,11 +30,6 @@ import java.util.logging.Level; import java.util.logging.Logger; -import com.parse.boltsinternal.Capture; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - /** * ParseCommandCache manages an on-disk cache of commands to be executed, and a thread with a * standard run loop that executes the commands. There should only ever be one instance of this @@ -48,43 +47,42 @@ class ParseCommandCache extends ParseEventuallyQueue { private static final Object lock = new Object(); // order. private static int filenameCounter = 0; // Appended to temp file names so we know their creation + final ConnectivityNotifier.ConnectivityListener listener = (context, intent) -> { + final boolean connectionLost = + intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + final boolean isConnected = ConnectivityNotifier.isConnected(context); + + /* + Hack to avoid blocking the UI thread with disk I/O + + setConnected uses the same lock we use for synchronizing disk I/O, so there's a possibility + that we can block the UI thread on disk I/O, so we're going to bump the lock usage to a + different thread. + + TODO(grantland): Convert to TaskQueue, similar to ParsePinningEventuallyQueue + */ + Task.call((Callable) () -> { + if (connectionLost) { + setConnected(false); + } else { + setConnected(isConnected); + } + return null; + }, ParseExecutors.io()); + }; // Guards access to running. Gets a broadcast whenever running changes. A thread should only wait // on runningLock if it's sure the value of running is going to change. Only the run loop // (runLoop) thread should ever notify on runningLock. It's perfectly fine for a thread that has // runningLock to then also try to acquire the other lock. private final Object runningLock; private final ParseHttpClient httpClient; + private final File cachePath; // Where the cache is stored on disk. + // Map of filename to TaskCompletionSource, for all commands that are in the queue from this run + // of the program. This is necessary so that the original objects can be notified after their + // saves complete. + private final HashMap> pendingTasks = new HashMap<>(); + private final Logger log; // Why is there a custom logger? To prevent Mockito deadlock! ConnectivityNotifier notifier; - ConnectivityNotifier.ConnectivityListener listener = new ConnectivityNotifier.ConnectivityListener() { - @Override - public void networkConnectivityStatusChanged(Context context, Intent intent) { - final boolean connectionLost = - intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); - final boolean isConnected = ConnectivityNotifier.isConnected(context); - - /* - Hack to avoid blocking the UI thread with disk I/O - - setConnected uses the same lock we use for synchronizing disk I/O, so there's a possibility - that we can block the UI thread on disk I/O, so we're going to bump the lock usage to a - different thread. - - TODO(grantland): Convert to TaskQueue, similar to ParsePinningEventuallyQueue - */ - Task.call(new Callable() { - @Override - public Void call() { - if (connectionLost) { - setConnected(false); - } else { - setConnected(isConnected); - } - return null; - } - }, ParseExecutors.io()); - } - }; - private File cachePath; // Where the cache is stored on disk. private int timeoutMaxRetries = 5; // Don't retry more than 5 times before assuming disconnection. private double timeoutRetryWaitSeconds = 600.0f; // Wait 10 minutes before retrying after network // timeout. @@ -92,12 +90,7 @@ public Void call() { // processed by the run loop? private boolean shouldStop; // Should the run loop thread processing the disk cache continue? private boolean unprocessedCommandsExist; // Has a command been added which hasn't yet been - // Map of filename to TaskCompletionSource, for all commands that are in the queue from this run - // of the program. This is necessary so that the original objects can be notified after their - // saves complete. - private HashMap> pendingTasks = new HashMap<>(); private boolean running; // Is the run loop executing commands from the disk cache running? - private Logger log; // Why is there a custom logger? To prevent Mockito deadlock! public ParseCommandCache(Context context, ParseHttpClient client) { setConnected(false); @@ -425,15 +418,12 @@ public void setConnected(boolean connected) { private T waitForTaskWithoutLock(Task task) throws ParseException { synchronized (lock) { final Capture finished = new Capture<>(false); - task.continueWith(new Continuation() { - @Override - public Void then(Task task) { - finished.set(true); - synchronized (lock) { - lock.notifyAll(); - } - return null; + task.continueWith((Continuation) task1 -> { + finished.set(true); + synchronized (lock) { + lock.notifyAll(); } + return null; }, Task.BACKGROUND_EXECUTOR); while (!finished.get()) { try { @@ -518,36 +508,33 @@ private void maybeRunAllCommandsNow(int retriesRemaining) { } notifyTestHelper(TestHelper.COMMAND_OLD_FORMAT_DISCARDED); } else { - commandTask = command.executeAsync(httpClient).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - String localId = command.getLocalId(); - Exception error = task.getError(); - if (error != null) { - if (error instanceof ParseException - && ((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) { - // do nothing - } else { - if (tcs != null) { - tcs.setError(error); - } + commandTask = command.executeAsync(httpClient).continueWithTask(task -> { + String localId = command.getLocalId(); + Exception error = task.getError(); + if (error != null) { + if (error instanceof ParseException + && ((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) { + // do nothing + } else { + if (tcs != null) { + tcs.setError(error); } - return task; } + return task; + } - JSONObject json = task.getResult(); - if (tcs != null) { - tcs.setResult(json); - } else if (localId != null) { - // If this command created a new objectId, add it to the map. - String objectId = json.optString("objectId", null); - if (objectId != null) { - ParseCorePlugins.getInstance() - .getLocalIdManager().setObjectId(localId, objectId); - } + JSONObject json1 = task.getResult(); + if (tcs != null) { + tcs.setResult(json1); + } else if (localId != null) { + // If this command created a new objectId, add it to the map. + String objectId = json1.optString("objectId", null); + if (objectId != null) { + ParseCorePlugins.getInstance() + .getLocalIdManager().setObjectId(localId, objectId); } - return task; } + return task; }); } diff --git a/parse/src/main/java/com/parse/ParseConfig.java b/parse/src/main/java/com/parse/ParseConfig.java index e985cde3d..6d1d39c6d 100644 --- a/parse/src/main/java/com/parse/ParseConfig.java +++ b/parse/src/main/java/com/parse/ParseConfig.java @@ -8,6 +8,8 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONArray; import org.json.JSONObject; @@ -17,9 +19,6 @@ import java.util.List; import java.util.Map; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * The {@code ParseConfig} is a local representation of configuration data that can be set from the * Parse dashboard. @@ -34,7 +33,7 @@ public class ParseConfig { } /* package */ ParseConfig() { - params = Collections.unmodifiableMap(new HashMap()); + params = Collections.unmodifiableMap(new HashMap<>()); } /* package for tests */ @@ -87,26 +86,13 @@ public static void getInBackground(ConfigCallback callback) { * @return A Task that is resolved when the fetch completes. */ public static Task getInBackground() { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return getAsync(toAwait); - } - }); + return taskQueue.enqueue(ParseConfig::getAsync); } private static Task getAsync(final Task toAwait) { - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final String sessionToken = task.getResult(); - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return getConfigController().getAsync(sessionToken); - } - }); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + final String sessionToken = task.getResult(); + return toAwait.continueWithTask(task1 -> getConfigController().getAsync(sessionToken)); }); } diff --git a/parse/src/main/java/com/parse/ParseConfigController.java b/parse/src/main/java/com/parse/ParseConfigController.java index 6c8707498..4982bf8b7 100644 --- a/parse/src/main/java/com/parse/ParseConfigController.java +++ b/parse/src/main/java/com/parse/ParseConfigController.java @@ -8,15 +8,14 @@ */ package com.parse; -import org.json.JSONObject; - -import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; +import org.json.JSONObject; + class ParseConfigController { private final ParseHttpClient restClient; - private ParseCurrentConfigController currentConfigController; + private final ParseCurrentConfigController currentConfigController; public ParseConfigController(ParseHttpClient restClient, ParseCurrentConfigController currentConfigController) { @@ -30,19 +29,11 @@ public ParseConfigController(ParseHttpClient restClient, public Task getAsync(String sessionToken) { final ParseRESTCommand command = ParseRESTConfigCommand.fetchConfigCommand(sessionToken); - return command.executeAsync(restClient).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - JSONObject result = task.getResult(); - - final ParseConfig config = ParseConfig.decode(result, ParseDecoder.get()); - return currentConfigController.setCurrentConfigAsync(config).continueWith(new Continuation() { - @Override - public ParseConfig then(Task task) { - return config; - } - }); - } + return command.executeAsync(restClient).onSuccessTask(task -> { + JSONObject result = task.getResult(); + + final ParseConfig config = ParseConfig.decode(result, ParseDecoder.get()); + return currentConfigController.setCurrentConfigAsync(config).continueWith(task1 -> config); }); } } diff --git a/parse/src/main/java/com/parse/ParseCorePlugins.java b/parse/src/main/java/com/parse/ParseCorePlugins.java index ea5b8a79f..8101faea6 100644 --- a/parse/src/main/java/com/parse/ParseCorePlugins.java +++ b/parse/src/main/java/com/parse/ParseCorePlugins.java @@ -19,28 +19,29 @@ class ParseCorePlugins { /* package */ static final String PIN_CURRENT_INSTALLATION = "_currentInstallation"; /* package */ static final String FILENAME_CURRENT_CONFIG = "currentConfig"; private static final ParseCorePlugins INSTANCE = new ParseCorePlugins(); - private AtomicReference objectController = new AtomicReference<>(); - private AtomicReference userController = new AtomicReference<>(); - private AtomicReference sessionController = new AtomicReference<>(); + private final AtomicReference objectController = new AtomicReference<>(); + private final AtomicReference userController = new AtomicReference<>(); + private final AtomicReference sessionController = new AtomicReference<>(); // TODO(mengyan): Inject into ParseUserInstanceController - private AtomicReference currentUserController = + private final AtomicReference currentUserController = new AtomicReference<>(); // TODO(mengyan): Inject into ParseInstallationInstanceController - private AtomicReference currentInstallationController = + private final AtomicReference currentInstallationController = new AtomicReference<>(); - private AtomicReference authenticationController = + private final AtomicReference authenticationController = new AtomicReference<>(); - private AtomicReference queryController = new AtomicReference<>(); - private AtomicReference fileController = new AtomicReference<>(); - private AtomicReference analyticsController = new AtomicReference<>(); - private AtomicReference cloudCodeController = new AtomicReference<>(); - private AtomicReference configController = new AtomicReference<>(); - private AtomicReference pushController = new AtomicReference<>(); - private AtomicReference pushChannelsController = + private final AtomicReference queryController = new AtomicReference<>(); + private final AtomicReference fileController = new AtomicReference<>(); + private final AtomicReference analyticsController = new AtomicReference<>(); + private final AtomicReference cloudCodeController = new AtomicReference<>(); + private final AtomicReference configController = new AtomicReference<>(); + private final AtomicReference pushController = new AtomicReference<>(); + private final AtomicReference pushChannelsController = new AtomicReference<>(); - private AtomicReference defaultACLController = new AtomicReference<>(); - private AtomicReference localIdManager = new AtomicReference<>(); - private AtomicReference subclassingController = new AtomicReference<>(); + private final AtomicReference defaultACLController = new AtomicReference<>(); + private final AtomicReference localIdManager = new AtomicReference<>(); + private final AtomicReference subclassingController = new AtomicReference<>(); + private ParseCorePlugins() { // do nothing } diff --git a/parse/src/main/java/com/parse/ParseCountingByteArrayHttpBody.java b/parse/src/main/java/com/parse/ParseCountingByteArrayHttpBody.java index 961d6df1a..0b4a47933 100644 --- a/parse/src/main/java/com/parse/ParseCountingByteArrayHttpBody.java +++ b/parse/src/main/java/com/parse/ParseCountingByteArrayHttpBody.java @@ -8,11 +8,11 @@ */ package com.parse; +import static java.lang.Math.min; + import java.io.IOException; import java.io.OutputStream; -import static java.lang.Math.min; - class ParseCountingByteArrayHttpBody extends ParseByteArrayHttpBody { private static final int DEFAULT_CHUNK_SIZE = 4096; private final ProgressCallback progressCallback; diff --git a/parse/src/main/java/com/parse/ParseCurrentConfigController.java b/parse/src/main/java/com/parse/ParseCurrentConfigController.java index a78d7dd9b..3e429f4cf 100644 --- a/parse/src/main/java/com/parse/ParseCurrentConfigController.java +++ b/parse/src/main/java/com/parse/ParseCurrentConfigController.java @@ -8,50 +8,43 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.IOException; -import java.util.concurrent.Callable; - -import com.parse.boltsinternal.Task; class ParseCurrentConfigController { private final Object currentConfigMutex = new Object(); + private final File currentConfigFile; /* package for test */ ParseConfig currentConfig; - private File currentConfigFile; public ParseCurrentConfigController(File currentConfigFile) { this.currentConfigFile = currentConfigFile; } public Task setCurrentConfigAsync(final ParseConfig config) { - return Task.call(new Callable() { - @Override - public Void call() { - synchronized (currentConfigMutex) { - currentConfig = config; - saveToDisk(config); - } - return null; + return Task.call(() -> { + synchronized (currentConfigMutex) { + currentConfig = config; + saveToDisk(config); } + return null; }, ParseExecutors.io()); } public Task getCurrentConfigAsync() { - return Task.call(new Callable() { - @Override - public ParseConfig call() { - synchronized (currentConfigMutex) { - if (currentConfig == null) { - ParseConfig config = getFromDisk(); - currentConfig = (config != null) ? config : new ParseConfig(); - } + return Task.call(() -> { + synchronized (currentConfigMutex) { + if (currentConfig == null) { + ParseConfig config = getFromDisk(); + currentConfig = (config != null) ? config : new ParseConfig(); } - return currentConfig; } + return currentConfig; }, ParseExecutors.io()); } diff --git a/parse/src/main/java/com/parse/ParseEventuallyQueue.java b/parse/src/main/java/com/parse/ParseEventuallyQueue.java index 8152b6b64..c1f8a45ef 100644 --- a/parse/src/main/java/com/parse/ParseEventuallyQueue.java +++ b/parse/src/main/java/com/parse/ParseEventuallyQueue.java @@ -10,6 +10,8 @@ import android.util.SparseArray; +import com.parse.boltsinternal.Task; + import org.json.JSONException; import org.json.JSONObject; @@ -18,8 +20,6 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import com.parse.boltsinternal.Task; - /* package */ abstract class ParseEventuallyQueue { private boolean isConnected; @@ -140,7 +140,7 @@ public static class TestHelper { public static final int NETWORK_DOWN = 7; public static final int COMMAND_OLD_FORMAT_DISCARDED = 8; private static final int MAX_EVENTS = 1000; - private SparseArray events = new SparseArray<>(); + private final SparseArray events = new SparseArray<>(); private TestHelper() { clear(); diff --git a/parse/src/main/java/com/parse/ParseException.java b/parse/src/main/java/com/parse/ParseException.java index 1b2124379..60c582e53 100644 --- a/parse/src/main/java/com/parse/ParseException.java +++ b/parse/src/main/java/com/parse/ParseException.java @@ -200,7 +200,7 @@ public class ParseException extends Exception { */ public static final int UNSUPPORTED_SERVICE = 252; private static final long serialVersionUID = 1; - private int code; + private final int code; /** * Construct a new ParseException with a particular error code. diff --git a/parse/src/main/java/com/parse/ParseExecutors.java b/parse/src/main/java/com/parse/ParseExecutors.java index e0a0e7d57..6f6f4cc10 100644 --- a/parse/src/main/java/com/parse/ParseExecutors.java +++ b/parse/src/main/java/com/parse/ParseExecutors.java @@ -8,11 +8,11 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import java.util.concurrent.Executor; import java.util.concurrent.ScheduledExecutorService; -import com.parse.boltsinternal.Task; - class ParseExecutors { private static final Object SCHEDULED_EXECUTOR_LOCK = new Object(); diff --git a/parse/src/main/java/com/parse/ParseFieldOperations.java b/parse/src/main/java/com/parse/ParseFieldOperations.java index b78246730..c08155357 100644 --- a/parse/src/main/java/com/parse/ParseFieldOperations.java +++ b/parse/src/main/java/com/parse/ParseFieldOperations.java @@ -20,7 +20,7 @@ */ /* package */ final class ParseFieldOperations { // A map of all known decoders. - private static Map opDecoderMap = new HashMap<>(); + private static final Map opDecoderMap = new HashMap<>(); private ParseFieldOperations() { } diff --git a/parse/src/main/java/com/parse/ParseFile.java b/parse/src/main/java/com/parse/ParseFile.java index edf745d72..65929a5d1 100644 --- a/parse/src/main/java/com/parse/ParseFile.java +++ b/parse/src/main/java/com/parse/ParseFile.java @@ -11,6 +11,10 @@ import android.os.Parcel; import android.os.Parcelable; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + import org.json.JSONException; import org.json.JSONObject; @@ -23,10 +27,6 @@ import java.util.Set; import java.util.concurrent.Callable; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - /** * {@code ParseFile} is a local representation of a file that is saved to the Parse cloud. *

@@ -57,6 +57,8 @@ public ParseFile[] newArray(int size) { } }; /* package for tests */ final TaskQueue taskQueue = new TaskQueue(); + private final Set> currentTasks = Collections.synchronizedSet( + new HashSet<>()); /** * Staging of {@code ParseFile}'s data is stored in memory until the {@code ParseFile} has been * successfully synced with the server. @@ -64,8 +66,6 @@ public ParseFile[] newArray(int size) { /* package for tests */ byte[] data; /* package for tests */ File file; private State state; - private Set> currentTasks = Collections.synchronizedSet( - new HashSet>()); /** * Creates a new file from a file pointer. @@ -75,6 +75,7 @@ public ParseFile[] newArray(int size) { public ParseFile(File file) { this(file, null); } + /** * Creates a new file from a file pointer, and content type. Content type will be used instead of * auto-detection by file extension. @@ -186,18 +187,10 @@ private static ProgressCallback progressCallbackOnMainThread( return null; } - return new ProgressCallback() { - @Override - public void done(final Integer percentDone) { - Task.call(new Callable() { - @Override - public Void call() { - progressCallback.done(percentDone); - return null; - } - }, ParseExecutors.main()); - } - }; + return percentDone -> Task.call((Callable) () -> { + progressCallback.done(percentDone); + return null; + }, ParseExecutors.main()); } /* package for tests */ State getState() { @@ -259,45 +252,39 @@ private Task saveAsync(final String sessionToken, } // Wait for our turn in the queue, then check state to decide whether to no-op. - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (!isDirty()) { - return Task.forResult(null); - } - if (cancellationToken != null && cancellationToken.isCancelled()) { - return Task.cancelled(); - } - - Task saveTask; - if (data != null) { - saveTask = getFileController().saveAsync( - state, - data, - sessionToken, - progressCallbackOnMainThread(uploadProgressCallback), - cancellationToken); - } else { - saveTask = getFileController().saveAsync( - state, - file, - sessionToken, - progressCallbackOnMainThread(uploadProgressCallback), - cancellationToken); - } - - return saveTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - state = task.getResult(); - // Since we have successfully uploaded the file, we do not need to hold the file pointer - // anymore. - data = null; - file = null; - return task.makeVoid(); - } - }); + return toAwait.continueWithTask(task -> { + if (!isDirty()) { + return Task.forResult(null); } + if (cancellationToken != null && cancellationToken.isCancelled()) { + return Task.cancelled(); + } + + Task saveTask; + if (data != null) { + saveTask = getFileController().saveAsync( + state, + data, + sessionToken, + progressCallbackOnMainThread(uploadProgressCallback), + cancellationToken); + } else { + saveTask = getFileController().saveAsync( + state, + file, + sessionToken, + progressCallbackOnMainThread(uploadProgressCallback), + cancellationToken); + } + + return saveTask.onSuccessTask(task1 -> { + state = task1.getResult(); + // Since we have successfully uploaded the file, we do not need to hold the file pointer + // anymore. + data = null; + file = null; + return task1.makeVoid(); + }); }); } @@ -312,30 +299,19 @@ public Task saveInBackground(final ProgressCallback uploadProgressCallback final TaskCompletionSource cts = new TaskCompletionSource<>(); currentTasks.add(cts); - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final String sessionToken = task.getResult(); - return saveAsync(sessionToken, uploadProgressCallback, cts.getTask()); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - cts.trySetResult(null); // release - currentTasks.remove(cts); - return task; - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + final String sessionToken = task.getResult(); + return saveAsync(sessionToken, uploadProgressCallback, cts.getTask()); + }).continueWithTask(task -> { + cts.trySetResult(null); // release + currentTasks.remove(cts); + return task; }); } /* package */ Task saveAsync(final String sessionToken, final ProgressCallback uploadProgressCallback, final Task cancellationToken) { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return saveAsync(sessionToken, uploadProgressCallback, toAwait, cancellationToken); - } - }); + return taskQueue.enqueue(toAwait -> saveAsync(sessionToken, uploadProgressCallback, toAwait, cancellationToken)); } /** @@ -388,29 +364,18 @@ public Task getDataInBackground(final ProgressCallback progressCallback) final TaskCompletionSource cts = new TaskCompletionSource<>(); currentTasks.add(cts); - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(new Continuation() { - @Override - public byte[] then(Task task) { - File file = task.getResult(); - try { - return ParseFileUtils.readFileToByteArray(file); - } catch (IOException e) { - // do nothing - } - return null; - } - }); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - cts.trySetResult(null); // release - currentTasks.remove(cts); - return task; + return taskQueue.enqueue(toAwait -> fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(task -> { + File file = task.getResult(); + try { + return ParseFileUtils.readFileToByteArray(file); + } catch (IOException e) { + // do nothing } + return null; + })).continueWithTask(task -> { + cts.trySetResult(null); // release + currentTasks.remove(cts); + return task; }); } @@ -470,18 +435,10 @@ public Task getFileInBackground(final ProgressCallback progressCallback) { final TaskCompletionSource cts = new TaskCompletionSource<>(); currentTasks.add(cts); - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return fetchInBackground(progressCallback, toAwait, cts.getTask()); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - cts.trySetResult(null); // release - currentTasks.remove(cts); - return task; - } + return taskQueue.enqueue(toAwait -> fetchInBackground(progressCallback, toAwait, cts.getTask())).continueWithTask(task -> { + cts.trySetResult(null); // release + currentTasks.remove(cts); + return task; }); } @@ -548,23 +505,10 @@ public Task getDataStreamInBackground(final ProgressCallback progre final TaskCompletionSource cts = new TaskCompletionSource<>(); currentTasks.add(cts); - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(new Continuation() { - @Override - public InputStream then(Task task) throws Exception { - return new FileInputStream(task.getResult()); - } - }); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - cts.trySetResult(null); // release - currentTasks.remove(cts); - return task; - } + return taskQueue.enqueue((Continuation>) toAwait -> fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(task -> new FileInputStream(task.getResult()))).continueWithTask(task -> { + cts.trySetResult(null); // release + currentTasks.remove(cts); + return task; }); } @@ -614,18 +558,15 @@ private Task fetchInBackground( return Task.cancelled(); } - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (cancellationToken != null && cancellationToken.isCancelled()) { - return Task.cancelled(); - } - return getFileController().fetchAsync( - state, - null, - progressCallbackOnMainThread(progressCallback), - cancellationToken); + return toAwait.continueWithTask(task -> { + if (cancellationToken != null && cancellationToken.isCancelled()) { + return Task.cancelled(); } + return getFileController().fetchAsync( + state, + null, + progressCallbackOnMainThread(progressCallback), + cancellationToken); }); } @@ -685,6 +626,7 @@ void writeToParcel(Parcel dest, ParseParcelEncoder encoder) { private final String name; private final String contentType; private final String url; + private State(Builder builder) { name = builder.name != null ? builder.name : "file"; contentType = builder.mimeType; diff --git a/parse/src/main/java/com/parse/ParseFileController.java b/parse/src/main/java/com/parse/ParseFileController.java index a6ba29316..be15a9a9e 100644 --- a/parse/src/main/java/com/parse/ParseFileController.java +++ b/parse/src/main/java/com/parse/ParseFileController.java @@ -8,18 +8,15 @@ */ package com.parse; +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import org.json.JSONObject; import java.io.File; import java.io.IOException; -import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - // TODO(grantland): Create ParseFileController interface class ParseFileController { @@ -104,24 +101,21 @@ public Task saveAsync( uploadProgressCallback, null, cancellationToken - ).onSuccess(new Continuation() { - @Override - public ParseFile.State then(Task task) throws Exception { - JSONObject result = task.getResult(); - ParseFile.State newState = new ParseFile.State.Builder(state) - .name(result.getString("name")) - .url(result.getString("url")) - .build(); - - // Write data to cache - try { - ParseFileUtils.writeByteArrayToFile(getCacheFile(newState), data); - } catch (IOException e) { - // do nothing - } - - return newState; + ).onSuccess(task -> { + JSONObject result = task.getResult(); + ParseFile.State newState = new ParseFile.State.Builder(state) + .name(result.getString("name")) + .url(result.getString("url")) + .build(); + + // Write data to cache + try { + ParseFileUtils.writeByteArrayToFile(getCacheFile(newState), data); + } catch (IOException e) { + // do nothing } + + return newState; }, ParseExecutors.io()); } @@ -150,24 +144,21 @@ public Task saveAsync( uploadProgressCallback, null, cancellationToken - ).onSuccess(new Continuation() { - @Override - public ParseFile.State then(Task task) throws Exception { - JSONObject result = task.getResult(); - ParseFile.State newState = new ParseFile.State.Builder(state) - .name(result.getString("name")) - .url(result.getString("url")) - .build(); - - // Write data to cache - try { - ParseFileUtils.copyFile(file, getCacheFile(newState)); - } catch (IOException e) { - // do nothing - } - - return newState; + ).onSuccess(task -> { + JSONObject result = task.getResult(); + ParseFile.State newState = new ParseFile.State.Builder(state) + .name(result.getString("name")) + .url(result.getString("url")) + .build(); + + // Write data to cache + try { + ParseFileUtils.copyFile(file, getCacheFile(newState)); + } catch (IOException e) { + // do nothing } + + return newState; }, ParseExecutors.io()); } @@ -180,59 +171,48 @@ public Task fetchAsync( return Task.cancelled(); } final File cacheFile = getCacheFile(state); - return Task.call(new Callable() { - @Override - public Boolean call() { - return cacheFile.exists(); + return Task.call(cacheFile::exists, ParseExecutors.io()).continueWithTask(task -> { + boolean result = task.getResult(); + if (result) { + return Task.forResult(cacheFile); } - }, ParseExecutors.io()).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - boolean result = task.getResult(); - if (result) { - return Task.forResult(cacheFile); - } + if (cancellationToken != null && cancellationToken.isCancelled()) { + return Task.cancelled(); + } + + // Generate the temp file path for caching ParseFile content based on ParseFile's url + // The reason we do not write to the cacheFile directly is because there is no way we can + // verify if a cacheFile is complete or not. If download is interrupted in the middle, next + // time when we download the ParseFile, since cacheFile has already existed, we will return + // this incomplete cacheFile + final File tempFile = getTempFile(state); + + // network + final ParseFileRequest request = + new ParseFileRequest(ParseHttpRequest.Method.GET, state.url(), tempFile); + + // We do not need to delete the temp file since we always try to overwrite it + return request.executeAsync( + fileClient(), + null, + downloadProgressCallback, + cancellationToken).continueWithTask(task1 -> { + // If the top-level task was cancelled, don't actually set the data -- just move on. if (cancellationToken != null && cancellationToken.isCancelled()) { - return Task.cancelled(); + throw new CancellationException(); + } + if (task1.isFaulted()) { + ParseFileUtils.deleteQuietly(tempFile); + return task1.cast(); } - // Generate the temp file path for caching ParseFile content based on ParseFile's url - // The reason we do not write to the cacheFile directly is because there is no way we can - // verify if a cacheFile is complete or not. If download is interrupted in the middle, next - // time when we download the ParseFile, since cacheFile has already existed, we will return - // this incomplete cacheFile - final File tempFile = getTempFile(state); - - // network - final ParseFileRequest request = - new ParseFileRequest(ParseHttpRequest.Method.GET, state.url(), tempFile); - - // We do not need to delete the temp file since we always try to overwrite it - return request.executeAsync( - fileClient(), - null, - downloadProgressCallback, - cancellationToken).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - // If the top-level task was cancelled, don't actually set the data -- just move on. - if (cancellationToken != null && cancellationToken.isCancelled()) { - throw new CancellationException(); - } - if (task.isFaulted()) { - ParseFileUtils.deleteQuietly(tempFile); - return task.cast(); - } - - // Since we give the cacheFile pointer to developers, it is not safe to guarantee - // cacheFile always does not exist here, so it is better to delete it manually, - // otherwise moveFile may throw an exception. - ParseFileUtils.deleteQuietly(cacheFile); - ParseFileUtils.moveFile(tempFile, cacheFile); - return Task.forResult(cacheFile); - } - }, ParseExecutors.io()); - } + // Since we give the cacheFile pointer to developers, it is not safe to guarantee + // cacheFile always does not exist here, so it is better to delete it manually, + // otherwise moveFile may throw an exception. + ParseFileUtils.deleteQuietly(cacheFile); + ParseFileUtils.moveFile(tempFile, cacheFile); + return Task.forResult(cacheFile); + }, ParseExecutors.io()); }); } } diff --git a/parse/src/main/java/com/parse/ParseFileRequest.java b/parse/src/main/java/com/parse/ParseFileRequest.java index 49eaf4d07..24f8e1301 100644 --- a/parse/src/main/java/com/parse/ParseFileRequest.java +++ b/parse/src/main/java/com/parse/ParseFileRequest.java @@ -8,15 +8,13 @@ */ package com.parse; +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; -import java.util.concurrent.Callable; - -import com.parse.boltsinternal.Task; /** * Request returns a byte array of the response and provides a callback the progress of the data @@ -48,34 +46,31 @@ protected Task onResponseAsync(final ParseHttpResponse response, return null; } - return Task.call(new Callable() { - @Override - public Void call() throws Exception { - long totalSize = response.getTotalSize(); - long downloadedSize = 0; - InputStream responseStream = null; - FileOutputStream tempFileStream = null; - try { - responseStream = response.getContent(); - tempFileStream = ParseFileUtils.openOutputStream(tempFile); + return Task.call(() -> { + long totalSize = response.getTotalSize(); + long downloadedSize = 0; + InputStream responseStream = null; + FileOutputStream tempFileStream = null; + try { + responseStream = response.getContent(); + tempFileStream = ParseFileUtils.openOutputStream(tempFile); - int nRead; - byte[] data = new byte[32 << 10]; // 32KB + int nRead; + byte[] data = new byte[32 << 10]; // 32KB - while ((nRead = responseStream.read(data, 0, data.length)) != -1) { - tempFileStream.write(data, 0, nRead); - downloadedSize += nRead; - if (downloadProgressCallback != null && totalSize != -1) { - int progressToReport = - Math.round((float) downloadedSize / (float) totalSize * 100.0f); - downloadProgressCallback.done(progressToReport); - } + while ((nRead = responseStream.read(data, 0, data.length)) != -1) { + tempFileStream.write(data, 0, nRead); + downloadedSize += nRead; + if (downloadProgressCallback != null && totalSize != -1) { + int progressToReport = + Math.round((float) downloadedSize / (float) totalSize * 100.0f); + downloadProgressCallback.done(progressToReport); } - return null; - } finally { - ParseIOUtils.closeQuietly(responseStream); - ParseIOUtils.closeQuietly(tempFileStream); } + return null; + } finally { + ParseIOUtils.closeQuietly(responseStream); + ParseIOUtils.closeQuietly(tempFileStream); } }, ParseExecutors.io()); } diff --git a/parse/src/main/java/com/parse/ParseFileUtils.java b/parse/src/main/java/com/parse/ParseFileUtils.java index 046f16a6e..666b8b9b6 100644 --- a/parse/src/main/java/com/parse/ParseFileUtils.java +++ b/parse/src/main/java/com/parse/ParseFileUtils.java @@ -537,7 +537,7 @@ public static JSONObject readFileToJSONObject(File file) throws IOException, JSO * Writes a {@link JSONObject} to a file creating the file if it does not exist. */ public static void writeJSONObjectToFile(File file, JSONObject json) throws IOException { - ParseFileUtils.writeByteArrayToFile(file, json.toString().getBytes(Charset.forName("UTF-8"))); + ParseFileUtils.writeByteArrayToFile(file, json.toString().getBytes("UTF-8")); } //endregion diff --git a/parse/src/main/java/com/parse/ParseGeoPoint.java b/parse/src/main/java/com/parse/ParseGeoPoint.java index 87e1d12c7..d27a151e6 100644 --- a/parse/src/main/java/com/parse/ParseGeoPoint.java +++ b/parse/src/main/java/com/parse/ParseGeoPoint.java @@ -13,11 +13,10 @@ import android.os.Parcel; import android.os.Parcelable; -import java.util.Locale; - -import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; +import java.util.Locale; + /** * {@code ParseGeoPoint} represents a latitude / longitude point that may be associated with a key * in a {@link ParseObject} or used as a reference point for geo queries. This allows proximity @@ -46,8 +45,8 @@ public ParseGeoPoint[] newArray(int size) { return new ParseGeoPoint[size]; } }; - static double EARTH_MEAN_RADIUS_KM = 6371.0; - static double EARTH_MEAN_RADIUS_MILE = 3958.8; + static final double EARTH_MEAN_RADIUS_KM = 6371.0; + static final double EARTH_MEAN_RADIUS_MILE = 3958.8; private double latitude = 0.0; private double longitude = 0.0; @@ -120,12 +119,9 @@ public static Task getCurrentLocationInBackground(long timeout) { criteria.setAccuracy(Criteria.NO_REQUIREMENT); criteria.setPowerRequirement(Criteria.NO_REQUIREMENT); return LocationNotifier.getCurrentLocationAsync(Parse.getApplicationContext(), timeout, criteria) - .onSuccess(new Continuation() { - @Override - public ParseGeoPoint then(Task task) { - Location location = task.getResult(); - return new ParseGeoPoint(location.getLatitude(), location.getLongitude()); - } + .onSuccess(task -> { + Location location = task.getResult(); + return new ParseGeoPoint(location.getLatitude(), location.getLongitude()); }); } @@ -167,12 +163,9 @@ public static void getCurrentLocationInBackground(long timeout, LocationCallback */ public static Task getCurrentLocationInBackground(long timeout, Criteria criteria) { return LocationNotifier.getCurrentLocationAsync(Parse.getApplicationContext(), timeout, criteria) - .onSuccess(new Continuation() { - @Override - public ParseGeoPoint then(Task task) { - Location location = task.getResult(); - return new ParseGeoPoint(location.getLatitude(), location.getLongitude()); - } + .onSuccess(task -> { + Location location = task.getResult(); + return new ParseGeoPoint(location.getLatitude(), location.getLongitude()); }); } diff --git a/parse/src/main/java/com/parse/ParseHttpClient.java b/parse/src/main/java/com/parse/ParseHttpClient.java index affe8673f..912810a7c 100644 --- a/parse/src/main/java/com/parse/ParseHttpClient.java +++ b/parse/src/main/java/com/parse/ParseHttpClient.java @@ -34,7 +34,7 @@ */ class ParseHttpClient { - private OkHttpClient okHttpClient; + private final OkHttpClient okHttpClient; private boolean hasExecuted; ParseHttpClient(@Nullable OkHttpClient.Builder builder) { @@ -161,7 +161,7 @@ Request getRequest(ParseHttpRequest parseRequest) { private static class ParseOkHttpRequestBody extends RequestBody { - private ParseHttpBody parseBody; + private final ParseHttpBody parseBody; ParseOkHttpRequestBody(ParseHttpBody parseBody) { this.parseBody = parseBody; diff --git a/parse/src/main/java/com/parse/ParseInstallation.java b/parse/src/main/java/com/parse/ParseInstallation.java index 86b853945..d085a54c8 100644 --- a/parse/src/main/java/com/parse/ParseInstallation.java +++ b/parse/src/main/java/com/parse/ParseInstallation.java @@ -13,15 +13,14 @@ import android.content.pm.PackageManager; import android.text.TextUtils; +import com.parse.boltsinternal.Task; + import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.TimeZone; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * The {@code ParseInstallation} is a local representation of installation data that can be saved * and retrieved from the Parse cloud. @@ -133,35 +132,27 @@ public void setObjectId(String newObjectId) { } else { result = Task.forResult(null); } - return result.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return ParseInstallation.super.fetchAsync(sessionToken, toAwait); - } - }); + return result.onSuccessTask(task -> ParseInstallation.super.fetchAsync(sessionToken, toAwait)); } } @Override /* package */ Task saveAsync(final String sessionToken, final Task toAwait) { - return super.saveAsync(sessionToken, toAwait).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // Retry the fetch as a save operation because this Installation was deleted on the server. - if (task.getError() != null - && task.getError() instanceof ParseException) { - int errCode = ((ParseException) task.getError()).getCode(); - if (errCode == ParseException.OBJECT_NOT_FOUND - || (errCode == ParseException.MISSING_REQUIRED_FIELD_ERROR && getObjectId() == null)) { - synchronized (mutex) { - setState(new State.Builder(getState()).objectId(null).build()); - markAllFieldsDirty(); - return ParseInstallation.super.saveAsync(sessionToken, toAwait); - } + return super.saveAsync(sessionToken, toAwait).continueWithTask(task -> { + // Retry the fetch as a save operation because this Installation was deleted on the server. + if (task.getError() != null + && task.getError() instanceof ParseException) { + int errCode = ((ParseException) task.getError()).getCode(); + if (errCode == ParseException.OBJECT_NOT_FOUND + || (errCode == ParseException.MISSING_REQUIRED_FIELD_ERROR && getObjectId() == null)) { + synchronized (mutex) { + setState(new State.Builder(getState()).objectId(null).build()); + markAllFieldsDirty(); + return ParseInstallation.super.saveAsync(sessionToken, toAwait); } } - return task; } + return task; }); } @@ -174,22 +165,12 @@ public Task then(Task task) { return task; } - return task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return getCurrentInstallationController().setAsync(ParseInstallation.this); - } - }); + return task.onSuccessTask(task1 -> getCurrentInstallationController().setAsync(ParseInstallation.this)); } @Override /* package */ Task handleFetchResultAsync(final ParseObject.State newState) { - return super.handleFetchResultAsync(newState).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return getCurrentInstallationController().setAsync(ParseInstallation.this); - } - }); + return super.handleFetchResultAsync(newState).onSuccessTask(task -> getCurrentInstallationController().setAsync(ParseInstallation.this)); } // Android documentation states that getID may return one of many forms: America/LosAngeles, diff --git a/parse/src/main/java/com/parse/ParseJSONUtils.java b/parse/src/main/java/com/parse/ParseJSONUtils.java index 5e6371ed4..02081250a 100644 --- a/parse/src/main/java/com/parse/ParseJSONUtils.java +++ b/parse/src/main/java/com/parse/ParseJSONUtils.java @@ -8,8 +8,6 @@ */ package com.parse; -import androidx.annotation.NonNull; - import org.json.JSONException; import org.json.JSONObject; @@ -48,13 +46,7 @@ public static JSONObject create(JSONObject copyFrom, Collection excludes */ public static Iterable keys(JSONObject object) { final JSONObject finalObject = object; - return new Iterable() { - @NonNull - @Override - public Iterator iterator() { - return finalObject.keys(); - } - }; + return finalObject::keys; } /** diff --git a/parse/src/main/java/com/parse/ParseKeyValueCache.java b/parse/src/main/java/com/parse/ParseKeyValueCache.java index 20ad10f8c..5338a6b2c 100644 --- a/parse/src/main/java/com/parse/ParseKeyValueCache.java +++ b/parse/src/main/java/com/parse/ParseKeyValueCache.java @@ -14,11 +14,9 @@ import org.json.JSONObject; import java.io.File; -import java.io.FilenameFilter; import java.io.IOException; import java.io.RandomAccessFile; import java.util.Arrays; -import java.util.Comparator; import java.util.Date; /** @@ -81,12 +79,7 @@ static int size() { private static File getKeyValueCacheFile(String key) { final String suffix = '.' + key; - File[] matches = getKeyValueCacheDir().listFiles(new FilenameFilter() { - @Override - public boolean accept(File dir, String filename) { - return filename.endsWith(suffix); - } - }); + File[] matches = getKeyValueCacheDir().listFiles((dir, filename) -> filename.endsWith(suffix)); return (matches == null || matches.length == 0) ? null : matches[0]; } @@ -162,15 +155,12 @@ static void saveToKeyValueCache(String key, String value) { // Sometimes (i.e. tests) the time of lastModified isn't granular enough, // so we resort // to sorting by the file name which is always prepended with time in ms - Arrays.sort(files, new Comparator() { - @Override - public int compare(File f1, File f2) { - int dateCompare = Long.valueOf(f1.lastModified()).compareTo(f2.lastModified()); - if (dateCompare != 0) { - return dateCompare; - } else { - return f1.getName().compareTo(f2.getName()); - } + Arrays.sort(files, (f1, f2) -> { + int dateCompare = Long.compare(f1.lastModified(), f2.lastModified()); + if (dateCompare != 0) { + return dateCompare; + } else { + return f1.getName().compareTo(f2.getName()); } }); diff --git a/parse/src/main/java/com/parse/ParseObject.java b/parse/src/main/java/com/parse/ParseObject.java index d00526522..16250c1e1 100644 --- a/parse/src/main/java/com/parse/ParseObject.java +++ b/parse/src/main/java/com/parse/ParseObject.java @@ -11,9 +11,15 @@ import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.parse.boltsinternal.Capture; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -32,15 +38,9 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; -import com.parse.boltsinternal.Capture; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - /** * The {@code ParseObject} is a local representation of data that can be saved and retrieved from * the Parse cloud. @@ -61,15 +61,15 @@ public class ParseObject implements Parcelable { * @see #unpin() */ public static final String DEFAULT_PIN = "_default"; - static final String KEY_IS_DELETING_EVENTUALLY = "__isDeletingEventually"; - private static final String AUTO_CLASS_NAME = "_Automatic"; - private static final String TAG = "ParseObject"; /* REST JSON Keys */ public static final String KEY_OBJECT_ID = "objectId"; public static final String KEY_CREATED_AT = "createdAt"; public static final String KEY_UPDATED_AT = "updatedAt"; + static final String KEY_IS_DELETING_EVENTUALLY = "__isDeletingEventually"; + private static final String AUTO_CLASS_NAME = "_Automatic"; + private static final String TAG = "ParseObject"; private static final String KEY_CLASS_NAME = "className"; private static final String KEY_ACL = "ACL"; /* @@ -334,22 +334,16 @@ static Task enqueueForAll(final List objects, // Add fullTask to each of the objects' queues. final List> childTasks = new ArrayList<>(); for (ParseObject obj : objects) { - obj.taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task task) { - childTasks.add(task); - return fullTask; - } + obj.taskQueue.enqueue(task -> { + childTasks.add(task); + return fullTask; }); } // When all of the objects' queues are ready, signal fullTask that it's ready to go on. - Task.whenAll(childTasks).continueWith(new Continuation() { - @Override - public Void then(Task task) { - readyToStart.setResult(null); - return null; - } + Task.whenAll(childTasks).continueWith((Continuation) task -> { + readyToStart.setResult(null); + return null; }); return fullTask; } finally { @@ -475,46 +469,28 @@ private static Task deleteAllAsync( } } - return enqueueForAll(uniqueObjects, new Continuation>() { - @Override - public Task then(Task toAwait) { - return deleteAllAsync(uniqueObjects, sessionToken, toAwait); - } - }); + return enqueueForAll(uniqueObjects, toAwait -> deleteAllAsync(uniqueObjects, sessionToken, toAwait)); } private static Task deleteAllAsync( final List uniqueObjects, final String sessionToken, Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - int objectCount = uniqueObjects.size(); - List states = new ArrayList<>(objectCount); - for (int i = 0; i < objectCount; i++) { - ParseObject object = uniqueObjects.get(i); - object.validateDelete(); - states.add(object.getState()); - } - List> batchTasks = getObjectController().deleteAllAsync(states, sessionToken); - - List> tasks = new ArrayList<>(objectCount); - for (int i = 0; i < objectCount; i++) { - Task batchTask = batchTasks.get(i); - final T object = uniqueObjects.get(i); - tasks.add(batchTask.onSuccessTask(new Continuation>() { - @Override - public Task then(final Task batchTask) { - return object.handleDeleteResultAsync().continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return batchTask; - } - }); - } - })); - } - return Task.whenAll(tasks); - } + return toAwait.continueWithTask(task -> { + int objectCount = uniqueObjects.size(); + List states = new ArrayList<>(objectCount); + for (int i = 0; i < objectCount; i++) { + ParseObject object = uniqueObjects.get(i); + object.validateDelete(); + states.add(object.getState()); + } + List> batchTasks = getObjectController().deleteAllAsync(states, sessionToken); + + List> tasks = new ArrayList<>(objectCount); + for (int i = 0; i < objectCount; i++) { + Task batchTask = batchTasks.get(i); + final T object = uniqueObjects.get(i); + tasks.add(batchTask.onSuccessTask(batchTask1 -> object.handleDeleteResultAsync().continueWithTask(task1 -> batchTask1))); + } + return Task.whenAll(tasks); }); } @@ -548,12 +524,9 @@ public static void deleteAllInBackground(List objects * @return A {@link Task} that is resolved when deleteAll completes. */ public static Task deleteAllInBackground(final List objects) { - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String sessionToken = task.getResult(); - return deleteAllAsync(objects, sessionToken); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + String sessionToken = task.getResult(); + return deleteAllAsync(objects, sessionToken); }); } @@ -647,8 +620,8 @@ protected boolean visit(Object node) { private static void collectDirtyChildren(Object node, Collection dirtyChildren, Collection dirtyFiles) { collectDirtyChildren(node, dirtyChildren, dirtyFiles, - new HashSet(), - new HashSet()); + new HashSet<>(), + new HashSet<>()); } /** @@ -681,12 +654,9 @@ private static Task deepSaveAsync(final Object object, final String sessio for (ParseFile file : files) { tasks.add(file.saveAsync(sessionToken, null, null)); } - Task filesTask = Task.whenAll(tasks).continueWith(new Continuation() { - @Override - public Void then(Task task) { - filesComplete.set(true); - return null; - } + Task filesTask = Task.whenAll(tasks).continueWith(task -> { + filesComplete.set(true); + return null; }); // objects will need to wait for users to be complete since they may be nested children. @@ -695,55 +665,39 @@ public Void then(Task task) { for (final ParseUser user : users) { tasks.add(user.saveAsync(sessionToken)); } - Task usersTask = Task.whenAll(tasks).continueWith(new Continuation() { - @Override - public Void then(Task task) { - usersComplete.set(true); - return null; - } + Task usersTask = Task.whenAll(tasks).continueWith(task -> { + usersComplete.set(true); + return null; }); final Capture> remaining = new Capture<>(objects); - Task objectsTask = Task.forResult(null).continueWhile(new Callable() { - @Override - public Boolean call() { - return remaining.get().size() > 0; - } - }, new Continuation>() { - @Override - public Task then(Task task) { - // Partition the objects into two sets: those that can be save immediately, - // and those that rely on other objects to be created first. - final List current = new ArrayList<>(); - final Set nextBatch = new HashSet<>(); - for (ParseObject obj : remaining.get()) { - if (obj.canBeSerialized()) { - current.add(obj); - } else { - nextBatch.add(obj); - } - } - remaining.set(nextBatch); - - if (current.size() == 0 && filesComplete.get() && usersComplete.get()) { - // We do cycle-detection when building the list of objects passed to this function, so - // this should never get called. But we should check for it anyway, so that we get an - // exception instead of an infinite loop. - throw new RuntimeException("Unable to save a ParseObject with a relation to a cycle."); + Task objectsTask = Task.forResult(null).continueWhile(() -> remaining.get().size() > 0, task -> { + // Partition the objects into two sets: those that can be save immediately, + // and those that rely on other objects to be created first. + final List current = new ArrayList<>(); + final Set nextBatch = new HashSet<>(); + for (ParseObject obj : remaining.get()) { + if (obj.canBeSerialized()) { + current.add(obj); + } else { + nextBatch.add(obj); } + } + remaining.set(nextBatch); - // Package all save commands together - if (current.size() == 0) { - return Task.forResult(null); - } + if (current.size() == 0 && filesComplete.get() && usersComplete.get()) { + // We do cycle-detection when building the list of objects passed to this function, so + // this should never get called. But we should check for it anyway, so that we get an + // exception instead of an infinite loop. + throw new RuntimeException("Unable to save a ParseObject with a relation to a cycle."); + } - return enqueueForAll(current, new Continuation>() { - @Override - public Task then(Task toAwait) { - return saveAllAsync(current, sessionToken, toAwait); - } - }); + // Package all save commands together + if (current.size() == 0) { + return Task.forResult(null); } + + return enqueueForAll(current, toAwait -> saveAllAsync(current, sessionToken, toAwait)); }); return Task.whenAll(Arrays.asList(filesTask, usersTask, objectsTask)); @@ -751,51 +705,42 @@ public Task then(Task toAwait) { private static Task saveAllAsync( final List uniqueObjects, final String sessionToken, Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - int objectCount = uniqueObjects.size(); - List states = new ArrayList<>(objectCount); - List operationsList = new ArrayList<>(objectCount); - List decoders = new ArrayList<>(objectCount); - for (int i = 0; i < objectCount; i++) { - ParseObject object = uniqueObjects.get(i); - object.updateBeforeSave(); - object.validateSave(); - - states.add(object.getState()); - operationsList.add(object.startSave()); - final Map fetchedObjects = object.collectFetchedObjects(); - decoders.add(new KnownParseObjectDecoder(fetchedObjects)); - } - List> batchTasks = getObjectController().saveAllAsync( - states, operationsList, sessionToken, decoders); - - List> tasks = new ArrayList<>(objectCount); - for (int i = 0; i < objectCount; i++) { - Task batchTask = batchTasks.get(i); - final T object = uniqueObjects.get(i); - final ParseOperationSet operations = operationsList.get(i); - tasks.add(batchTask.continueWithTask(new Continuation>() { - @Override - public Task then(final Task batchTask) { - ParseObject.State result = batchTask.getResult(); // will be null on failure - return object.handleSaveResultAsync(result, operations).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isFaulted() || task.isCancelled()) { - return task; - } - - // We still want to propagate batchTask errors - return batchTask.makeVoid(); - } - }); + return toAwait.continueWithTask(task -> { + int objectCount = uniqueObjects.size(); + List states = new ArrayList<>(objectCount); + List operationsList = new ArrayList<>(objectCount); + List decoders = new ArrayList<>(objectCount); + for (int i = 0; i < objectCount; i++) { + ParseObject object = uniqueObjects.get(i); + object.updateBeforeSave(); + object.validateSave(); + + states.add(object.getState()); + operationsList.add(object.startSave()); + final Map fetchedObjects = object.collectFetchedObjects(); + decoders.add(new KnownParseObjectDecoder(fetchedObjects)); + } + List> batchTasks = getObjectController().saveAllAsync( + states, operationsList, sessionToken, decoders); + + List> tasks = new ArrayList<>(objectCount); + for (int i = 0; i < objectCount; i++) { + Task batchTask = batchTasks.get(i); + final T object = uniqueObjects.get(i); + final ParseOperationSet operations = operationsList.get(i); + tasks.add(batchTask.continueWithTask(batchTask1 -> { + State result = batchTask1.getResult(); // will be null on failure + return object.handleSaveResultAsync(result, operations).continueWithTask(task1 -> { + if (task1.isFaulted() || task1.isCancelled()) { + return task1; } - })); - } - return Task.whenAll(tasks); + + // We still want to propagate batchTask errors + return batchTask1.makeVoid(); + }); + })); } + return Task.whenAll(tasks); }); } @@ -829,52 +774,43 @@ public static void saveAllInBackground(List objects, * @return A {@link Task} that is resolved when saveAll completes. */ public static Task saveAllInBackground(final List objects) { - return ParseUser.getCurrentUserAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseUser current = task.getResult(); - if (current == null) { - return Task.forResult(null); + return ParseUser.getCurrentUserAsync().onSuccessTask(task -> { + final ParseUser current = task.getResult(); + if (current == null) { + return Task.forResult(null); + } + if (!current.isLazy()) { + return Task.forResult(current.getSessionToken()); + } + + // The current user is lazy/unresolved. If it is attached to any of the objects via ACL, + // we'll need to resolve/save it before proceeding. + for (ParseObject object : objects) { + if (!object.isDataAvailable(KEY_ACL)) { + continue; } - if (!current.isLazy()) { - return Task.forResult(current.getSessionToken()); + final ParseACL acl = object.getACL(false); + if (acl == null) { + continue; } - - // The current user is lazy/unresolved. If it is attached to any of the objects via ACL, - // we'll need to resolve/save it before proceeding. - for (ParseObject object : objects) { - if (!object.isDataAvailable(KEY_ACL)) { - continue; - } - final ParseACL acl = object.getACL(false); - if (acl == null) { - continue; - } - final ParseUser user = acl.getUnresolvedUser(); - if (user != null && user.isCurrentUser()) { - // We only need to find one, since there's only one current user. - return user.saveAsync(null).onSuccess(new Continuation() { - @Override - public String then(Task task) { - if (acl.hasUnresolvedUser()) { - throw new IllegalStateException("ACL has an unresolved ParseUser. " - + "Save or sign up before attempting to serialize the ACL."); - } - return user.getSessionToken(); - } - }); - } + final ParseUser user = acl.getUnresolvedUser(); + if (user != null && user.isCurrentUser()) { + // We only need to find one, since there's only one current user. + return user.saveAsync(null).onSuccess(task1 -> { + if (acl.hasUnresolvedUser()) { + throw new IllegalStateException("ACL has an unresolved ParseUser. " + + "Save or sign up before attempting to serialize the ACL."); + } + return user.getSessionToken(); + }); } - - // There were no objects with ACLs pointing to unresolved users. - return Task.forResult(null); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final String sessionToken = task.getResult(); - return deepSaveAsync(objects, sessionToken); } + + // There were no objects with ACLs pointing to unresolved users. + return Task.forResult(null); + }).onSuccessTask(task -> { + final String sessionToken = task.getResult(); + return deepSaveAsync(objects, sessionToken); }); } @@ -916,17 +852,9 @@ public static void fetchAllIfNeededInBackground(final Li private static Task> fetchAllAsync( final List objects, final boolean onlyIfNeeded) { - return ParseUser.getCurrentUserAsync().onSuccessTask(new Continuation>>() { - @Override - public Task> then(Task task) { - final ParseUser user = task.getResult(); - return enqueueForAll(objects, new Continuation>>() { - @Override - public Task> then(Task task) { - return fetchAllAsync(objects, user, onlyIfNeeded, task); - } - }); - } + return ParseUser.getCurrentUserAsync().onSuccessTask(task -> { + final ParseUser user = task.getResult(); + return enqueueForAll(objects, task1 -> fetchAllAsync(objects, user, onlyIfNeeded, task1)); }); } @@ -969,37 +897,29 @@ private static Task> fetchAllAsync( final ParseQuery query = ParseQuery.getQuery(className) .whereContainedIn(KEY_OBJECT_ID, objectIds) .setLimit(objectIds.size()); - return toAwait.continueWithTask(new Continuation>>() { - @Override - public Task> then(Task task) { - return query.findAsync(query.getBuilder().build(), user, null); + return toAwait.continueWithTask(task -> query.findAsync(query.getBuilder().build(), user, null)).onSuccess(task -> { + Map resultMap = new HashMap<>(); + for (T o : task.getResult()) { + resultMap.put(o.getObjectId(), o); } - }).onSuccess(new Continuation, List>() { - @Override - public List then(Task> task) throws Exception { - Map resultMap = new HashMap<>(); - for (T o : task.getResult()) { - resultMap.put(o.getObjectId(), o); + for (T object : objects) { + if (onlyIfNeeded && object.isDataAvailable()) { + continue; } - for (T object : objects) { - if (onlyIfNeeded && object.isDataAvailable()) { - continue; - } - T newObject = resultMap.get(object.getObjectId()); - if (newObject == null) { - throw new ParseException( - ParseException.OBJECT_NOT_FOUND, - "Object id " + object.getObjectId() + " does not exist"); - } - if (!Parse.isLocalDatastoreEnabled()) { - // We only need to merge if LDS is disabled, since single instance will do the merging - // for us. - object.mergeFromObject(newObject); - } + T newObject = resultMap.get(object.getObjectId()); + if (newObject == null) { + throw new ParseException( + ParseException.OBJECT_NOT_FOUND, + "Object id " + object.getObjectId() + " does not exist"); + } + if (!Parse.isLocalDatastoreEnabled()) { + // We only need to merge if LDS is disabled, since single instance will do the merging + // for us. + object.mergeFromObject(newObject); } - return objects; } + return objects; }); } @@ -1109,55 +1029,44 @@ private static Task pinAllInBackground(final Strin // Resolve and persist unresolved users attached via ACL, similarly how we do in saveAsync for (final ParseObject object : objects) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - if (!object.isDataAvailable(KEY_ACL)) { - return Task.forResult(null); - } - - final ParseACL acl = object.getACL(false); - if (acl == null) { - return Task.forResult(null); - } + task = task.onSuccessTask(task13 -> { + if (!object.isDataAvailable(KEY_ACL)) { + return Task.forResult(null); + } - ParseUser user = acl.getUnresolvedUser(); - if (user == null || !user.isCurrentUser()) { - return Task.forResult(null); - } + final ParseACL acl = object.getACL(false); + if (acl == null) { + return Task.forResult(null); + } - return ParseUser.pinCurrentUserIfNeededAsync(user); + ParseUser user = acl.getUnresolvedUser(); + if (user == null || !user.isCurrentUser()) { + return Task.forResult(null); } + + return ParseUser.pinCurrentUserIfNeededAsync(user); }); } - return task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return Parse.getLocalDatastore().pinAllObjectsAsync( - name != null ? name : DEFAULT_PIN, - objects, - includeAllChildren); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - // Hack to emulate persisting current user on disk after a save like in ParseUser#saveAsync - // Note: This does not persist current user if it's a child object of `objects`, it probably - // should, but we can't unless we do something similar to #deepSaveAsync. - if (ParseCorePlugins.PIN_CURRENT_USER.equals(name)) { - return task; - } - for (ParseObject object : objects) { - if (object instanceof ParseUser) { - final ParseUser user = (ParseUser) object; - if (user.isCurrentUser()) { - return ParseUser.pinCurrentUserIfNeededAsync(user); - } + return task.onSuccessTask(task12 -> Parse.getLocalDatastore().pinAllObjectsAsync( + name != null ? name : DEFAULT_PIN, + objects, + includeAllChildren)).onSuccessTask(task1 -> { + // Hack to emulate persisting current user on disk after a save like in ParseUser#saveAsync + // Note: This does not persist current user if it's a child object of `objects`, it probably + // should, but we can't unless we do something similar to #deepSaveAsync. + if (ParseCorePlugins.PIN_CURRENT_USER.equals(name)) { + return task1; + } + for (ParseObject object : objects) { + if (object instanceof ParseUser) { + final ParseUser user = (ParseUser) object; + if (user.isCurrentUser()) { + return ParseUser.pinCurrentUserIfNeededAsync(user); } } - return task; } + return task1; }); } @@ -2087,12 +1996,7 @@ Task handleSaveResultAsync( */ final OfflineStore store = Parse.getLocalDatastore(); if (store != null) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.fetchLocallyAsync(ParseObject.this).makeVoid(); - } - }); + task = task.onSuccessTask(task15 -> store.fetchLocallyAsync(ParseObject.this).makeVoid()); } final boolean success = result != null; @@ -2109,14 +2013,11 @@ public Task then(Task task) { ParseOperationSet nextOperation = opIterator.next(); nextOperation.mergeFrom(operationsBeforeSave); if (store != null) { - task = task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isFaulted()) { - return Task.forResult(null); - } else { - return store.updateDataForObjectAsync(ParseObject.this); - } + task = task.continueWithTask(task14 -> { + if (task14.isFaulted()) { + return Task.forResult(null); + } else { + return store.updateDataForObjectAsync(ParseObject.this); } }); } @@ -2125,42 +2026,31 @@ public Task then(Task task) { } // fetchLocallyAsync will return an error if this object isn't in the LDS yet and that's ok - task = task.continueWith(new Continuation() { - @Override - public Void then(Task task) { - synchronized (mutex) { - State newState; - if (result.isComplete()) { - // Result is complete, so just replace - newState = result; - } else { - // Result is incomplete, so we'll need to apply it to the current state - newState = getState().newBuilder() - .apply(operationsBeforeSave) - .apply(result) - .build(); - } - setState(newState); + task = task.continueWith(task13 -> { + synchronized (mutex) { + State newState; + if (result.isComplete()) { + // Result is complete, so just replace + newState = result; + } else { + // Result is incomplete, so we'll need to apply it to the current state + newState = getState().newBuilder() + .apply(operationsBeforeSave) + .apply(result) + .build(); } - return null; + setState(newState); } + return null; }); if (store != null) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.updateDataForObjectAsync(ParseObject.this); - } - }); + task = task.onSuccessTask(task12 -> store.updateDataForObjectAsync(ParseObject.this)); } - task = task.onSuccess(new Continuation() { - @Override - public Void then(Task task) { - saveEvent.invoke(ParseObject.this, null); - return null; - } + task = task.onSuccess(task1 -> { + saveEvent.invoke(ParseObject.this, null); + return null; }); return task; @@ -2195,57 +2085,43 @@ public final void save() throws ParseException { * @return A {@link Task} that is resolved when the save completes. */ public final Task saveInBackground() { - return ParseUser.getCurrentUserAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseUser current = task.getResult(); - if (current == null) { - return Task.forResult(null); - } - if (!current.isLazy()) { - return Task.forResult(current.getSessionToken()); - } + return ParseUser.getCurrentUserAsync().onSuccessTask(task -> { + final ParseUser current = task.getResult(); + if (current == null) { + return Task.forResult(null); + } + if (!current.isLazy()) { + return Task.forResult(current.getSessionToken()); + } - // The current user is lazy/unresolved. If it is attached to us via ACL, we'll need to - // resolve/save it before proceeding. - if (!isDataAvailable(KEY_ACL)) { - return Task.forResult(null); - } - final ParseACL acl = getACL(false); - if (acl == null) { - return Task.forResult(null); - } - final ParseUser user = acl.getUnresolvedUser(); - if (user == null || !user.isCurrentUser()) { - return Task.forResult(null); - } - return user.saveAsync(null).onSuccess(new Continuation() { - @Override - public String then(Task task) { - if (acl.hasUnresolvedUser()) { - throw new IllegalStateException("ACL has an unresolved ParseUser. " - + "Save or sign up before attempting to serialize the ACL."); - } - return user.getSessionToken(); - } - }); + // The current user is lazy/unresolved. If it is attached to us via ACL, we'll need to + // resolve/save it before proceeding. + if (!isDataAvailable(KEY_ACL)) { + return Task.forResult(null); } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final String sessionToken = task.getResult(); - return saveAsync(sessionToken); + final ParseACL acl = getACL(false); + if (acl == null) { + return Task.forResult(null); + } + final ParseUser user = acl.getUnresolvedUser(); + if (user == null || !user.isCurrentUser()) { + return Task.forResult(null); } + return user.saveAsync(null).onSuccess(task1 -> { + if (acl.hasUnresolvedUser()) { + throw new IllegalStateException("ACL has an unresolved ParseUser. " + + "Save or sign up before attempting to serialize the ACL."); + } + return user.getSessionToken(); + }); + }).onSuccessTask(task -> { + final String sessionToken = task.getResult(); + return saveAsync(sessionToken); }); } Task saveAsync(final String sessionToken) { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return saveAsync(sessionToken, toAwait); - } - }); + return taskQueue.enqueue(toAwait -> saveAsync(sessionToken, toAwait)); } Task saveAsync(final String sessionToken, final Task toAwait) { @@ -2274,29 +2150,20 @@ Task saveAsync(final String sessionToken, final Task toAwait) { return task.onSuccessTask( TaskQueue.waitFor(toAwait) - ).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final Map fetchedObjects = collectFetchedObjects(); - ParseDecoder decoder = new KnownParseObjectDecoder(fetchedObjects); - return getObjectController().saveAsync(getState(), operations, sessionToken, decoder); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(final Task saveTask) { - ParseObject.State result = saveTask.getResult(); - return handleSaveResultAsync(result, operations).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isFaulted() || task.isCancelled()) { - return task; - } - - // We still want to propagate saveTask errors - return saveTask.makeVoid(); - } - }); - } + ).onSuccessTask(task12 -> { + final Map fetchedObjects = collectFetchedObjects(); + ParseDecoder decoder = new KnownParseObjectDecoder(fetchedObjects); + return getObjectController().saveAsync(getState(), operations, sessionToken, decoder); + }).continueWithTask(saveTask -> { + State result = saveTask.getResult(); + return handleSaveResultAsync(result, operations).continueWithTask(task1 -> { + if (task1.isFaulted() || task1.isCancelled()) { + return task1; + } + + // We still want to propagate saveTask errors + return saveTask.makeVoid(); + }); }); } @@ -2428,12 +2295,9 @@ public final Task saveEventually() { // ParsePinningEventuallyQueue calls handleSaveEventuallyResultAsync directly. handleSaveResultTask = runEventuallyTask.makeVoid(); } else { - handleSaveResultTask = runEventuallyTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - JSONObject json = task.getResult(); - return handleSaveEventuallyResultAsync(json, operationSet); - } + handleSaveResultTask = runEventuallyTask.onSuccessTask(task -> { + JSONObject json = task.getResult(); + return handleSaveEventuallyResultAsync(json, operationSet); }); } return handleSaveResultTask; @@ -2448,18 +2312,10 @@ private void enqueueSaveEventuallyOperationAsync(final ParseOperationSet operati "This should only be used to enqueue saveEventually operation sets"); } - taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseEventuallyQueue cache = Parse.getEventuallyQueue(); - return cache.waitForOperationSetAndEventuallyPin(operationSet, null).makeVoid(); - } - }); - } - }); + taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task -> { + ParseEventuallyQueue cache = Parse.getEventuallyQueue(); + return cache.waitForOperationSetAndEventuallyPin(operationSet, null).makeVoid(); + })); } /** @@ -2474,15 +2330,12 @@ Task handleSaveEventuallyResultAsync( final boolean success = json != null; Task handleSaveResultTask = handleSaveResultAsync(json, operationSet); - return handleSaveResultTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - if (success) { - Parse.getEventuallyQueue() - .notifyTestHelper(ParseCommandCache.TestHelper.OBJECT_UPDATED); - } - return task; + return handleSaveResultTask.onSuccessTask(task -> { + if (success) { + Parse.getEventuallyQueue() + .notifyTestHelper(ParseCommandCache.TestHelper.OBJECT_UPDATED); } + return task; }); } @@ -2557,12 +2410,7 @@ public final Task deleteEventually() { // ParsePinningEventuallyQueue calls handleDeleteEventuallyResultAsync directly. handleDeleteResultTask = runEventuallyTask.makeVoid(); } else { - handleDeleteResultTask = runEventuallyTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return handleDeleteEventuallyResultAsync(); - } - }); + handleDeleteResultTask = runEventuallyTask.onSuccessTask(task -> handleDeleteEventuallyResultAsync()); } return handleDeleteResultTask; @@ -2579,13 +2427,10 @@ Task handleDeleteEventuallyResultAsync() { } Task handleDeleteResultTask = handleDeleteResultAsync(); - return handleDeleteResultTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - Parse.getEventuallyQueue() - .notifyTestHelper(ParseCommandCache.TestHelper.OBJECT_REMOVED); - return task; - } + return handleDeleteResultTask.onSuccessTask(task -> { + Parse.getEventuallyQueue() + .notifyTestHelper(ParseCommandCache.TestHelper.OBJECT_REMOVED); + return task; }); } @@ -2603,58 +2448,39 @@ Task handleFetchResultAsync(final ParseObject.State result) { */ final OfflineStore store = Parse.getLocalDatastore(); if (store != null) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.fetchLocallyAsync(ParseObject.this).makeVoid(); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // Catch CACHE_MISS - if (task.getError() instanceof ParseException - && ((ParseException) task.getError()).getCode() == ParseException.CACHE_MISS) { - return null; - } - return task; + task = task.onSuccessTask(task15 -> store.fetchLocallyAsync(ParseObject.this).makeVoid()).continueWithTask(task14 -> { + // Catch CACHE_MISS + if (task14.getError() instanceof ParseException + && ((ParseException) task14.getError()).getCode() == ParseException.CACHE_MISS) { + return null; } + return task14; }); } - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (mutex) { - State newState; - if (result.isComplete()) { - // Result is complete, so just replace - newState = result; - } else { - // Result is incomplete, so we'll need to apply it to the current state - newState = getState().newBuilder().apply(result).build(); - } - setState(newState); + task = task.onSuccessTask(task13 -> { + synchronized (mutex) { + State newState; + if (result.isComplete()) { + // Result is complete, so just replace + newState = result; + } else { + // Result is incomplete, so we'll need to apply it to the current state + newState = getState().newBuilder().apply(result).build(); } - return null; + setState(newState); } + return null; }); if (store != null) { - task = task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return store.updateDataForObjectAsync(ParseObject.this); - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // Catch CACHE_MISS - if (task.getError() instanceof ParseException - && ((ParseException) task.getError()).getCode() == ParseException.CACHE_MISS) { - return null; - } - return task; + task = task.onSuccessTask(task12 -> store.updateDataForObjectAsync(ParseObject.this)).continueWithTask(task1 -> { + // Catch CACHE_MISS + if (task1.getError() instanceof ParseException + && ((ParseException) task1.getError()).getCode() == ParseException.CACHE_MISS) { + return null; } + return task1; }); } @@ -2675,30 +2501,19 @@ public T fetch() throws ParseException { @SuppressWarnings("unchecked") Task fetchAsync( final String sessionToken, Task toAwait) { - return toAwait.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - State state; - Map fetchedObjects; - synchronized (mutex) { - state = getState(); - fetchedObjects = collectFetchedObjects(); - } - ParseDecoder decoder = new KnownParseObjectDecoder(fetchedObjects); - return getObjectController().fetchAsync(state, sessionToken, decoder); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseObject.State result = task.getResult(); - return handleFetchResultAsync(result); - } - }).onSuccess(new Continuation() { - @Override - public T then(Task task) { - return (T) ParseObject.this; + return toAwait.onSuccessTask(task -> { + State state; + Map fetchedObjects; + synchronized (mutex) { + state = getState(); + fetchedObjects = collectFetchedObjects(); } - }); + ParseDecoder decoder = new KnownParseObjectDecoder(fetchedObjects); + return getObjectController().fetchAsync(state, sessionToken, decoder); + }).onSuccessTask(task -> { + State result = task.getResult(); + return handleFetchResultAsync(result); + }).onSuccess(task -> (T) ParseObject.this); } /** @@ -2708,17 +2523,9 @@ public T then(Task task) { * @return A {@link Task} that is resolved when fetch completes. */ public final Task fetchInBackground() { - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final String sessionToken = task.getResult(); - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return fetchAsync(sessionToken, toAwait); - } - }); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + final String sessionToken = task.getResult(); + return taskQueue.enqueue(toAwait -> fetchAsync(sessionToken, toAwait)); }); } @@ -2743,20 +2550,14 @@ public final Task fetchIfNeededInBackground() { if (isDataAvailable()) { return Task.forResult((T) this); } - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final String sessionToken = task.getResult(); - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - if (isDataAvailable()) { - return Task.forResult((T) ParseObject.this); - } - return fetchAsync(sessionToken, toAwait); - } - }); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + final String sessionToken = task.getResult(); + return taskQueue.enqueue(toAwait -> { + if (isDataAvailable()) { + return Task.forResult((T) ParseObject.this); + } + return fetchAsync(sessionToken, toAwait); + }); }); } @@ -2791,29 +2592,18 @@ void validateDelete() { private Task deleteAsync(final String sessionToken, Task toAwait) { validateDelete(); - return toAwait.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - isDeleting = true; - if (state.objectId() == null) { - return task.cast(); // no reason to call delete since it doesn't exist - } - return deleteAsync(sessionToken); + return toAwait.onSuccessTask(task -> { + isDeleting = true; + if (state.objectId() == null) { + return task.cast(); // no reason to call delete since it doesn't exist } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return handleDeleteResultAsync(); - } - }).continueWith(new Continuation() { - @Override - public Void then(Task task) throws Exception { - isDeleting = false; - if (task.isFaulted()) { - throw task.getError(); - } - return null; + return deleteAsync(sessionToken); + }).onSuccessTask(task -> handleDeleteResultAsync()).continueWith(task -> { + isDeleting = false; + if (task.isFaulted()) { + throw task.getError(); } + return null; }); } @@ -2837,16 +2627,13 @@ Task handleDeleteResultAsync() { final OfflineStore store = Parse.getLocalDatastore(); if (store != null) { - task = task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (mutex) { - if (isDeleted) { - store.unregisterObject(ParseObject.this); - return store.deleteDataForObjectAsync(ParseObject.this); - } else { - return store.updateDataForObjectAsync(ParseObject.this); - } + task = task.continueWithTask(task1 -> { + synchronized (mutex) { + if (isDeleted) { + store.unregisterObject(ParseObject.this); + return store.deleteDataForObjectAsync(ParseObject.this); + } else { + return store.updateDataForObjectAsync(ParseObject.this); } } }); @@ -2862,17 +2649,9 @@ public Task then(Task task) { * @return A {@link Task} that is resolved when delete completes. */ public final Task deleteInBackground() { - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final String sessionToken = task.getResult(); - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return deleteAsync(sessionToken, toAwait); - } - }); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + final String sessionToken = task.getResult(); + return taskQueue.enqueue(toAwait -> deleteAsync(sessionToken, toAwait)); }); } @@ -4060,8 +3839,8 @@ public String toString() { static abstract class Init { + final Map serverData = new HashMap<>(); private final String className; - Map serverData = new HashMap<>(); private String objectId; private long createdAt = -1; private long updatedAt = -1; diff --git a/parse/src/main/java/com/parse/ParseObjectController.java b/parse/src/main/java/com/parse/ParseObjectController.java index 9a2204bff..655070d80 100644 --- a/parse/src/main/java/com/parse/ParseObjectController.java +++ b/parse/src/main/java/com/parse/ParseObjectController.java @@ -8,10 +8,10 @@ */ package com.parse; -import java.util.List; - import com.parse.boltsinternal.Task; +import java.util.List; + interface ParseObjectController { Task fetchAsync( diff --git a/parse/src/main/java/com/parse/ParseObjectParcelDecoder.java b/parse/src/main/java/com/parse/ParseObjectParcelDecoder.java index c9a16caf7..09c589458 100644 --- a/parse/src/main/java/com/parse/ParseObjectParcelDecoder.java +++ b/parse/src/main/java/com/parse/ParseObjectParcelDecoder.java @@ -14,7 +14,7 @@ */ /* package */ class ParseObjectParcelDecoder extends ParseParcelDecoder { - private Map objects = new HashMap<>(); + private final Map objects = new HashMap<>(); public ParseObjectParcelDecoder() { } diff --git a/parse/src/main/java/com/parse/ParseObjectParcelEncoder.java b/parse/src/main/java/com/parse/ParseObjectParcelEncoder.java index 4d3634c0a..de9a408f7 100644 --- a/parse/src/main/java/com/parse/ParseObjectParcelEncoder.java +++ b/parse/src/main/java/com/parse/ParseObjectParcelEncoder.java @@ -13,7 +13,7 @@ */ /* package */ class ParseObjectParcelEncoder extends ParseParcelEncoder { - private Set ids = new HashSet<>(); + private final Set ids = new HashSet<>(); public ParseObjectParcelEncoder() { } diff --git a/parse/src/main/java/com/parse/ParsePinningEventuallyQueue.java b/parse/src/main/java/com/parse/ParsePinningEventuallyQueue.java index 0e1cd9570..355f376d2 100644 --- a/parse/src/main/java/com/parse/ParsePinningEventuallyQueue.java +++ b/parse/src/main/java/com/parse/ParsePinningEventuallyQueue.java @@ -11,9 +11,12 @@ import android.Manifest; import android.content.Context; -import android.content.Intent; import android.net.ConnectivityManager; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + import org.json.JSONObject; import java.util.ArrayList; @@ -22,10 +25,6 @@ import java.util.HashMap; import java.util.List; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - /** * Manages all *Eventually calls when the local datastore is enabled. *

@@ -46,56 +45,53 @@ class ParsePinningEventuallyQueue extends ParseEventuallyQueue { /** * TCS that is held until a {@link ParseOperationSet} is completed. */ - private HashMap> pendingOperationSetUUIDTasks = + private final HashMap> pendingOperationSetUUIDTasks = new HashMap<>(); /** * Queue for reading/writing eventually operations. Makes all reads/writes atomic operations. */ - private TaskQueue taskQueue = new TaskQueue(); + private final TaskQueue taskQueue = new TaskQueue(); /** * Queue for running *Eventually operations. It uses waitForOperationSetAndEventuallyPin to * synchronize {@link ParseObject#taskQueue} until they are both ready to process the same * ParseOperationSet. */ - private TaskQueue operationSetTaskQueue = new TaskQueue(); + private final TaskQueue operationSetTaskQueue = new TaskQueue(); /** * List of {@link ParseOperationSet#uuid} that are currently queued in * {@link ParsePinningEventuallyQueue#operationSetTaskQueue}. */ - private ArrayList eventuallyPinUUIDQueue = new ArrayList<>(); - /** - * TCS that is created when there is no internet connection and isn't resolved until connectivity - * is achieved. - *

- * If an error is set, it means that we are trying to clear out the taskQueues. - */ - private TaskCompletionSource connectionTaskCompletionSource = new TaskCompletionSource<>(); - private ConnectivityNotifier notifier; - private ConnectivityNotifier.ConnectivityListener listener = new ConnectivityNotifier.ConnectivityListener() { - @Override - public void networkConnectivityStatusChanged(Context context, Intent intent) { - boolean connectionLost = - intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); - if (connectionLost) { - setConnected(false); - } else { - setConnected(ConnectivityNotifier.isConnected(context)); - } - } - }; + private final ArrayList eventuallyPinUUIDQueue = new ArrayList<>(); + private final ConnectivityNotifier notifier; /** * Map of eventually operation UUID to TCS that is resolved when the operation is complete. */ - private HashMap> pendingEventuallyTasks = + private final HashMap> pendingEventuallyTasks = new HashMap<>(); /** * Map of eventually operation UUID to matching ParseOperationSet. */ - private HashMap uuidToOperationSet = new HashMap<>(); + private final HashMap uuidToOperationSet = new HashMap<>(); /** * Map of eventually operation UUID to matching EventuallyPin. */ - private HashMap uuidToEventuallyPin = new HashMap<>(); + private final HashMap uuidToEventuallyPin = new HashMap<>(); + /** + * TCS that is created when there is no internet connection and isn't resolved until connectivity + * is achieved. + *

+ * If an error is set, it means that we are trying to clear out the taskQueues. + */ + private TaskCompletionSource connectionTaskCompletionSource = new TaskCompletionSource<>(); + private final ConnectivityNotifier.ConnectivityListener listener = (context, intent) -> { + boolean connectionLost = + intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); + if (connectionLost) { + setConnected(false); + } else { + setConnected(ConnectivityNotifier.isConnected(context)); + } + }; public ParsePinningEventuallyQueue(Context context, ParseHttpClient client) { setConnected(ConnectivityNotifier.isConnected(context)); @@ -143,36 +139,20 @@ public int pendingCount() { public Task pendingCountAsync() { final TaskCompletionSource tcs = new TaskCompletionSource<>(); - taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return pendingCountAsync(toAwait).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - int count = task.getResult(); - tcs.setResult(count); - return Task.forResult(null); - } - }); - } - }); + taskQueue.enqueue((Continuation>) toAwait -> pendingCountAsync(toAwait).continueWithTask(task -> { + int count = task.getResult(); + tcs.setResult(count); + return Task.forResult(null); + })); return tcs.getTask(); } public Task pendingCountAsync(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return EventuallyPin.findAllPinned().continueWithTask(new Continuation, Task>() { - @Override - public Task then(Task> task) { - List pins = task.getResult(); - return Task.forResult(pins.size()); - } - }); - } - }); + return toAwait.continueWithTask(task -> EventuallyPin.findAllPinned().continueWithTask(task1 -> { + List pins = task1.getResult(); + return Task.forResult(pins.size()); + })); } @Override @@ -232,55 +212,41 @@ public Task enqueueEventuallyAsync(final ParseRESTCommand command, Parse.requirePermission(Manifest.permission.ACCESS_NETWORK_STATE); final TaskCompletionSource tcs = new TaskCompletionSource<>(); - taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return enqueueEventuallyAsync(command, object, toAwait, tcs); - } - }); + taskQueue.enqueue(toAwait -> enqueueEventuallyAsync(command, object, toAwait, tcs)); return tcs.getTask(); } private Task enqueueEventuallyAsync(final ParseRESTCommand command, final ParseObject object, Task toAwait, final TaskCompletionSource tcs) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task toAwait) { - Task pinTask = EventuallyPin.pinEventuallyCommand(object, command); - - return pinTask.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - EventuallyPin pin = task.getResult(); - Exception error = task.getError(); - if (error != null) { - if (Parse.LOG_LEVEL_WARNING >= Parse.getLogLevel()) { - PLog.w(TAG, "Unable to save command for later.", error); - } - notifyTestHelper(TestHelper.COMMAND_NOT_ENQUEUED); - return Task.forResult(null); - } + return toAwait.continueWithTask(toAwait1 -> { + Task pinTask = EventuallyPin.pinEventuallyCommand(object, command); - pendingOperationSetUUIDTasks.put(pin.getUUID(), tcs); - - // We don't need to wait for this. - populateQueueAsync().continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - /* - * We need to wait until after we populated the operationSetTaskQueue to notify - * that we've enqueued this command. - */ - notifyTestHelper(TestHelper.COMMAND_ENQUEUED); - return task; - } - }); - - return task.makeVoid(); + return pinTask.continueWithTask(task -> { + EventuallyPin pin = task.getResult(); + Exception error = task.getError(); + if (error != null) { + if (Parse.LOG_LEVEL_WARNING >= Parse.getLogLevel()) { + PLog.w(TAG, "Unable to save command for later.", error); } + notifyTestHelper(TestHelper.COMMAND_NOT_ENQUEUED); + return Task.forResult(null); + } + + pendingOperationSetUUIDTasks.put(pin.getUUID(), tcs); + + // We don't need to wait for this. + populateQueueAsync().continueWithTask(task1 -> { + /* + * We need to wait until after we populated the operationSetTaskQueue to notify + * that we've enqueued this command. + */ + notifyTestHelper(TestHelper.COMMAND_ENQUEUED); + return task1; }); - } + + return task.makeVoid(); + }); }); } @@ -291,33 +257,22 @@ public Task then(Task task) { * operationSetTaskQueue. */ private Task populateQueueAsync() { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return populateQueueAsync(toAwait); - } - }); + return taskQueue.enqueue(this::populateQueueAsync); } private Task populateQueueAsync(Task toAwait) { - return toAwait.continueWithTask(new Continuation>>() { - @Override - public Task> then(Task task) { - // We don't want to enqueue any EventuallyPins that are already queued. - return EventuallyPin.findAllPinned(eventuallyPinUUIDQueue); + return toAwait.continueWithTask(task -> { + // We don't want to enqueue any EventuallyPins that are already queued. + return EventuallyPin.findAllPinned(eventuallyPinUUIDQueue); + }).onSuccessTask(task -> { + List pins = task.getResult(); + + for (final EventuallyPin pin : pins) { + // We don't need to wait for this. + runEventuallyAsync(pin); } - }).onSuccessTask(new Continuation, Task>() { - @Override - public Task then(Task> task) { - List pins = task.getResult(); - - for (final EventuallyPin pin : pins) { - // We don't need to wait for this. - runEventuallyAsync(pin); - } - return task.makeVoid(); - } + return task.makeVoid(); }); } @@ -335,18 +290,10 @@ private Task runEventuallyAsync(final EventuallyPin eventuallyPin) { } eventuallyPinUUIDQueue.add(uuid); - operationSetTaskQueue.enqueue(new Continuation>() { - @Override - public Task then(final Task toAwait) { - return runEventuallyAsync(eventuallyPin, toAwait).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - eventuallyPinUUIDQueue.remove(uuid); - return task; - } - }); - } - }); + operationSetTaskQueue.enqueue(toAwait -> runEventuallyAsync(eventuallyPin, toAwait).continueWithTask(task -> { + eventuallyPinUUIDQueue.remove(uuid); + return task; + })); return Task.forResult(null); } @@ -358,47 +305,34 @@ public Task then(Task task) { * @return A task that is resolved when the eventually operation completes. */ private Task runEventuallyAsync(final EventuallyPin eventuallyPin, final Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return waitForConnectionAsync(); + return toAwait.continueWithTask(task -> waitForConnectionAsync()).onSuccessTask(task -> waitForOperationSetAndEventuallyPin(null, eventuallyPin).continueWithTask(task1 -> { + Exception error = task1.getError(); + if (error != null) { + if (error instanceof PauseException) { + // Bubble up the PauseException. + return task1.makeVoid(); + } + + if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) { + PLog.e(TAG, "Failed to run command.", error); + } + + notifyTestHelper(TestHelper.COMMAND_FAILED, error); + } else { + notifyTestHelper(TestHelper.COMMAND_SUCCESSFUL); } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return waitForOperationSetAndEventuallyPin(null, eventuallyPin).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - Exception error = task.getError(); - if (error != null) { - if (error instanceof PauseException) { - // Bubble up the PauseException. - return task.makeVoid(); - } - - if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) { - PLog.e(TAG, "Failed to run command.", error); - } - - notifyTestHelper(TestHelper.COMMAND_FAILED, error); - } else { - notifyTestHelper(TestHelper.COMMAND_SUCCESSFUL); - } - TaskCompletionSource tcs = - pendingOperationSetUUIDTasks.remove(eventuallyPin.getUUID()); - if (tcs != null) { - if (error != null) { - tcs.setError(error); - } else { - tcs.setResult(task.getResult()); - } - } - return task.makeVoid(); - } - }); + TaskCompletionSource tcs = + pendingOperationSetUUIDTasks.remove(eventuallyPin.getUUID()); + if (tcs != null) { + if (error != null) { + tcs.setError(error); + } else { + tcs.setResult(task1.getResult()); + } } - }); + return task1.makeVoid(); + })); } /** @@ -447,25 +381,22 @@ public Task then(Task task) { } } - return process(eventuallyPin, operationSet).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (taskQueueSyncLock) { - pendingEventuallyTasks.remove(uuid); - uuidToOperationSet.remove(uuid); - uuidToEventuallyPin.remove(uuid); - } + return process(eventuallyPin, operationSet).continueWithTask(task -> { + synchronized (taskQueueSyncLock) { + pendingEventuallyTasks.remove(uuid); + uuidToOperationSet.remove(uuid); + uuidToEventuallyPin.remove(uuid); + } - Exception error = task.getError(); - if (error != null) { - tcs.trySetError(error); - } else if (task.isCancelled()) { - tcs.trySetCancelled(); - } else { - tcs.trySetResult(task.getResult()); - } - return tcs.getTask(); + Exception error = task.getError(); + if (error != null) { + tcs.trySetError(error); + } else if (task.isCancelled()) { + tcs.trySetCancelled(); + } else { + tcs.trySetResult(task.getResult()); } + return tcs.getTask(); }); } @@ -475,74 +406,60 @@ public Task then(Task task) { private Task process(final EventuallyPin eventuallyPin, final ParseOperationSet operationSet) { - return waitForConnectionAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - final int type = eventuallyPin.getType(); - final ParseObject object = eventuallyPin.getObject(); - String sessionToken = eventuallyPin.getSessionToken(); - - Task executeTask; - if (type == EventuallyPin.TYPE_SAVE) { - executeTask = object.saveAsync(httpClient, operationSet, sessionToken); - } else if (type == EventuallyPin.TYPE_DELETE) { - executeTask = object.deleteAsync(sessionToken).cast(); - } else { // else if (type == EventuallyPin.TYPE_COMMAND) { - ParseRESTCommand command = eventuallyPin.getCommand(); - if (command == null) { - executeTask = Task.forResult(null); - notifyTestHelper(TestHelper.COMMAND_OLD_FORMAT_DISCARDED); - } else { - executeTask = command.executeAsync(httpClient); + return waitForConnectionAsync().onSuccessTask(task -> { + final int type = eventuallyPin.getType(); + final ParseObject object = eventuallyPin.getObject(); + String sessionToken = eventuallyPin.getSessionToken(); + + Task executeTask; + if (type == EventuallyPin.TYPE_SAVE) { + executeTask = object.saveAsync(httpClient, operationSet, sessionToken); + } else if (type == EventuallyPin.TYPE_DELETE) { + executeTask = object.deleteAsync(sessionToken).cast(); + } else { // else if (type == EventuallyPin.TYPE_COMMAND) { + ParseRESTCommand command = eventuallyPin.getCommand(); + if (command == null) { + executeTask = Task.forResult(null); + notifyTestHelper(TestHelper.COMMAND_OLD_FORMAT_DISCARDED); + } else { + executeTask = command.executeAsync(httpClient); + } + } + + return executeTask.continueWithTask(executeTask1 -> { + Exception error = executeTask1.getError(); + if (error != null) { + if (error instanceof ParseException + && ((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) { + // We did our retry logic in ParseRequest, so just mark as not connected + // and move on. + setConnected(false); + + notifyTestHelper(TestHelper.NETWORK_DOWN); + + return process(eventuallyPin, operationSet); } } - return executeTask.continueWithTask(new Continuation>() { - @Override - public Task then(final Task executeTask) { - Exception error = executeTask.getError(); - if (error != null) { - if (error instanceof ParseException - && ((ParseException) error).getCode() == ParseException.CONNECTION_FAILED) { - // We did our retry logic in ParseRequest, so just mark as not connected - // and move on. - setConnected(false); - - notifyTestHelper(TestHelper.NETWORK_DOWN); - - return process(eventuallyPin, operationSet); - } + // Delete the command regardless, even if it failed. Otherwise, we'll just keep + // trying it forever. + // We don't have to wait for taskQueue since it will not be enqueued again + // since this EventuallyPin is still in eventuallyPinUUIDQueue. + return eventuallyPin.unpinInBackground(EventuallyPin.PIN_NAME).continueWithTask(task12 -> { + JSONObject result = executeTask1.getResult(); + if (type == EventuallyPin.TYPE_SAVE) { + return object.handleSaveEventuallyResultAsync(result, operationSet); + } else if (type == EventuallyPin.TYPE_DELETE) { + if (executeTask1.isFaulted()) { + return task12; + } else { + return object.handleDeleteEventuallyResultAsync(); } - - // Delete the command regardless, even if it failed. Otherwise, we'll just keep - // trying it forever. - // We don't have to wait for taskQueue since it will not be enqueued again - // since this EventuallyPin is still in eventuallyPinUUIDQueue. - return eventuallyPin.unpinInBackground(EventuallyPin.PIN_NAME).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - JSONObject result = executeTask.getResult(); - if (type == EventuallyPin.TYPE_SAVE) { - return object.handleSaveEventuallyResultAsync(result, operationSet); - } else if (type == EventuallyPin.TYPE_DELETE) { - if (executeTask.isFaulted()) { - return task; - } else { - return object.handleDeleteEventuallyResultAsync(); - } - } else { // else if (type == EventuallyPin.TYPE_COMMAND) { - return task; - } - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return executeTask; - } - }); + } else { // else if (type == EventuallyPin.TYPE_COMMAND) { + return task12; } - }); - } + }).continueWithTask(task1 -> executeTask1); + }); }); } @@ -562,28 +479,15 @@ public Task then(Task task) { public void clear() { pause(); - Task task = taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return EventuallyPin.findAllPinned().onSuccessTask(new Continuation, Task>() { - @Override - public Task then(Task> task) { - List pins = task.getResult(); - - List> tasks = new ArrayList<>(); - for (EventuallyPin pin : pins) { - tasks.add(pin.unpinInBackground(EventuallyPin.PIN_NAME)); - } - return Task.whenAll(tasks); - } - }); - } - }); + Task task = taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task12 -> EventuallyPin.findAllPinned().onSuccessTask(task1 -> { + List pins = task1.getResult(); + + List> tasks = new ArrayList<>(); + for (EventuallyPin pin : pins) { + tasks.add(pin.unpinInBackground(EventuallyPin.PIN_NAME)); } - }); + return Task.whenAll(tasks); + }))); try { ParseTaskUtils.wait(task); @@ -607,12 +511,7 @@ private Task whenAll(Collection taskQueues) { List> tasks = new ArrayList<>(); for (TaskQueue taskQueue : taskQueues) { - Task task = taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return toAwait; - } - }); + Task task = taskQueue.enqueue(toAwait -> toAwait); tasks.add(task); } diff --git a/parse/src/main/java/com/parse/ParsePlugins.java b/parse/src/main/java/com/parse/ParsePlugins.java index 1a02703e9..74aa44e24 100644 --- a/parse/src/main/java/com/parse/ParsePlugins.java +++ b/parse/src/main/java/com/parse/ParsePlugins.java @@ -12,13 +12,10 @@ import android.os.Build; import java.io.File; -import java.io.IOException; import okhttp3.Headers; -import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; -import okhttp3.Response; /** * Public for LiveQuery. You probably don't need access @@ -38,6 +35,7 @@ public class ParsePlugins { ParseHttpClient fileClient; private Context applicationContext; private InstallationId installationId; + private ParsePlugins(Context context, Parse.Configuration configuration) { if (context != null) { applicationContext = context.getApplicationContext(); @@ -116,31 +114,28 @@ ParseHttpClient restClient() { clientBuilder = new OkHttpClient.Builder(); } //add it as the first interceptor - clientBuilder.interceptors().add(0, new Interceptor() { - @Override - public Response intercept(Chain chain) throws IOException { - Request request = chain.request(); - Headers.Builder headersBuilder = request.headers().newBuilder() - .set(ParseRESTCommand.HEADER_APPLICATION_ID, configuration.applicationId) - .set(ParseRESTCommand.HEADER_APP_BUILD_VERSION, - String.valueOf(ManifestInfo.getVersionCode())) - .set(ParseRESTCommand.HEADER_APP_DISPLAY_VERSION, - ManifestInfo.getVersionName()) - .set(ParseRESTCommand.HEADER_OS_VERSION, Build.VERSION.RELEASE) - .set(ParseRESTCommand.USER_AGENT, userAgent()); - if (request.header(ParseRESTCommand.HEADER_INSTALLATION_ID) == null) { - // We can do this synchronously since the caller is already on a background thread - headersBuilder.set(ParseRESTCommand.HEADER_INSTALLATION_ID, installationId().get()); - } - // client key can be null with self-hosted Parse Server - if (configuration.clientKey != null) { - headersBuilder.set(ParseRESTCommand.HEADER_CLIENT_KEY, configuration.clientKey); - } - request = request.newBuilder() - .headers(headersBuilder.build()) - .build(); - return chain.proceed(request); + clientBuilder.interceptors().add(0, chain -> { + Request request = chain.request(); + Headers.Builder headersBuilder = request.headers().newBuilder() + .set(ParseRESTCommand.HEADER_APPLICATION_ID, configuration.applicationId) + .set(ParseRESTCommand.HEADER_APP_BUILD_VERSION, + String.valueOf(ManifestInfo.getVersionCode())) + .set(ParseRESTCommand.HEADER_APP_DISPLAY_VERSION, + ManifestInfo.getVersionName()) + .set(ParseRESTCommand.HEADER_OS_VERSION, Build.VERSION.RELEASE) + .set(ParseRESTCommand.USER_AGENT, userAgent()); + if (request.header(ParseRESTCommand.HEADER_INSTALLATION_ID) == null) { + // We can do this synchronously since the caller is already on a background thread + headersBuilder.set(ParseRESTCommand.HEADER_INSTALLATION_ID, installationId().get()); + } + // client key can be null with self-hosted Parse Server + if (configuration.clientKey != null) { + headersBuilder.set(ParseRESTCommand.HEADER_CLIENT_KEY, configuration.clientKey); } + request = request.newBuilder() + .headers(headersBuilder.build()) + .build(); + return chain.proceed(request); }); restClient = ParseHttpClient.createClient(clientBuilder); } diff --git a/parse/src/main/java/com/parse/ParsePush.java b/parse/src/main/java/com/parse/ParsePush.java index b91ca00cc..021fc7134 100644 --- a/parse/src/main/java/com/parse/ParsePush.java +++ b/parse/src/main/java/com/parse/ParsePush.java @@ -8,6 +8,8 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import org.json.JSONException; import org.json.JSONObject; @@ -16,9 +18,6 @@ import java.util.HashSet; import java.util.Set; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * The {@code ParsePush} is a local representation of data that can be sent as a push notification. *

@@ -28,8 +27,8 @@ */ public class ParsePush { + /* package for test */ static final String KEY_DATA_MESSAGE = "alert"; private static final String TAG = "com.parse.ParsePush"; - /* package for test */ static String KEY_DATA_MESSAGE = "alert"; /* package for test */ final State.Builder builder; /** @@ -282,12 +281,9 @@ public void setMessage(String message) { public Task sendInBackground() { // Since getCurrentSessionTokenAsync takes time, we build the state before it. final State state = builder.build(); - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String sessionToken = task.getResult(); - return getPushController().sendInBackground(state, sessionToken); - } + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + String sessionToken = task.getResult(); + return getPushController().sendInBackground(state, sessionToken); }); } @@ -320,6 +316,7 @@ public void sendInBackground(SendCallback callback) { private final Long expirationTimeInterval; private final Long pushTime; private final JSONObject data; + private State(Builder builder) { this.channelSet = builder.channelSet == null ? null : Collections.unmodifiableSet(new HashSet<>(builder.channelSet)); @@ -387,7 +384,7 @@ public Builder(State state) { : Collections.unmodifiableSet(new HashSet<>(state.channelSet())); this.query = state.queryState() == null ? null - : new ParseQuery<>(new ParseQuery.State.Builder(state.queryState())); + : new ParseQuery<>(new ParseQuery.State.Builder<>(state.queryState())); this.expirationTime = state.expirationTime(); this.expirationTimeInterval = state.expirationTimeInterval(); this.pushTime = state.pushTime(); diff --git a/parse/src/main/java/com/parse/ParsePushBroadcastReceiver.java b/parse/src/main/java/com/parse/ParsePushBroadcastReceiver.java index 19b8a1b59..71b2eaf43 100644 --- a/parse/src/main/java/com/parse/ParsePushBroadcastReceiver.java +++ b/parse/src/main/java/com/parse/ParsePushBroadcastReceiver.java @@ -21,13 +21,13 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; + import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; import org.json.JSONException; import org.json.JSONObject; -import java.util.Locale; import java.util.Random; /** @@ -398,7 +398,7 @@ protected NotificationCompat.Builder getNotification(Context context, Intent int String title = pushData.optString("title", ManifestInfo.getDisplayName(context)); String alert = pushData.optString("alert", "Notification received."); - String tickerText = String.format(Locale.getDefault(), "%s: %s", title, alert); + String tickerText = String.format("%s: %s", title, alert); Bundle extras = intent.getExtras(); diff --git a/parse/src/main/java/com/parse/ParsePushChannelsController.java b/parse/src/main/java/com/parse/ParsePushChannelsController.java index f2468f550..9794f9608 100644 --- a/parse/src/main/java/com/parse/ParsePushChannelsController.java +++ b/parse/src/main/java/com/parse/ParsePushChannelsController.java @@ -8,12 +8,11 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import java.util.Collections; import java.util.List; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - class ParsePushChannelsController { private static ParseCurrentInstallationController getCurrentInstallationController() { @@ -24,19 +23,16 @@ public Task subscribeInBackground(final String channel) { if (channel == null) { throw new IllegalArgumentException("Can't subscribe to null channel."); } - return getCurrentInstallationController().getAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseInstallation installation = task.getResult(); - List channels = installation.getList(ParseInstallation.KEY_CHANNELS); - if (channels == null - || installation.isDirty(ParseInstallation.KEY_CHANNELS) - || !channels.contains(channel)) { - installation.addUnique(ParseInstallation.KEY_CHANNELS, channel); - return installation.saveInBackground(); - } else { - return Task.forResult(null); - } + return getCurrentInstallationController().getAsync().onSuccessTask(task -> { + ParseInstallation installation = task.getResult(); + List channels = installation.getList(ParseInstallation.KEY_CHANNELS); + if (channels == null + || installation.isDirty(ParseInstallation.KEY_CHANNELS) + || !channels.contains(channel)) { + installation.addUnique(ParseInstallation.KEY_CHANNELS, channel); + return installation.saveInBackground(); + } else { + return Task.forResult(null); } }); } @@ -45,18 +41,15 @@ public Task unsubscribeInBackground(final String channel) { if (channel == null) { throw new IllegalArgumentException("Can't unsubscribe from null channel."); } - return getCurrentInstallationController().getAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseInstallation installation = task.getResult(); - List channels = installation.getList(ParseInstallation.KEY_CHANNELS); - if (channels != null && channels.contains(channel)) { - installation.removeAll( - ParseInstallation.KEY_CHANNELS, Collections.singletonList(channel)); - return installation.saveInBackground(); - } else { - return Task.forResult(null); - } + return getCurrentInstallationController().getAsync().onSuccessTask(task -> { + ParseInstallation installation = task.getResult(); + List channels = installation.getList(ParseInstallation.KEY_CHANNELS); + if (channels != null && channels.contains(channel)) { + installation.removeAll( + ParseInstallation.KEY_CHANNELS, Collections.singletonList(channel)); + return installation.saveInBackground(); + } else { + return Task.forResult(null); } }); } diff --git a/parse/src/main/java/com/parse/ParsePushController.java b/parse/src/main/java/com/parse/ParsePushController.java index 2991e115a..f4494a634 100644 --- a/parse/src/main/java/com/parse/ParsePushController.java +++ b/parse/src/main/java/com/parse/ParsePushController.java @@ -23,7 +23,7 @@ public Task sendInBackground(ParsePush.State state, String sessionToken) { } ParseRESTCommand buildRESTSendPushCommand(ParsePush.State state, - String sessionToken) { + String sessionToken) { return ParseRESTPushCommand.sendPushCommand(state.queryState(), state.channelSet(), state.expirationTime(), state.expirationTimeInterval(), state.pushTime(), state.data(), sessionToken); diff --git a/parse/src/main/java/com/parse/ParseQuery.java b/parse/src/main/java/com/parse/ParseQuery.java index 22d1178b9..3b03ad4ea 100644 --- a/parse/src/main/java/com/parse/ParseQuery.java +++ b/parse/src/main/java/com/parse/ParseQuery.java @@ -10,6 +10,9 @@ import androidx.annotation.NonNull; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + import org.json.JSONException; import org.json.JSONObject; @@ -25,10 +28,6 @@ import java.util.concurrent.Callable; import java.util.regex.Pattern; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - /** * The {@code ParseQuery} class defines a query that is used to fetch {@link ParseObject}s. The most * common use case is finding all objects that match a query through the {@link #findInBackground()} @@ -95,10 +94,10 @@ public class ParseQuery { public static final int MAX_LIMIT = 1000; private final State.Builder builder; - private ParseUser user; // Just like ParseFile - private Set> currentTasks = Collections.synchronizedSet( - new HashSet>()); + private final Set> currentTasks = Collections.synchronizedSet( + new HashSet<>()); + private ParseUser user; /** * Constructs a query for a {@link ParseObject} subclass type. A default query with no further @@ -117,7 +116,7 @@ public ParseQuery(Class subclass) { * @param theClassName The name of the class to retrieve {@link ParseObject}s for. */ public ParseQuery(String theClassName) { - this(new State.Builder(theClassName)); + this(new State.Builder<>(theClassName)); } /** @@ -404,13 +403,10 @@ private Task perform(Callable> runnable, final } catch (Exception e) { task = Task.forError(e); } - return task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - tcs.trySetResult(null); // release - currentTasks.remove(tcs); - return task; - } + return task.continueWithTask(task1 -> { + tcs.trySetResult(null); // release + currentTasks.remove(tcs); + return task1; }); } @@ -444,30 +440,17 @@ public void findInBackground(final FindCallback callback) { state.isFromLocalDatastore()) { task = findAsync(state); } else { - task = doCacheThenNetwork(state, callback, new CacheThenNetworkCallable>>() { - @Override - public Task> call(State state, ParseUser user, Task cancellationToken) { - return findAsync(state, user, cancellationToken); - } - }); + task = doCacheThenNetwork(state, callback, this::findAsync); } ParseTaskUtils.callbackOnMainThreadAsync(task, callback); } private Task> findAsync(final State state) { final TaskCompletionSource tcs = new TaskCompletionSource<>(); - return perform(new Callable>>() { - @Override - public Task> call() { - return getUserAsync(state).onSuccessTask(new Continuation>>() { - @Override - public Task> then(Task task) { - final ParseUser user = task.getResult(); - return findAsync(state, user, tcs.getTask()); - } - }); - } - }, tcs); + return perform(() -> getUserAsync(state).onSuccessTask(task -> { + final ParseUser user = task.getResult(); + return findAsync(state, user, tcs.getTask()); + }), tcs); } /* package */ Task> findAsync(State state, ParseUser user, Task cancellationToken) { @@ -511,30 +494,17 @@ public void getFirstInBackground(final GetCallback callback) { state.isFromLocalDatastore()) { task = getFirstAsync(state); } else { - task = doCacheThenNetwork(state, callback, new CacheThenNetworkCallable>() { - @Override - public Task call(State state, ParseUser user, Task cancellationToken) { - return getFirstAsync(state, user, cancellationToken); - } - }); + task = doCacheThenNetwork(state, callback, this::getFirstAsync); } ParseTaskUtils.callbackOnMainThreadAsync(task, callback); } private Task getFirstAsync(final State state) { final TaskCompletionSource tcs = new TaskCompletionSource<>(); - return perform(new Callable>() { - @Override - public Task call() { - return getUserAsync(state).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseUser user = task.getResult(); - return getFirstAsync(state, user, tcs.getTask()); - } - }); - } - }, tcs); + return perform(() -> getUserAsync(state).onSuccessTask(task -> { + final ParseUser user = task.getResult(); + return getFirstAsync(state, user, tcs.getTask()); + }), tcs); } private Task getFirstAsync(State state, ParseUser user, Task cancellationToken) { @@ -574,12 +544,7 @@ public void countInBackground(final CountCallback callback) { // Hack to workaround CountCallback's non-uniform signature. final ParseCallback2 c = callback != null - ? new ParseCallback2() { - @Override - public void done(Integer integer, ParseException e) { - callback.done(e == null ? integer : -1, e); - } - } + ? (integer, e) -> callback.done(e == null ? integer : -1, e) : null; final Task task; @@ -587,30 +552,17 @@ public void done(Integer integer, ParseException e) { state.isFromLocalDatastore()) { task = countAsync(state); } else { - task = doCacheThenNetwork(state, c, new CacheThenNetworkCallable>() { - @Override - public Task call(State state, ParseUser user, Task cancellationToken) { - return countAsync(state, user, cancellationToken); - } - }); + task = doCacheThenNetwork(state, c, this::countAsync); } ParseTaskUtils.callbackOnMainThreadAsync(task, c); } private Task countAsync(final State state) { final TaskCompletionSource tcs = new TaskCompletionSource<>(); - return perform(new Callable>() { - @Override - public Task call() { - return getUserAsync(state).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseUser user = task.getResult(); - return countAsync(state, user, tcs.getTask()); - } - }); - } - }, tcs); + return perform(() -> getUserAsync(state).onSuccessTask(task -> { + final ParseUser user = task.getResult(); + return countAsync(state, user, tcs.getTask()); + }), tcs); } private Task countAsync(State state, ParseUser user, Task cancellationToken) { @@ -729,12 +681,7 @@ public void getInBackground(final String objectId, final GetCallback callback state.isFromLocalDatastore()) { task = getFirstAsync(state); } else { - task = doCacheThenNetwork(state, callback, new CacheThenNetworkCallable>() { - @Override - public Task call(State state, ParseUser user, Task cancellationToken) { - return getFirstAsync(state, user, cancellationToken); - } - }); + task = doCacheThenNetwork(state, callback, this::getFirstAsync); } ParseTaskUtils.callbackOnMainThreadAsync(task, callback); } @@ -752,35 +699,24 @@ private Task doCacheThenNetwork( final CacheThenNetworkCallable> delegate) { final TaskCompletionSource tcs = new TaskCompletionSource<>(); - return perform(new Callable>() { - @Override - public Task call() { - return getUserAsync(state).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseUser user = task.getResult(); - final State cacheState = new State.Builder(state) - .setCachePolicy(CachePolicy.CACHE_ONLY) - .build(); - final State networkState = new State.Builder(state) - .setCachePolicy(CachePolicy.NETWORK_ONLY) - .build(); - - Task executionTask = delegate.call(cacheState, user, tcs.getTask()); - executionTask = ParseTaskUtils.callbackOnMainThreadAsync(executionTask, callback); - return executionTask.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isCancelled()) { - return task; - } - return delegate.call(networkState, user, tcs.getTask()); - } - }); - } - }); - } - }, tcs); + return perform(() -> getUserAsync(state).onSuccessTask(task -> { + final ParseUser user = task.getResult(); + final State cacheState = new State.Builder(state) + .setCachePolicy(CachePolicy.CACHE_ONLY) + .build(); + final State networkState = new State.Builder(state) + .setCachePolicy(CachePolicy.NETWORK_ONLY) + .build(); + + Task executionTask = delegate.call(cacheState, user, tcs.getTask()); + executionTask = ParseTaskUtils.callbackOnMainThreadAsync(executionTask, callback); + return executionTask.continueWithTask(task1 -> { + if (task1.isCancelled()) { + return task1; + } + return delegate.call(networkState, user, tcs.getTask()); + }); + }), tcs); } /** @@ -1463,8 +1399,8 @@ public QueryConstraints(Map map) { * Constraint for a $relatedTo query. */ /* package */ static class RelationConstraint { - private String key; - private ParseObject object; + private final String key; + private final ParseObject object; public RelationConstraint(String key, ParseObject object) { if (key == null || object == null) { @@ -1524,6 +1460,7 @@ public static class State { private final boolean isFromLocalDatastore; private final String pinName; private final boolean ignoreACLs; + private State(Builder builder) { className = builder.className; where = new QueryConstraints(builder.where); @@ -1665,11 +1602,11 @@ public static class Builder { private final QueryConstraints where = new QueryConstraints(); private final Set includes = new HashSet<>(); private final Map extraOptions = new HashMap<>(); + private final List order = new ArrayList<>(); // This is nullable since we allow unset selectedKeys as well as no selectedKeys private Set selectedKeys; private int limit = -1; // negative limits mean, do not send a limit private int skip = 0; // negative skip means do not send a skip - private List order = new ArrayList<>(); // TODO(grantland): Move out of State private boolean trace; // Query Caching @@ -1679,6 +1616,7 @@ public static class Builder { private boolean isFromLocalDatastore = false; private String pinName; private boolean ignoreACLs; + public Builder(String className) { this.className = className; } diff --git a/parse/src/main/java/com/parse/ParseQueryController.java b/parse/src/main/java/com/parse/ParseQueryController.java index 8917558fd..ac684c751 100644 --- a/parse/src/main/java/com/parse/ParseQueryController.java +++ b/parse/src/main/java/com/parse/ParseQueryController.java @@ -8,10 +8,10 @@ */ package com.parse; -import java.util.List; - import com.parse.boltsinternal.Task; +import java.util.List; + /** * A {@code ParseQueryController} defines how a {@link ParseQuery} is executed. */ diff --git a/parse/src/main/java/com/parse/ParseRESTCommand.java b/parse/src/main/java/com/parse/ParseRESTCommand.java index 250b5a783..33ecee726 100644 --- a/parse/src/main/java/com/parse/ParseRESTCommand.java +++ b/parse/src/main/java/com/parse/ParseRESTCommand.java @@ -8,6 +8,7 @@ */ package com.parse; +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpBody; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -26,8 +27,6 @@ import java.util.Iterator; import java.util.Map; -import com.parse.boltsinternal.Task; - /** * A helper object to send requests to the server. */ @@ -55,6 +54,7 @@ class ParseRESTCommand extends ParseRequest { private String installationId; private String operationSetUUID; private String localId; + public ParseRESTCommand( String httpPath, ParseHttpRequest.Method httpMethod, @@ -74,6 +74,7 @@ public ParseRESTCommand( String sessionToken) { this(httpPath, httpMethod, jsonParameters, null, sessionToken); } + private ParseRESTCommand( String httpPath, ParseHttpRequest.Method httpMethod, diff --git a/parse/src/main/java/com/parse/ParseRESTFileCommand.java b/parse/src/main/java/com/parse/ParseRESTFileCommand.java index 02e37ebcd..f190f78e6 100644 --- a/parse/src/main/java/com/parse/ParseRESTFileCommand.java +++ b/parse/src/main/java/com/parse/ParseRESTFileCommand.java @@ -21,6 +21,7 @@ class ParseRESTFileCommand extends ParseRESTCommand { private final byte[] data; private final String contentType; private final File file; + public ParseRESTFileCommand(Builder builder) { super(builder); if (builder.file != null && builder.data != null) { diff --git a/parse/src/main/java/com/parse/ParseRESTObjectBatchCommand.java b/parse/src/main/java/com/parse/ParseRESTObjectBatchCommand.java index 75fa1bd09..55f3b7fa6 100644 --- a/parse/src/main/java/com/parse/ParseRESTObjectBatchCommand.java +++ b/parse/src/main/java/com/parse/ParseRESTObjectBatchCommand.java @@ -8,6 +8,9 @@ */ package com.parse; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -22,10 +25,6 @@ import java.util.ArrayList; import java.util.List; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - class ParseRESTObjectBatchCommand extends ParseRESTCommand { public final static int COMMAND_OBJECT_BATCH_MAX_SIZE = 50; @@ -89,50 +88,47 @@ public static List> executeBatch( ParseRESTCommand command = new ParseRESTObjectBatchCommand( "batch", ParseHttpRequest.Method.POST, parameters, sessionToken); - command.executeAsync(client).continueWith(new Continuation() { - @Override - public Void then(Task task) throws Exception { - TaskCompletionSource tcs; - - if (task.isFaulted() || task.isCancelled()) { - // REST command failed or canceled, fail or cancel all tasks - for (int i = 0; i < batchSize; i++) { - tcs = tcss.get(i); - if (task.isFaulted()) { - tcs.setError(task.getError()); - } else { - tcs.setCancelled(); - } - } - } - - JSONObject json = task.getResult(); - JSONArray results = json.getJSONArray(KEY_RESULTS); + command.executeAsync(client).continueWith((Continuation) task -> { + TaskCompletionSource tcs; - int resultLength = results.length(); - if (resultLength != batchSize) { - // Invalid response, fail all tasks - for (int i = 0; i < batchSize; i++) { - tcs = tcss.get(i); - tcs.setError(new IllegalStateException( - "Batch command result count expected: " + batchSize + " but was: " + resultLength)); + if (task.isFaulted() || task.isCancelled()) { + // REST command failed or canceled, fail or cancel all tasks + for (int i = 0; i < batchSize; i++) { + tcs = tcss.get(i); + if (task.isFaulted()) { + tcs.setError(task.getError()); + } else { + tcs.setCancelled(); } } + } + + JSONObject json = task.getResult(); + JSONArray results = json.getJSONArray(KEY_RESULTS); + int resultLength = results.length(); + if (resultLength != batchSize) { + // Invalid response, fail all tasks for (int i = 0; i < batchSize; i++) { - JSONObject result = results.getJSONObject(i); tcs = tcss.get(i); + tcs.setError(new IllegalStateException( + "Batch command result count expected: " + batchSize + " but was: " + resultLength)); + } + } - if (result.has("success")) { - JSONObject success = result.getJSONObject("success"); - tcs.setResult(success); - } else if (result.has("error")) { - JSONObject error = result.getJSONObject("error"); - tcs.setError(new ParseException(error.getInt("code"), error.getString("error"))); - } + for (int i = 0; i < batchSize; i++) { + JSONObject result = results.getJSONObject(i); + tcs = tcss.get(i); + + if (result.has("success")) { + JSONObject success = result.getJSONObject("success"); + tcs.setResult(success); + } else if (result.has("error")) { + JSONObject error = result.getJSONObject("error"); + tcs.setError(new ParseException(error.getInt("code"), error.getString("error"))); } - return null; } + return null; }); return tasks; diff --git a/parse/src/main/java/com/parse/ParseRESTUserCommand.java b/parse/src/main/java/com/parse/ParseRESTUserCommand.java index a3df33438..48def5b87 100644 --- a/parse/src/main/java/com/parse/ParseRESTUserCommand.java +++ b/parse/src/main/java/com/parse/ParseRESTUserCommand.java @@ -8,6 +8,7 @@ */ package com.parse; +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -17,13 +18,11 @@ import java.util.HashMap; import java.util.Map; -import com.parse.boltsinternal.Task; - class ParseRESTUserCommand extends ParseRESTCommand { private static final String HEADER_REVOCABLE_SESSION = "X-Parse-Revocable-Session"; private static final String HEADER_TRUE = "1"; - private boolean isRevocableSessionEnabled; + private final boolean isRevocableSessionEnabled; //region Authentication private int statusCode; diff --git a/parse/src/main/java/com/parse/ParseRelation.java b/parse/src/main/java/com/parse/ParseRelation.java index 257105bc9..09c35580b 100644 --- a/parse/src/main/java/com/parse/ParseRelation.java +++ b/parse/src/main/java/com/parse/ParseRelation.java @@ -37,6 +37,8 @@ public ParseRelation[] newArray(int size) { } }; private final Object mutex = new Object(); + // For offline caching, we keep track of every object we've known to be in the relation. + private final Set knownObjects = new HashSet<>(); // The owning object of this ParseRelation. private WeakReference parent; // The object Id of the parent. @@ -47,8 +49,6 @@ public ParseRelation[] newArray(int size) { private String key; // The className of the target objects. private String targetClass; - // For offline caching, we keep track of every object we've known to be in the relation. - private Set knownObjects = new HashSet<>(); /* package */ ParseRelation(ParseObject parent, String key) { this.parent = new WeakReference<>(parent); diff --git a/parse/src/main/java/com/parse/ParseRequest.java b/parse/src/main/java/com/parse/ParseRequest.java index efd5443bf..012434a39 100644 --- a/parse/src/main/java/com/parse/ParseRequest.java +++ b/parse/src/main/java/com/parse/ParseRequest.java @@ -10,6 +10,9 @@ import androidx.annotation.NonNull; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; import com.parse.http.ParseHttpBody; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -23,10 +26,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - /** * ParseRequest takes an arbitrary HttpUriRequest and retries it a number of times with * exponential backoff. @@ -53,7 +52,7 @@ public Thread newThread(@NonNull Runnable r) { private static final int MAX_QUEUE_SIZE = 128; protected static final ExecutorService NETWORK_EXECUTOR = newThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, - new LinkedBlockingQueue(MAX_QUEUE_SIZE), sThreadFactory); + new LinkedBlockingQueue<>(MAX_QUEUE_SIZE), sThreadFactory); private static long defaultInitialRetryDelay = DEFAULT_INITIAL_RETRY_DELAY; /* package */ ParseHttpRequest.Method method; /* package */ String url; @@ -127,24 +126,18 @@ private Task sendOneRequestAsync( final ParseHttpClient client, final ParseHttpRequest request, final ProgressCallback downloadProgressCallback) { - return Task.forResult(null).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) throws Exception { - ParseHttpResponse response = client.execute(request); - return onResponseAsync(response, downloadProgressCallback); - } - }, NETWORK_EXECUTOR).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isFaulted()) { - Exception error = task.getError(); - if (error instanceof IOException) { - return Task.forError(newTemporaryException("i/o failure", error)); - } + return Task.forResult(null).onSuccessTask(task -> { + ParseHttpResponse response = client.execute(request); + return onResponseAsync(response, downloadProgressCallback); + }, NETWORK_EXECUTOR).continueWithTask(task -> { + if (task.isFaulted()) { + Exception error = task.getError(); + if (error instanceof IOException) { + return Task.forError(newTemporaryException("i/o failure", error)); } - return task; - // Jump off the network executor so this task continuations won't steal network threads } + return task; + // Jump off the network executor so this task continuations won't steal network threads }, Task.BACKGROUND_EXECUTOR); } @@ -210,54 +203,45 @@ private Task executeAsync( if (cancellationToken != null && cancellationToken.isCancelled()) { return Task.cancelled(); } - return sendOneRequestAsync(client, request, downloadProgressCallback).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - Exception e = task.getError(); - if (task.isFaulted() && e instanceof ParseException) { - if (cancellationToken != null && cancellationToken.isCancelled()) { - return Task.cancelled(); - } - - if (e instanceof ParseRequestException && - ((ParseRequestException) e).isPermanentFailure) { - return task; - } - - if (attemptsMade < maxRetries()) { - PLog.i("com.parse.ParseRequest", "Request failed. Waiting " + delay - + " milliseconds before attempt #" + (attemptsMade + 1)); - - final TaskCompletionSource retryTask = new TaskCompletionSource<>(); - ParseExecutors.scheduled().schedule(new Runnable() { - @Override - public void run() { - executeAsync( - client, - request, - attemptsMade + 1, - delay * 2, - downloadProgressCallback, - cancellationToken).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isCancelled()) { - retryTask.setCancelled(); - } else if (task.isFaulted()) { - retryTask.setError(task.getError()); - } else { - retryTask.setResult(task.getResult()); - } - return null; - } - }); + return sendOneRequestAsync(client, request, downloadProgressCallback).continueWithTask(task -> { + Exception e = task.getError(); + if (task.isFaulted() && e instanceof ParseException) { + if (cancellationToken != null && cancellationToken.isCancelled()) { + return Task.cancelled(); + } + + if (e instanceof ParseRequestException && + ((ParseRequestException) e).isPermanentFailure) { + return task; + } + + if (attemptsMade < maxRetries()) { + PLog.i("com.parse.ParseRequest", "Request failed. Waiting " + delay + + " milliseconds before attempt #" + (attemptsMade + 1)); + + final TaskCompletionSource retryTask = new TaskCompletionSource<>(); + ParseExecutors.scheduled().schedule(() -> { + executeAsync( + client, + request, + attemptsMade + 1, + delay * 2, + downloadProgressCallback, + cancellationToken).continueWithTask((Continuation>) task1 -> { + if (task1.isCancelled()) { + retryTask.setCancelled(); + } else if (task1.isFaulted()) { + retryTask.setError(task1.getError()); + } else { + retryTask.setResult(task1.getResult()); } - }, delay, TimeUnit.MILLISECONDS); - return retryTask.getTask(); - } + return null; + }); + }, delay, TimeUnit.MILLISECONDS); + return retryTask.getTask(); } - return task; } + return task; }); } diff --git a/parse/src/main/java/com/parse/ParseSQLiteCursor.java b/parse/src/main/java/com/parse/ParseSQLiteCursor.java index 092c9db27..13f1d762a 100644 --- a/parse/src/main/java/com/parse/ParseSQLiteCursor.java +++ b/parse/src/main/java/com/parse/ParseSQLiteCursor.java @@ -18,11 +18,11 @@ import android.os.Build; import android.os.Bundle; +import com.parse.boltsinternal.Task; + import java.util.concurrent.Callable; import java.util.concurrent.Executor; -import com.parse.boltsinternal.Task; - /** * Wrapper class to invoke {@link Cursor#close()} on a specific thread on Android versions below * android-14 as they require {@link Cursor#close()} to be called on the same thread the cursor @@ -32,8 +32,9 @@ */ class ParseSQLiteCursor implements Cursor { - private Cursor cursor; - private Executor executor; + private final Cursor cursor; + private final Executor executor; + private ParseSQLiteCursor(Cursor cursor, Executor executor) { this.cursor = cursor; this.executor = executor; @@ -197,12 +198,9 @@ public boolean requery() { @Override public void close() { // Basically close _eventually_. - Task.call(new Callable() { - @Override - public Void call() { - cursor.close(); - return null; - } + Task.call((Callable) () -> { + cursor.close(); + return null; }, executor); } diff --git a/parse/src/main/java/com/parse/ParseSQLiteDatabase.java b/parse/src/main/java/com/parse/ParseSQLiteDatabase.java index c1e72dd4d..689a5a0d7 100644 --- a/parse/src/main/java/com/parse/ParseSQLiteDatabase.java +++ b/parse/src/main/java/com/parse/ParseSQLiteDatabase.java @@ -13,13 +13,12 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; import com.parse.boltsinternal.TaskCompletionSource; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + class ParseSQLiteDatabase { /** @@ -39,9 +38,9 @@ class ParseSQLiteDatabase { private static final TaskQueue taskQueue = new TaskQueue(); private final Object currentLock = new Object(); private final TaskCompletionSource tcs = new TaskCompletionSource<>(); + private final int openFlags; private SQLiteDatabase db; private Task current = null; - private int openFlags; /** * Creates a Session which opens a database connection and begins a transaction @@ -51,36 +50,23 @@ private ParseSQLiteDatabase(int flags) { //TODO (grantland): if (!writable) -- do we have to serialize everything? openFlags = flags; - taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - synchronized (currentLock) { - current = toAwait; - } - return tcs.getTask(); + taskQueue.enqueue(toAwait -> { + synchronized (currentLock) { + current = toAwait; } + return tcs.getTask(); }); } /* protected */ static Task openDatabaseAsync(final SQLiteOpenHelper helper, int flags) { final ParseSQLiteDatabase db = new ParseSQLiteDatabase(flags); - return db.open(helper).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return Task.forResult(db); - } - }); + return db.open(helper).continueWithTask(task -> Task.forResult(db)); } public Task isReadOnlyAsync() { synchronized (currentLock) { - Task task = current.continueWith(new Continuation() { - @Override - public Boolean then(Task task) { - return db.isReadOnly(); - } - }); + Task task = current.continueWith(task1 -> db.isReadOnly()); current = task.makeVoid(); return task; } @@ -88,12 +74,7 @@ public Boolean then(Task task) { public Task isOpenAsync() { synchronized (currentLock) { - Task task = current.continueWith(new Continuation() { - @Override - public Boolean then(Task task) { - return db.isOpen(); - } - }); + Task task = current.continueWith(task1 -> db.isOpen()); current = task.makeVoid(); return task; } @@ -105,21 +86,15 @@ public boolean inTransaction() { /* package */ Task open(final SQLiteOpenHelper helper) { synchronized (currentLock) { - current = current.continueWith(new Continuation() { - @Override - public SQLiteDatabase then(Task task) { - // get*Database() is synchronous and calls through SQLiteOpenHelper#onCreate, onUpdate, - // etc. - return (openFlags & SQLiteDatabase.OPEN_READONLY) == SQLiteDatabase.OPEN_READONLY - ? helper.getReadableDatabase() - : helper.getWritableDatabase(); - } - }, dbExecutor).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - db = task.getResult(); - return task.makeVoid(); - } + current = current.continueWith(task -> { + // get*Database() is synchronous and calls through SQLiteOpenHelper#onCreate, onUpdate, + // etc. + return (openFlags & SQLiteDatabase.OPEN_READONLY) == SQLiteDatabase.OPEN_READONLY + ? helper.getReadableDatabase() + : helper.getWritableDatabase(); + }, dbExecutor).continueWithTask(task -> { + db = task.getResult(); + return task.makeVoid(); }, Task.BACKGROUND_EXECUTOR); // We want to jump off the dbExecutor return current; } @@ -132,19 +107,13 @@ public Task then(Task task) { */ public Task beginTransactionAsync() { synchronized (currentLock) { - current = current.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - db.beginTransaction(); - return task; - } + current = current.continueWithTask(task -> { + db.beginTransaction(); + return task; }, dbExecutor); - return current.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return current.continueWithTask(task -> { + // We want to jump off the dbExecutor + return task; }, Task.BACKGROUND_EXECUTOR); } } @@ -156,19 +125,13 @@ public Task then(Task task) { */ public Task setTransactionSuccessfulAsync() { synchronized (currentLock) { - current = current.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - db.setTransactionSuccessful(); - return task; - } + current = current.onSuccessTask(task -> { + db.setTransactionSuccessful(); + return task; }, dbExecutor); - return current.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return current.continueWithTask(task -> { + // We want to jump off the dbExecutor + return task; }, Task.BACKGROUND_EXECUTOR); } } @@ -180,20 +143,14 @@ public Task then(Task task) { */ public Task endTransactionAsync() { synchronized (currentLock) { - current = current.continueWith(new Continuation() { - @Override - public Void then(Task task) { - db.endTransaction(); - // We want to swallow any exceptions from our Session task - return null; - } + current = current.continueWith(task -> { + db.endTransaction(); + // We want to swallow any exceptions from our Session task + return null; }, dbExecutor); - return current.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return current.continueWithTask(task -> { + // We want to jump off the dbExecutor + return task; }, Task.BACKGROUND_EXECUTOR); } } @@ -204,23 +161,17 @@ public Task then(Task task) { */ public Task closeAsync() { synchronized (currentLock) { - current = current.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - try { - db.close(); - } finally { - tcs.setResult(null); - } - return tcs.getTask(); + current = current.continueWithTask(task -> { + try { + db.close(); + } finally { + tcs.setResult(null); } + return tcs.getTask(); }, dbExecutor); - return current.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return current.continueWithTask(task -> { + // We want to jump off the dbExecutor + return task; }, Task.BACKGROUND_EXECUTOR); } } @@ -233,29 +184,18 @@ public Task then(Task task) { public Task queryAsync(final String table, final String[] select, final String where, final String[] args) { synchronized (currentLock) { - Task task = current.onSuccess(new Continuation() { - @Override - public Cursor then(Task task) { - return db.query(table, select, where, args, null, null, null); - } - }, dbExecutor).onSuccess(new Continuation() { - @Override - public Cursor then(Task task) { - Cursor cursor = ParseSQLiteCursor.create(task.getResult(), dbExecutor); - /* Ensure the cursor window is filled on the dbExecutor thread. We need to do this because - * the cursor cannot be filled from a different thread than it was created on. - */ - cursor.getCount(); - return cursor; - } + Task task = current.onSuccess(task13 -> db.query(table, select, where, args, null, null, null), dbExecutor).onSuccess(task12 -> { + Cursor cursor = ParseSQLiteCursor.create(task12.getResult(), dbExecutor); + /* Ensure the cursor window is filled on the dbExecutor thread. We need to do this because + * the cursor cannot be filled from a different thread than it was created on. + */ + cursor.getCount(); + return cursor; }, dbExecutor); current = task.makeVoid(); - return task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return task.continueWithTask(task1 -> { + // We want to jump off the dbExecutor + return task1; }, Task.BACKGROUND_EXECUTOR); } } @@ -268,19 +208,11 @@ public Task then(Task task) { public Task insertWithOnConflict(final String table, final ContentValues values, final int conflictAlgorithm) { synchronized (currentLock) { - Task task = current.onSuccess(new Continuation() { - @Override - public Long then(Task task) { - return db.insertWithOnConflict(table, null, values, conflictAlgorithm); - } - }, dbExecutor); + Task task = current.onSuccess(task12 -> db.insertWithOnConflict(table, null, values, conflictAlgorithm), dbExecutor); current = task.makeVoid(); - return task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return task.continueWithTask(task1 -> { + // We want to jump off the dbExecutor + return task1; }, Task.BACKGROUND_EXECUTOR).makeVoid(); } } @@ -292,19 +224,11 @@ public Task then(Task task) { */ public Task insertOrThrowAsync(final String table, final ContentValues values) { synchronized (currentLock) { - Task task = current.onSuccess(new Continuation() { - @Override - public Long then(Task task) { - return db.insertOrThrow(table, null, values); - } - }, dbExecutor); + Task task = current.onSuccess(task12 -> db.insertOrThrow(table, null, values), dbExecutor); current = task.makeVoid(); - return task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return task.continueWithTask(task1 -> { + // We want to jump off the dbExecutor + return task1; }, Task.BACKGROUND_EXECUTOR).makeVoid(); } } @@ -317,19 +241,11 @@ public Task then(Task task) { public Task updateAsync(final String table, final ContentValues values, final String where, final String[] args) { synchronized (currentLock) { - Task task = current.onSuccess(new Continuation() { - @Override - public Integer then(Task task) { - return db.update(table, values, where, args); - } - }, dbExecutor); + Task task = current.onSuccess(task12 -> db.update(table, values, where, args), dbExecutor); current = task.makeVoid(); - return task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return task.continueWithTask(task1 -> { + // We want to jump off the dbExecutor + return task1; }, Task.BACKGROUND_EXECUTOR); } } @@ -341,19 +257,11 @@ public Task then(Task task) { */ public Task deleteAsync(final String table, final String where, final String[] args) { synchronized (currentLock) { - Task task = current.onSuccess(new Continuation() { - @Override - public Integer then(Task task) { - return db.delete(table, where, args); - } - }, dbExecutor); + Task task = current.onSuccess(task12 -> db.delete(table, where, args), dbExecutor); current = task.makeVoid(); - return task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return task.continueWithTask(task1 -> { + // We want to jump off the dbExecutor + return task1; }, Task.BACKGROUND_EXECUTOR).makeVoid(); } } @@ -365,28 +273,17 @@ public Task then(Task task) { */ public Task rawQueryAsync(final String sql, final String[] args) { synchronized (currentLock) { - Task task = current.onSuccess(new Continuation() { - @Override - public Cursor then(Task task) { - return db.rawQuery(sql, args); - } - }, dbExecutor).onSuccess(new Continuation() { - @Override - public Cursor then(Task task) { - Cursor cursor = ParseSQLiteCursor.create(task.getResult(), dbExecutor); - // Ensure the cursor window is filled on the dbExecutor thread. We need to do this because - // the cursor cannot be filled from a different thread than it was created on. - cursor.getCount(); - return cursor; - } + Task task = current.onSuccess(task13 -> db.rawQuery(sql, args), dbExecutor).onSuccess(task12 -> { + Cursor cursor = ParseSQLiteCursor.create(task12.getResult(), dbExecutor); + // Ensure the cursor window is filled on the dbExecutor thread. We need to do this because + // the cursor cannot be filled from a different thread than it was created on. + cursor.getCount(); + return cursor; }, dbExecutor); current = task.makeVoid(); - return task.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - // We want to jump off the dbExecutor - return task; - } + return task.continueWithTask(task1 -> { + // We want to jump off the dbExecutor + return task1; }, Task.BACKGROUND_EXECUTOR); } } diff --git a/parse/src/main/java/com/parse/ParseSession.java b/parse/src/main/java/com/parse/ParseSession.java index 7824a379d..ca3b1d5d4 100644 --- a/parse/src/main/java/com/parse/ParseSession.java +++ b/parse/src/main/java/com/parse/ParseSession.java @@ -8,13 +8,12 @@ */ package com.parse; +import com.parse.boltsinternal.Task; + import java.util.Arrays; import java.util.Collections; import java.util.List; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * The {@code ParseSession} is a local representation of session data that can be saved * and retrieved from the Parse cloud. @@ -44,21 +43,15 @@ private static ParseSessionController getSessionController() { * logged in. */ public static Task getCurrentSessionInBackground() { - return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String sessionToken = task.getResult(); - if (sessionToken == null) { - return Task.forResult(null); - } - return getSessionController().getSessionAsync(sessionToken).onSuccess(new Continuation() { - @Override - public ParseSession then(Task task) { - ParseObject.State result = task.getResult(); - return ParseObject.from(result); - } - }); + return ParseUser.getCurrentSessionTokenAsync().onSuccessTask(task -> { + String sessionToken = task.getResult(); + if (sessionToken == null) { + return Task.forResult(null); } + return getSessionController().getSessionAsync(sessionToken).onSuccess(task1 -> { + State result = task1.getResult(); + return ParseObject.from(result); + }); }); } @@ -86,12 +79,9 @@ static Task upgradeToRevocableSessionAsync(String sessionToken) { return Task.forResult(sessionToken); } - return getSessionController().upgradeToRevocable(sessionToken).onSuccess(new Continuation() { - @Override - public String then(Task task) { - ParseObject.State result = task.getResult(); - return ParseObject.from(result).getSessionToken(); - } + return getSessionController().upgradeToRevocable(sessionToken).onSuccess(task -> { + State result = task.getResult(); + return ParseObject.from(result).getSessionToken(); }); } diff --git a/parse/src/main/java/com/parse/ParseTaskUtils.java b/parse/src/main/java/com/parse/ParseTaskUtils.java index 82e1bdb27..8f9b43621 100644 --- a/parse/src/main/java/com/parse/ParseTaskUtils.java +++ b/parse/src/main/java/com/parse/ParseTaskUtils.java @@ -8,13 +8,13 @@ */ package com.parse; -import java.util.concurrent.CancellationException; - import com.parse.boltsinternal.AggregateException; import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; import com.parse.boltsinternal.TaskCompletionSource; +import java.util.concurrent.CancellationException; + class ParseTaskUtils { /** @@ -72,12 +72,7 @@ static Task callbackOnMainThreadAsync(Task task, if (callback == null) { return task; } - return callbackOnMainThreadAsync(task, new ParseCallback2() { - @Override - public void done(Void aVoid, ParseException e) { - callback.done(e); - } - }, reportCancellation); + return callbackOnMainThreadAsync(task, (aVoid, e) -> callback.done(e), reportCancellation); } @@ -103,35 +98,29 @@ static Task callbackOnMainThreadAsync(Task task, return task; } final TaskCompletionSource tcs = new TaskCompletionSource(); - task.continueWith(new Continuation() { - @Override - public Void then(final Task task) { - if (task.isCancelled() && !reportCancellation) { - tcs.setCancelled(); - return null; - } - ParseExecutors.main().execute(new Runnable() { - @Override - public void run() { - try { - Exception error = task.getError(); - if (error != null && !(error instanceof ParseException)) { - error = new ParseException(error); - } - callback.done(task.getResult(), (ParseException) error); - } finally { - if (task.isCancelled()) { - tcs.setCancelled(); - } else if (task.isFaulted()) { - tcs.setError(task.getError()); - } else { - tcs.setResult(task.getResult()); - } - } - } - }); + task.continueWith((Continuation) task1 -> { + if (task1.isCancelled() && !reportCancellation) { + tcs.setCancelled(); return null; } + ParseExecutors.main().execute(() -> { + try { + Exception error = task1.getError(); + if (error != null && !(error instanceof ParseException)) { + error = new ParseException(error); + } + callback.done(task1.getResult(), (ParseException) error); + } finally { + if (task1.isCancelled()) { + tcs.setCancelled(); + } else if (task1.isFaulted()) { + tcs.setError(task1.getError()); + } else { + tcs.setResult(task1.getResult()); + } + } + }); + return null; }); return tcs.getTask(); } diff --git a/parse/src/main/java/com/parse/ParseTextUtils.java b/parse/src/main/java/com/parse/ParseTextUtils.java index 152d93e4a..cc7221a04 100644 --- a/parse/src/main/java/com/parse/ParseTextUtils.java +++ b/parse/src/main/java/com/parse/ParseTextUtils.java @@ -16,6 +16,8 @@ package com.parse; +import java.util.Objects; + /* package */ class ParseTextUtils { private ParseTextUtils() { @@ -63,6 +65,6 @@ public static boolean isEmpty(CharSequence text) { * @return true if a and b are equal */ public static boolean equals(CharSequence a, CharSequence b) { - return (a == b) || (a != null && a.equals(b)); + return Objects.equals(a, b); } } diff --git a/parse/src/main/java/com/parse/ParseUser.java b/parse/src/main/java/com/parse/ParseUser.java index b93dbb2db..935584d88 100644 --- a/parse/src/main/java/com/parse/ParseUser.java +++ b/parse/src/main/java/com/parse/ParseUser.java @@ -10,8 +10,12 @@ import android.os.Bundle; import android.os.Parcel; + import androidx.annotation.NonNull; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import java.util.ArrayList; @@ -23,9 +27,6 @@ import java.util.List; import java.util.Map; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * The {@code ParseUser} is a local representation of user data that can be saved and retrieved from * the Parse cloud. @@ -100,18 +101,10 @@ public static Task logInInBackground(String username, String password throw new IllegalArgumentException("Must specify a password for the user to log in with"); } - return getUserController().logInAsync(username, password).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - State result = task.getResult(); - final ParseUser newCurrent = ParseObject.from(result); - return saveCurrentUserAsync(newCurrent).onSuccess(new Continuation() { - @Override - public ParseUser then(Task task) { - return newCurrent; - } - }); - } + return getUserController().logInAsync(username, password).onSuccessTask(task -> { + State result = task.getResult(); + final ParseUser newCurrent = ParseObject.from(result); + return saveCurrentUserAsync(newCurrent).onSuccess(task1 -> newCurrent); }); } @@ -162,19 +155,11 @@ public static Task becomeInBackground(String sessionToken) { throw new IllegalArgumentException("Must specify a sessionToken for the user to log in with"); } - return getUserController().getUserAsync(sessionToken).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - State result = task.getResult(); - - final ParseUser user = ParseObject.from(result); - return saveCurrentUserAsync(user).onSuccess(new Continuation() { - @Override - public ParseUser then(Task task) { - return user; - } - }); - } + return getUserController().getUserAsync(sessionToken).onSuccessTask(task -> { + State result = task.getResult(); + + final ParseUser user = ParseObject.from(result); + return saveCurrentUserAsync(user).onSuccess(task1 -> user); }); } @@ -390,97 +375,67 @@ public static Task logInWithInBackground( throw new IllegalArgumentException("Invalid authType: " + null); } - final Continuation> logInWithTask = new Continuation>() { - @Override - public Task then(Task task) { - return getUserController().logInAsync(authType, authData).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseUser.State result = task.getResult(); - final ParseUser user = ParseObject.from(result); - return saveCurrentUserAsync(user).onSuccess(new Continuation() { - @Override - public ParseUser then(Task task) { - return user; - } - }); - } - }); - } - }; + final Continuation> logInWithTask = task -> getUserController().logInAsync(authType, authData).onSuccessTask(task15 -> { + State result = task15.getResult(); + final ParseUser user = ParseObject.from(result); + return saveCurrentUserAsync(user).onSuccess(task14 -> user); + }); // Handle claiming of user. - return getCurrentUserController().getAsync(false).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseUser user = task.getResult(); - if (user != null) { - synchronized (user.mutex) { - if (ParseAnonymousUtils.isLinked(user)) { - if (user.isLazy()) { - final Map oldAnonymousData = - user.getAuthData(ParseAnonymousUtils.AUTH_TYPE); - return user.taskQueue.enqueue(new Continuation>() { - @Override - public Task then(final Task toAwait) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (user.mutex) { - // Replace any anonymity with the new linked authData. - user.stripAnonymity(); - user.putAuthData(authType, authData); - - return user.resolveLazinessAsync(task); - } - } - }).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (user.mutex) { - if (task.isFaulted()) { - user.removeAuthData(authType); - user.restoreAnonymity(oldAnonymousData); - return Task.forError(task.getError()); - } - if (task.isCancelled()) { - return Task.cancelled(); - } - return Task.forResult(user); - } - } - }); + return getCurrentUserController().getAsync(false).onSuccessTask(task -> { + final ParseUser user = task.getResult(); + if (user != null) { + synchronized (user.mutex) { + if (ParseAnonymousUtils.isLinked(user)) { + if (user.isLazy()) { + final Map oldAnonymousData = + user.getAuthData(ParseAnonymousUtils.AUTH_TYPE); + return user.taskQueue.enqueue(toAwait -> toAwait.continueWithTask(task13 -> { + synchronized (user.mutex) { + // Replace any anonymity with the new linked authData. + user.stripAnonymity(); + user.putAuthData(authType, authData); + + return user.resolveLazinessAsync(task13); + } + }).continueWithTask(task12 -> { + synchronized (user.mutex) { + if (task12.isFaulted()) { + user.removeAuthData(authType); + user.restoreAnonymity(oldAnonymousData); + return Task.forError(task12.getError()); } - }); - } else { - // Try to link the current user with third party user, unless a user is already linked - // to that third party user, then we'll just create a new user and link it with the - // third party user. New users will not be linked to the previous user's data. - return user.linkWithInBackground(authType, authData) - .continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isFaulted()) { - Exception error = task.getError(); - if (error instanceof ParseException - && ((ParseException) error).getCode() == ParseException.ACCOUNT_ALREADY_LINKED) { - // An account that's linked to the given authData already exists, so log in - // instead of trying to claim. - return Task.forResult(null).continueWithTask(logInWithTask); - } - } - if (task.isCancelled()) { - return Task.cancelled(); - } - return Task.forResult(user); + if (task12.isCancelled()) { + return Task.cancelled(); + } + return Task.forResult(user); + } + })); + } else { + // Try to link the current user with third party user, unless a user is already linked + // to that third party user, then we'll just create a new user and link it with the + // third party user. New users will not be linked to the previous user's data. + return user.linkWithInBackground(authType, authData) + .continueWithTask(task1 -> { + if (task1.isFaulted()) { + Exception error = task1.getError(); + if (error instanceof ParseException + && ((ParseException) error).getCode() == ParseException.ACCOUNT_ALREADY_LINKED) { + // An account that's linked to the given authData already exists, so log in + // instead of trying to claim. + return Task.forResult(null).continueWithTask(logInWithTask); } - }); - } + } + if (task1.isCancelled()) { + return Task.cancelled(); + } + return Task.forResult(user); + }); } } } - return Task.forResult(null).continueWithTask(logInWithTask); } + return Task.forResult(null).continueWithTask(logInWithTask); }); } @@ -529,15 +484,12 @@ public static Task enableRevocableSessionInBackground() { ParseCorePlugins.getInstance().registerUserController( new NetworkUserController(ParsePlugins.get().restClient(), true)); - return getCurrentUserController().getAsync(false).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseUser user = task.getResult(); - if (user == null) { - return Task.forResult(null); - } - return user.upgradeToRevocableSessionAsync(); + return getCurrentUserController().getAsync(false).onSuccessTask(task -> { + ParseUser user = task.getResult(); + if (user == null) { + return Task.forResult(null); } + return user.upgradeToRevocableSessionAsync(); }); } @@ -875,17 +827,7 @@ private void restoreAnonymity(Map anonymousData) { if (isCurrentUser()) { // If the user is the currently logged in user, we persist all data to disk - return task.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return cleanUpAuthDataAsync(); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return saveCurrentUserAsync(ParseUser.this); - } - }); + return task.onSuccessTask(task12 -> cleanUpAuthDataAsync()).onSuccessTask(task1 -> saveCurrentUserAsync(ParseUser.this)); } return task; @@ -920,22 +862,7 @@ public ParseUser fetch() throws ParseException { Task task = super.fetchAsync(sessionToken, toAwait); if (isCurrentUser()) { - return task.onSuccessTask(new Continuation>() { - @Override - public Task then(final Task fetchAsyncTask) { - return cleanUpAuthDataAsync(); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return saveCurrentUserAsync(ParseUser.this); - } - }).onSuccess(new Continuation() { - @Override - public T then(Task task) { - return (T) ParseUser.this; - } - }); + return task.onSuccessTask(fetchAsyncTask -> cleanUpAuthDataAsync()).onSuccessTask(task12 -> saveCurrentUserAsync(ParseUser.this)).onSuccess(task1 -> (T) ParseUser.this); } return task; @@ -956,12 +883,7 @@ public T then(Task task) { * @return A Task that is resolved when sign up completes. */ public Task signUpInBackground() { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task task) { - return signUpAsync(task); - } - }); + return taskQueue.enqueue(this::signUpAsync); } /* package for tests */ Task signUpAsync(Task toAwait) { @@ -1020,60 +942,46 @@ public Task then(Task task) { user.setPassword(getPassword()); revert(); - return user.saveAsync(sessionToken, isLazy, toAwait).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (task.isCancelled() || task.isFaulted()) { // Error - synchronized (user.mutex) { - if (oldUsername != null) { - user.setUsername(oldUsername); - } else { - user.revert(KEY_USERNAME); - } - if (oldPassword != null) { - user.setPassword(oldPassword); - } else { - user.revert(KEY_PASSWORD); - } - user.restoreAnonymity(anonymousData); + return user.saveAsync(sessionToken, isLazy, toAwait).continueWithTask(task -> { + if (task.isCancelled() || task.isFaulted()) { // Error + synchronized (user.mutex) { + if (oldUsername != null) { + user.setUsername(oldUsername); + } else { + user.revert(KEY_USERNAME); } - return task; - } else { // Success - user.revert(KEY_PASSWORD); - revert(KEY_PASSWORD); + if (oldPassword != null) { + user.setPassword(oldPassword); + } else { + user.revert(KEY_PASSWORD); + } + user.restoreAnonymity(anonymousData); } - - mergeFromObject(user); - return saveCurrentUserAsync(ParseUser.this); + return task; + } else { // Success + user.revert(KEY_PASSWORD); + revert(KEY_PASSWORD); } + + mergeFromObject(user); + return saveCurrentUserAsync(ParseUser.this); }); } final ParseOperationSet operations = startSave(); - return toAwait.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return getUserController().signUpAsync( - getState(), operations, sessionToken - ).continueWithTask(new Continuation>() { - @Override - public Task then(final Task signUpTask) { - ParseUser.State result = signUpTask.getResult(); - return handleSaveResultAsync(result, - operations).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (!signUpTask.isCancelled() && !signUpTask.isFaulted()) { - return saveCurrentUserAsync(ParseUser.this); - } - return signUpTask.makeVoid(); - } - }); - } - }); - } - }); + return toAwait.onSuccessTask(task -> getUserController().signUpAsync( + getState(), operations, sessionToken + ).continueWithTask(signUpTask -> { + State result = signUpTask.getResult(); + return handleSaveResultAsync(result, + operations).continueWithTask(task1 -> { + if (!signUpTask.isCancelled() && !signUpTask.isFaulted()) { + return saveCurrentUserAsync(ParseUser.this); + } + return signUpTask.makeVoid(); + }); + })); } } @@ -1197,15 +1105,12 @@ public boolean isLinked(String authType) { private Task synchronizeAuthDataAsync( ParseAuthenticationManager manager, final String authType, Map authData) { - return manager.restoreAuthenticationAsync(authType, authData).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - boolean success = !task.isFaulted() && task.getResult(); - if (!success) { - return unlinkFromInBackground(authType); - } - return task.makeVoid(); + return manager.restoreAuthenticationAsync(authType, authData).continueWithTask(task -> { + boolean success = !task.isFaulted() && task.getResult(); + if (!success) { + return unlinkFromInBackground(authType); } + return task.makeVoid(); }); } @@ -1221,17 +1126,14 @@ private Task linkWithAsync( stripAnonymity(); putAuthData(authType, authData); - return saveAsync(sessionToken, isLazy, toAwait).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - synchronized (mutex) { - if (task.isFaulted() || task.isCancelled()) { - removeAuthData(authType); - restoreAnonymity(oldAnonymousData); - return task; - } - return synchronizeAuthDataAsync(authType); + return saveAsync(sessionToken, isLazy, toAwait).continueWithTask(task -> { + synchronized (mutex) { + if (task.isFaulted() || task.isCancelled()) { + removeAuthData(authType); + restoreAnonymity(oldAnonymousData); + return task; } + return synchronizeAuthDataAsync(authType); } }); } @@ -1243,12 +1145,7 @@ private Task linkWithAsync( final String authType, final Map authData, final String sessionToken) { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task task) { - return linkWithAsync(authType, authData, task, sessionToken); - } - }); + return taskQueue.enqueue(task -> linkWithAsync(authType, authData, task, sessionToken)); } /** @@ -1316,45 +1213,29 @@ public Task unlinkFromInBackground(final String authType) { final ParseOperationSet operations = startSave(); // Otherwise, treat this as a SignUpOrLogIn - return toAwait.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - return getUserController().logInAsync(getState(), operations).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - final ParseUser.State result = task.getResult(); - - Task resultTask; - // We can't merge this user with the server if this is a LogIn because LDS might - // already be keeping track of the servers objectId. - if (Parse.isLocalDatastoreEnabled() && !result.isNew()) { - resultTask = Task.forResult(result); - } else { - resultTask = handleSaveResultAsync(result, - operations).onSuccess(new Continuation() { - @Override - public ParseUser.State then(Task task) { - return result; - } - }); - } - return resultTask.onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - ParseUser.State result = task.getResult(); - if (!result.isNew()) { - // If the result is not a new user, treat this as a fresh logIn with complete - // serverData, and switch the current user to the new user. - final ParseUser newUser = ParseObject.from(result); - return saveCurrentUserAsync(newUser); - } - return task.makeVoid(); - } - }); - } - }); + return toAwait.onSuccessTask(task -> getUserController().logInAsync(getState(), operations).onSuccessTask(task13 -> { + final State result = task13.getResult(); + + Task resultTask; + // We can't merge this user with the server if this is a LogIn because LDS might + // already be keeping track of the servers objectId. + if (Parse.isLocalDatastoreEnabled() && !result.isNew()) { + resultTask = Task.forResult(result); + } else { + resultTask = handleSaveResultAsync(result, + operations).onSuccess(task12 -> result); } - }); + return resultTask.onSuccessTask(task1 -> { + State result1 = task1.getResult(); + if (!result1.isNew()) { + // If the result is not a new user, treat this as a fresh logIn with complete + // serverData, and switch the current user to the new user. + final ParseUser newUser = ParseObject.from(result1); + return saveCurrentUserAsync(newUser); + } + return task1.makeVoid(); + }); + })); } } @@ -1391,27 +1272,14 @@ protected void onRestoreInstanceState(Bundle savedState) { //region Legacy/Revocable Session Tokens /* package */ Task upgradeToRevocableSessionAsync() { - return taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task toAwait) { - return upgradeToRevocableSessionAsync(toAwait); - } - }); + return taskQueue.enqueue(this::upgradeToRevocableSessionAsync); } private Task upgradeToRevocableSessionAsync(Task toAwait) { final String sessionToken = getSessionToken(); - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - return ParseSession.upgradeToRevocableSessionAsync(sessionToken); - } - }).onSuccessTask(new Continuation>() { - @Override - public Task then(Task task) { - String result = task.getResult(); - return setSessionTokenInBackground(result); - } + return toAwait.continueWithTask(task -> ParseSession.upgradeToRevocableSessionAsync(sessionToken)).onSuccessTask(task -> { + String result = task.getResult(); + return setSessionTokenInBackground(result); }); } diff --git a/parse/src/main/java/com/parse/ParseUserController.java b/parse/src/main/java/com/parse/ParseUserController.java index 0ee548231..2b411ad72 100644 --- a/parse/src/main/java/com/parse/ParseUserController.java +++ b/parse/src/main/java/com/parse/ParseUserController.java @@ -8,10 +8,10 @@ */ package com.parse; -import java.util.Map; - import com.parse.boltsinternal.Task; +import java.util.Map; + interface ParseUserController { Task signUpAsync( diff --git a/parse/src/main/java/com/parse/ParseUserCurrentCoder.java b/parse/src/main/java/com/parse/ParseUserCurrentCoder.java index dedd9eae9..00d6a7aa3 100644 --- a/parse/src/main/java/com/parse/ParseUserCurrentCoder.java +++ b/parse/src/main/java/com/parse/ParseUserCurrentCoder.java @@ -8,14 +8,14 @@ */ package com.parse; +import static com.parse.ParseUser.State; + import org.json.JSONException; import org.json.JSONObject; import java.util.Iterator; import java.util.Map; -import static com.parse.ParseUser.State; - /** * Handles encoding/decoding ParseUser to/from /2 format JSON. /2 format json is only used for * persisting current ParseUser and ParseInstallation to disk when LDS is not enabled. diff --git a/parse/src/main/java/com/parse/PushHistory.java b/parse/src/main/java/com/parse/PushHistory.java index b952e9cf2..5ac475e7c 100644 --- a/parse/src/main/java/com/parse/PushHistory.java +++ b/parse/src/main/java/com/parse/PushHistory.java @@ -28,6 +28,7 @@ class PushHistory { private final PriorityQueue entries; private final HashSet pushIds; private String lastTime; + /** * Creates a push history object from a JSON object that looks like this: *

@@ -131,8 +132,8 @@ public boolean tryInsertPush(String pushId, String timestamp) { } private static class Entry implements Comparable { - public String pushId; - public String timestamp; + public final String pushId; + public final String timestamp; public Entry(String pushId, String timestamp) { this.pushId = pushId; diff --git a/parse/src/main/java/com/parse/TaskQueue.java b/parse/src/main/java/com/parse/TaskQueue.java index f8ba25181..20af61c8e 100644 --- a/parse/src/main/java/com/parse/TaskQueue.java +++ b/parse/src/main/java/com/parse/TaskQueue.java @@ -8,13 +8,13 @@ */ package com.parse; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; + import java.util.Arrays; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - /** * A helper class for enqueueing tasks */ @@ -31,17 +31,7 @@ class TaskQueue { * continuations. */ static Continuation> waitFor(final Task toAwait) { - return new Continuation>() { - @Override - public Task then(final Task task) { - return toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task ignored) { - return task; - } - }); - } - }; + return task -> toAwait.continueWithTask(ignored -> task); } /** @@ -54,12 +44,7 @@ private Task getTaskToAwait() { lock.lock(); try { Task toAwait = tail != null ? tail : Task.forResult(null); - return toAwait.continueWith(new Continuation() { - @Override - public Void then(Task task) { - return null; - } - }); + return toAwait.continueWith(task -> null); } finally { lock.unlock(); } diff --git a/parse/src/main/java/com/parse/WeakValueHashMap.java b/parse/src/main/java/com/parse/WeakValueHashMap.java index fab6a62af..d7a01c19b 100644 --- a/parse/src/main/java/com/parse/WeakValueHashMap.java +++ b/parse/src/main/java/com/parse/WeakValueHashMap.java @@ -15,7 +15,7 @@ * A HashMap where all the values are weak. */ class WeakValueHashMap { - private HashMap> map; + private final HashMap> map; public WeakValueHashMap() { map = new HashMap<>(); diff --git a/parse/src/main/java/com/parse/http/ParseHttpRequest.java b/parse/src/main/java/com/parse/http/ParseHttpRequest.java index 2e91f3597..80e5d576b 100644 --- a/parse/src/main/java/com/parse/http/ParseHttpRequest.java +++ b/parse/src/main/java/com/parse/http/ParseHttpRequest.java @@ -22,6 +22,7 @@ public final class ParseHttpRequest { private final Method method; private final Map headers; private final ParseHttpBody body; + private ParseHttpRequest(Builder builder) { this.url = builder.url; this.method = builder.method; diff --git a/parse/src/main/java/com/parse/http/ParseHttpResponse.java b/parse/src/main/java/com/parse/http/ParseHttpResponse.java index 367985019..8cb9c96b1 100644 --- a/parse/src/main/java/com/parse/http/ParseHttpResponse.java +++ b/parse/src/main/java/com/parse/http/ParseHttpResponse.java @@ -25,6 +25,7 @@ public final class ParseHttpResponse { private final String reasonPhrase; private final Map headers; private final String contentType; + private ParseHttpResponse(Builder builder) { this.statusCode = builder.statusCode; this.content = builder.content; diff --git a/parse/src/test/java/com/parse/CachedCurrentInstallationControllerTest.java b/parse/src/test/java/com/parse/CachedCurrentInstallationControllerTest.java index 421ecf3c1..f49cd93e6 100644 --- a/parse/src/test/java/com/parse/CachedCurrentInstallationControllerTest.java +++ b/parse/src/test/java/com/parse/CachedCurrentInstallationControllerTest.java @@ -8,13 +8,6 @@ */ package com.parse; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; @@ -26,6 +19,13 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + public class CachedCurrentInstallationControllerTest { private static final String KEY_DEVICE_TYPE = "deviceType"; diff --git a/parse/src/test/java/com/parse/CachedCurrentUserControllerTest.java b/parse/src/test/java/com/parse/CachedCurrentUserControllerTest.java index 56d05a444..87c7056a5 100644 --- a/parse/src/test/java/com/parse/CachedCurrentUserControllerTest.java +++ b/parse/src/test/java/com/parse/CachedCurrentUserControllerTest.java @@ -8,15 +8,6 @@ */ package com.parse; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -import com.parse.boltsinternal.Task; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -28,6 +19,15 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.parse.boltsinternal.Task; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + @SuppressWarnings("unchecked") public class CachedCurrentUserControllerTest extends ResetPluginsParseTest { @@ -217,7 +217,7 @@ public void testGetAsyncWithCurrentUserReadFromDiskSuccess() throws Exception { public void testGetAsyncAnonymousUser() throws Exception { ParseUser.State state = new ParseUser.State.Builder() .objectId("fake") - .putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap()) + .putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<>()) .build(); ParseObjectStore store = (ParseObjectStore) mock(ParseObjectStore.class); @@ -233,7 +233,7 @@ public void testGetAsyncAnonymousUser() throws Exception { @Test public void testGetAsyncLazyAnonymousUser() throws Exception { ParseUser.State state = new ParseUser.State.Builder() - .putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap()) + .putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<>()) .build(); ParseObjectStore store = (ParseObjectStore) mock(ParseObjectStore.class); diff --git a/parse/src/test/java/com/parse/EventuallyPinTest.java b/parse/src/test/java/com/parse/EventuallyPinTest.java index d8d6d05cb..36bdfe55f 100644 --- a/parse/src/test/java/com/parse/EventuallyPinTest.java +++ b/parse/src/test/java/com/parse/EventuallyPinTest.java @@ -1,7 +1,15 @@ package com.parse; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.database.sqlite.SQLiteException; +import com.parse.boltsinternal.Task; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -9,21 +17,12 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import com.parse.boltsinternal.Task; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class EventuallyPinTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); @Before public void setUp() { @@ -45,7 +44,7 @@ public void testFailingFindAllPinned() throws Exception { Parse.setLocalDatastore(offlineStore); when(offlineStore.findFromPinAsync(eq(EventuallyPin.PIN_NAME), any(ParseQuery.State.class), - any(ParseUser.class))) + nullable(ParseUser.class))) .thenReturn(Task.forError(new SQLiteException())); ParsePlugins plugins = mock(ParsePlugins.class); diff --git a/parse/src/test/java/com/parse/FileObjectStoreTest.java b/parse/src/test/java/com/parse/FileObjectStoreTest.java index 0581db5c7..fc460ca42 100644 --- a/parse/src/test/java/com/parse/FileObjectStoreTest.java +++ b/parse/src/test/java/com/parse/FileObjectStoreTest.java @@ -8,16 +8,6 @@ */ package com.parse; -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.skyscreamer.jsonassert.JSONCompareMode; - -import java.io.File; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -28,10 +18,20 @@ import static org.mockito.Mockito.when; import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; +import org.json.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.skyscreamer.jsonassert.JSONCompareMode; + +import java.io.File; + public class FileObjectStoreTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before public void setUp() { diff --git a/parse/src/test/java/com/parse/InstallationIdTest.java b/parse/src/test/java/com/parse/InstallationIdTest.java index fdf6dea9f..ccca4508a 100644 --- a/parse/src/test/java/com/parse/InstallationIdTest.java +++ b/parse/src/test/java/com/parse/InstallationIdTest.java @@ -8,20 +8,21 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import java.io.File; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; - public class InstallationIdTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Test public void testGetGeneratesInstallationIdAndFile() throws Exception { @@ -78,7 +79,7 @@ public void testInstallationIdIsRandom() { String installationIdString = new InstallationId(installationIdFile).get(); ParseFileUtils.deleteQuietly(installationIdFile); - assertFalse(installationIdString.equals(new InstallationId(installationIdFile).get())); + assertNotEquals(installationIdString, new InstallationId(installationIdFile).get()); } @Test diff --git a/parse/src/test/java/com/parse/ListsTest.java b/parse/src/test/java/com/parse/ListsTest.java index b32bd301e..ecc85d7ef 100644 --- a/parse/src/test/java/com/parse/ListsTest.java +++ b/parse/src/test/java/com/parse/ListsTest.java @@ -8,13 +8,13 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; + import org.junit.Test; import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; - public class ListsTest { @Test diff --git a/parse/src/test/java/com/parse/LocalIdManagerTest.java b/parse/src/test/java/com/parse/LocalIdManagerTest.java index acd0dd7d3..0c2b0631f 100644 --- a/parse/src/test/java/com/parse/LocalIdManagerTest.java +++ b/parse/src/test/java/com/parse/LocalIdManagerTest.java @@ -8,25 +8,23 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + import org.json.JSONObject; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class LocalIdManagerTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Test public void testLocalIdManager() throws Exception { diff --git a/parse/src/test/java/com/parse/NetworkObjectControllerTest.java b/parse/src/test/java/com/parse/NetworkObjectControllerTest.java index 866af9f30..db8d4c0dd 100644 --- a/parse/src/test/java/com/parse/NetworkObjectControllerTest.java +++ b/parse/src/test/java/com/parse/NetworkObjectControllerTest.java @@ -8,6 +8,14 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -20,7 +28,6 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.io.ByteArrayInputStream; import java.net.MalformedURLException; @@ -28,22 +35,12 @@ import java.util.ArrayList; import java.util.List; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - // For Uri.encode @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class NetworkObjectControllerTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); @Before public void setUp() throws MalformedURLException { diff --git a/parse/src/test/java/com/parse/NetworkQueryControllerTest.java b/parse/src/test/java/com/parse/NetworkQueryControllerTest.java index 74b9ff82a..a02e8d314 100644 --- a/parse/src/test/java/com/parse/NetworkQueryControllerTest.java +++ b/parse/src/test/java/com/parse/NetworkQueryControllerTest.java @@ -8,6 +8,12 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -19,12 +25,6 @@ import java.net.URL; import java.util.List; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - public class NetworkQueryControllerTest { private static JSONObject generateBasicMockResponse() throws JSONException { diff --git a/parse/src/test/java/com/parse/NetworkSessionControllerTest.java b/parse/src/test/java/com/parse/NetworkSessionControllerTest.java index b2c2a4b1a..5a50d61c5 100644 --- a/parse/src/test/java/com/parse/NetworkSessionControllerTest.java +++ b/parse/src/test/java/com/parse/NetworkSessionControllerTest.java @@ -8,6 +8,9 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import org.json.JSONException; import org.json.JSONObject; import org.junit.After; @@ -15,18 +18,13 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - // For Uri.encode @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class NetworkSessionControllerTest { private static JSONObject generateBasicMockResponse() throws JSONException { diff --git a/parse/src/test/java/com/parse/NetworkUserControllerTest.java b/parse/src/test/java/com/parse/NetworkUserControllerTest.java index 9c87aafbf..73207ba8a 100644 --- a/parse/src/test/java/com/parse/NetworkUserControllerTest.java +++ b/parse/src/test/java/com/parse/NetworkUserControllerTest.java @@ -8,6 +8,10 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import org.json.JSONException; import org.json.JSONObject; import org.junit.After; @@ -15,20 +19,14 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - // For Uri.encode @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class NetworkUserControllerTest { @Before diff --git a/parse/src/test/java/com/parse/OfflineObjectStoreTest.java b/parse/src/test/java/com/parse/OfflineObjectStoreTest.java index 6affeb896..9b30b8cc7 100644 --- a/parse/src/test/java/com/parse/OfflineObjectStoreTest.java +++ b/parse/src/test/java/com/parse/OfflineObjectStoreTest.java @@ -8,22 +8,11 @@ */ package com.parse; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.rules.TemporaryFolder; - -import java.util.Arrays; -import java.util.Collections; - -import com.parse.boltsinternal.Task; - import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyList; @@ -33,14 +22,25 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.parse.boltsinternal.Task; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.rules.TemporaryFolder; + +import java.util.Arrays; +import java.util.Collections; + public class OfflineObjectStoreTest { private static final String PIN_NAME = "test"; - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final ExpectedException thrown = ExpectedException.none(); @Rule - public ExpectedException thrown = ExpectedException.none(); + public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before public void setUp() { @@ -82,7 +82,7 @@ public void testGetAsyncFromLDS() throws Exception { //noinspection unchecked when(queryController.findAsync( any(ParseQuery.State.class), - any(ParseUser.class), + nullable(ParseUser.class), any(Task.class)) ).thenReturn(Task.forResult(Collections.singletonList(user))); ParseCorePlugins.getInstance().registerQueryController(queryController); @@ -93,7 +93,7 @@ public void testGetAsyncFromLDS() throws Exception { ParseUser userAgain = ParseTaskUtils.wait(store.getAsync()); //noinspection unchecked verify(queryController, times(1)) - .findAsync(any(ParseQuery.State.class), any(ParseUser.class), any(Task.class)); + .findAsync(any(ParseQuery.State.class), nullable(ParseUser.class), any(Task.class)); assertSame(user, userAgain); } @@ -104,7 +104,7 @@ public void testGetAsyncFromLDSWithTooManyObjects() throws Exception { //noinspection unchecked when(queryController.findAsync( any(ParseQuery.State.class), - any(ParseUser.class), + nullable(ParseUser.class), any(Task.class)) ).thenReturn(Task.forResult(Arrays.asList(mock(ParseUser.class), mock(ParseUser.class)))); ParseCorePlugins.getInstance().registerQueryController(queryController); @@ -122,7 +122,7 @@ public void testGetAsyncFromLDSWithTooManyObjects() throws Exception { ParseUser user = ParseTaskUtils.wait(store.getAsync()); //noinspection unchecked verify(queryController, times(1)) - .findAsync(any(ParseQuery.State.class), any(ParseUser.class), any(Task.class)); + .findAsync(any(ParseQuery.State.class), nullable(ParseUser.class), any(Task.class)); verify(lds, times(1)).unpinAllObjectsAsync(PIN_NAME); assertNull(user); } @@ -134,7 +134,7 @@ public void testGetAsyncMigrate() throws Exception { //noinspection unchecked when(queryController.findAsync( any(ParseQuery.State.class), - any(ParseUser.class), + nullable(ParseUser.class), any(Task.class)) ).thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerQueryController(queryController); @@ -159,7 +159,7 @@ public void testGetAsyncMigrate() throws Exception { ParseUser userAgain = ParseTaskUtils.wait(store.getAsync()); //noinspection unchecked verify(queryController, times(1)) - .findAsync(any(ParseQuery.State.class), any(ParseUser.class), any(Task.class)); + .findAsync(any(ParseQuery.State.class), nullable(ParseUser.class), any(Task.class)); verify(legacy, times(1)).getAsync(); verify(legacy, times(1)).deleteAsync(); verify(lds, times(1)).unpinAllObjectsAsync(PIN_NAME); @@ -179,7 +179,7 @@ public void testExistsAsyncLDS() throws Exception { //noinspection unchecked when(queryController.countAsync( any(ParseQuery.State.class), - any(ParseUser.class), + nullable(ParseUser.class), any(Task.class)) ).thenReturn(Task.forResult(1)); ParseCorePlugins.getInstance().registerQueryController(queryController); @@ -189,7 +189,7 @@ public void testExistsAsyncLDS() throws Exception { assertTrue(ParseTaskUtils.wait(store.existsAsync())); //noinspection unchecked verify(queryController, times(1)).countAsync( - any(ParseQuery.State.class), any(ParseUser.class), any(Task.class)); + any(ParseQuery.State.class), nullable(ParseUser.class), any(Task.class)); } @Test @@ -199,7 +199,7 @@ public void testExistsAsyncLegacy() throws Exception { //noinspection unchecked when(queryController.countAsync( any(ParseQuery.State.class), - any(ParseUser.class), + nullable(ParseUser.class), any(Task.class)) ).thenReturn(Task.forResult(0)); ParseCorePlugins.getInstance().registerQueryController(queryController); @@ -214,7 +214,7 @@ public void testExistsAsyncLegacy() throws Exception { assertTrue(ParseTaskUtils.wait(store.existsAsync())); //noinspection unchecked verify(queryController, times(1)).countAsync( - any(ParseQuery.State.class), any(ParseUser.class), any(Task.class)); + any(ParseQuery.State.class), nullable(ParseUser.class), any(Task.class)); } //endregion diff --git a/parse/src/test/java/com/parse/OfflineQueryControllerTest.java b/parse/src/test/java/com/parse/OfflineQueryControllerTest.java index e3172f075..79690c927 100644 --- a/parse/src/test/java/com/parse/OfflineQueryControllerTest.java +++ b/parse/src/test/java/com/parse/OfflineQueryControllerTest.java @@ -8,16 +8,16 @@ */ package com.parse; +import static org.junit.Assert.assertTrue; + +import com.parse.boltsinternal.Task; + import org.junit.After; import org.junit.Test; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertTrue; - public class OfflineQueryControllerTest { @After @@ -99,8 +99,8 @@ public void testGetFromLDS() { private static class TestOfflineStore extends OfflineStore { - private AtomicBoolean findCalled = new AtomicBoolean(); - private AtomicBoolean countCalled = new AtomicBoolean(); + private final AtomicBoolean findCalled = new AtomicBoolean(); + private final AtomicBoolean countCalled = new AtomicBoolean(); TestOfflineStore() { super((OfflineSQLiteOpenHelper) null); @@ -131,8 +131,8 @@ public void verifyCount() { private static class TestNetworkQueryController implements ParseQueryController { - private AtomicBoolean findCalled = new AtomicBoolean(); - private AtomicBoolean countCalled = new AtomicBoolean(); + private final AtomicBoolean findCalled = new AtomicBoolean(); + private final AtomicBoolean countCalled = new AtomicBoolean(); @Override public Task> findAsync( diff --git a/parse/src/test/java/com/parse/OfflineQueryLogicTest.java b/parse/src/test/java/com/parse/OfflineQueryLogicTest.java index 94f775866..930f78131 100644 --- a/parse/src/test/java/com/parse/OfflineQueryLogicTest.java +++ b/parse/src/test/java/com/parse/OfflineQueryLogicTest.java @@ -8,8 +8,23 @@ */ package com.parse; +import static com.parse.ParseMatchers.hasParseErrorCode; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import androidx.annotation.NonNull; +import com.parse.boltsinternal.Task; + import org.json.JSONArray; import org.json.JSONObject; import org.junit.After; @@ -27,27 +42,13 @@ import java.util.Map; import java.util.regex.Pattern; -import com.parse.boltsinternal.Task; - -import static com.parse.ParseMatchers.hasParseErrorCode; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - /** * Unit tests for OfflineQueryLogic. */ public class OfflineQueryLogicTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); private static boolean matches( OfflineQueryLogic logic, ParseQuery.State query, T object) throws ParseException { @@ -1189,7 +1190,7 @@ public void testFetchIncludesJSONObject() throws Exception { @Test public void testFetchIncludesNull() throws ParseException { OfflineStore store = mock(OfflineStore.class); - when(store.fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class))) + when(store.fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class))) .thenReturn(Task.forResult(null)); ParseQuery.State query = new ParseQuery.State.Builder<>("TestObject") @@ -1202,13 +1203,13 @@ public void testFetchIncludesNull() throws ParseException { ParseTaskUtils.wait(OfflineQueryLogic.fetchIncludesAsync(store, object, query, null)); // only itself verify(store, times(1)) - .fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class)); + .fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class)); } @Test public void testFetchIncludesNonParseObject() throws ParseException { OfflineStore store = mock(OfflineStore.class); - when(store.fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class))) + when(store.fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class))) .thenReturn(Task.forResult(null)); ParseQuery.State query = new ParseQuery.State.Builder<>("TestObject") @@ -1222,7 +1223,7 @@ public void testFetchIncludesNonParseObject() throws ParseException { ParseTaskUtils.wait(OfflineQueryLogic.fetchIncludesAsync(store, object, query, null)); // only itself verify(store, times(1)) - .fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class)); + .fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class)); } //endregion @@ -1230,7 +1231,7 @@ public void testFetchIncludesNonParseObject() throws ParseException { @Test public void testFetchIncludesDoesNotExist() throws ParseException { OfflineStore store = mock(OfflineStore.class); - when(store.fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class))) + when(store.fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class))) .thenReturn(Task.forResult(null)); ParseQuery.State query = new ParseQuery.State.Builder<>("TestObject") @@ -1242,13 +1243,13 @@ public void testFetchIncludesDoesNotExist() throws ParseException { ParseTaskUtils.wait(OfflineQueryLogic.fetchIncludesAsync(store, object, query, null)); // only itself verify(store, times(1)) - .fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class)); + .fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class)); } @Test public void testFetchIncludesNestedNull() throws Exception { OfflineStore store = mock(OfflineStore.class); - when(store.fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class))) + when(store.fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class))) .thenReturn(Task.forResult(null)); ParseQuery.State query = new ParseQuery.State.Builder<>("TestObject") @@ -1261,13 +1262,13 @@ public void testFetchIncludesNestedNull() throws Exception { ParseTaskUtils.wait(OfflineQueryLogic.fetchIncludesAsync(store, object, query, null)); // only itself verify(store, times(1)) - .fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class)); + .fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class)); } @Test public void testFetchIncludesNestedNonParseObject() throws Exception { OfflineStore store = mock(OfflineStore.class); - when(store.fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class))) + when(store.fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class))) .thenReturn(Task.forResult(null)); ParseQuery.State query = new ParseQuery.State.Builder<>("TestObject") @@ -1281,6 +1282,6 @@ public void testFetchIncludesNestedNonParseObject() throws Exception { ParseTaskUtils.wait(OfflineQueryLogic.fetchIncludesAsync(store, object, query, null)); // only itself verify(store, times(1)) - .fetchLocallyAsync(any(ParseObject.class), any(ParseSQLiteDatabase.class)); + .fetchLocallyAsync(any(ParseObject.class), nullable(ParseSQLiteDatabase.class)); } } diff --git a/parse/src/test/java/com/parse/ParseACLTest.java b/parse/src/test/java/com/parse/ParseACLTest.java index 8e000c1ee..b7501486e 100644 --- a/parse/src/test/java/com/parse/ParseACLTest.java +++ b/parse/src/test/java/com/parse/ParseACLTest.java @@ -8,20 +8,6 @@ */ package com.parse; -import android.os.Parcel; - -import org.json.JSONObject; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.HashMap; -import java.util.Map; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -35,8 +21,20 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.Parcel; + +import org.json.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.robolectric.RobolectricTestRunner; + +import java.util.HashMap; +import java.util.Map; + @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseACLTest { private final static String UNRESOLVED_KEY = "*unresolved"; @@ -165,10 +163,10 @@ public void testToJson() throws Exception { JSONObject aclJson = acl.toJSONObject(mockEncoder); assertEquals("unresolvedUserJson", aclJson.getString("unresolvedUser")); - assertEquals(aclJson.getJSONObject("userId").getBoolean("read"), true); - assertEquals(aclJson.getJSONObject("userId").has("write"), false); - assertEquals(aclJson.getJSONObject("*unresolved").getBoolean("read"), true); - assertEquals(aclJson.getJSONObject("*unresolved").has("write"), false); + assertTrue(aclJson.getJSONObject("userId").getBoolean("read")); + assertFalse(aclJson.getJSONObject("userId").has("write")); + assertTrue(aclJson.getJSONObject("*unresolved").getBoolean("read")); + assertFalse(aclJson.getJSONObject("*unresolved").has("write")); assertEquals(aclJson.length(), 3); } diff --git a/parse/src/test/java/com/parse/ParseAnalyticsControllerTest.java b/parse/src/test/java/com/parse/ParseAnalyticsControllerTest.java index 428525597..d41a42ed7 100644 --- a/parse/src/test/java/com/parse/ParseAnalyticsControllerTest.java +++ b/parse/src/test/java/com/parse/ParseAnalyticsControllerTest.java @@ -8,6 +8,19 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import org.junit.After; import org.junit.Before; @@ -15,28 +28,14 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Map; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - // For android.net.Uri @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseAnalyticsControllerTest { @Before @@ -66,7 +65,7 @@ public void testConstructor() { public void testTrackEvent() throws Exception { // Mock eventually queue ParseEventuallyQueue queue = mock(ParseEventuallyQueue.class); - when(queue.enqueueEventuallyAsync(any(ParseRESTCommand.class), any(ParseObject.class))) + when(queue.enqueueEventuallyAsync(any(ParseRESTCommand.class), nullable(ParseObject.class))) .thenReturn(Task.forResult(new JSONObject())); // Execute @@ -100,7 +99,7 @@ public void testTrackEvent() throws Exception { public void testTrackAppOpened() throws Exception { // Mock eventually queue ParseEventuallyQueue queue = mock(ParseEventuallyQueue.class); - when(queue.enqueueEventuallyAsync(any(ParseRESTCommand.class), any(ParseObject.class))) + when(queue.enqueueEventuallyAsync(any(ParseRESTCommand.class), nullable(ParseObject.class))) .thenReturn(Task.forResult(new JSONObject())); // Execute diff --git a/parse/src/test/java/com/parse/ParseAnalyticsTest.java b/parse/src/test/java/com/parse/ParseAnalyticsTest.java index bbebcb999..0dd660784 100644 --- a/parse/src/test/java/com/parse/ParseAnalyticsTest.java +++ b/parse/src/test/java/com/parse/ParseAnalyticsTest.java @@ -8,9 +8,26 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNull; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.annotation.LooperMode.Mode.PAUSED; +import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; + import android.content.Intent; import android.os.Bundle; +import com.parse.boltsinternal.Task; + import org.json.JSONException; import org.json.JSONObject; import org.junit.After; @@ -19,31 +36,16 @@ import org.junit.runner.RunWith; import org.mockito.Matchers; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.isNull; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - // For android.os.BaseBundle @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) +@LooperMode(PAUSED) public class ParseAnalyticsTest { ParseAnalyticsController controller; @@ -143,28 +145,26 @@ public void testTrackEventInBackgroundNormalCallback() throws Exception { dimensions.put("key", "value"); final Semaphore done = new Semaphore(0); ParseAnalytics.trackEventInBackground("test", dimensions, - new SaveCallback() { - @Override - public void done(ParseException e) { - assertNull(e); - done.release(); - } + e -> { + assertNull(e); + done.release(); }); + shadowMainLooper().idle(); + // Make sure the callback is called assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).trackEventInBackground( eq("test"), eq(dimensions), isNull(String.class)); final Semaphore doneAgain = new Semaphore(0); - ParseAnalytics.trackEventInBackground("test", new SaveCallback() { - @Override - public void done(ParseException e) { - assertNull(e); - doneAgain.release(); - } + ParseAnalytics.trackEventInBackground("test", e -> { + assertNull(e); + doneAgain.release(); }); + shadowMainLooper().idle(); + // Make sure the callback is called assertTrue(doneAgain.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).trackEventInBackground @@ -224,14 +224,13 @@ public void testTrackAppOpenedInBackgroundNullCallback() throws Exception { public void testTrackAppOpenedInBackgroundNormalCallback() throws Exception { Intent intent = makeIntentWithParseData("test"); final Semaphore done = new Semaphore(0); - ParseAnalytics.trackAppOpenedInBackground(intent, new SaveCallback() { - @Override - public void done(ParseException e) { - assertNull(e); - done.release(); - } + ParseAnalytics.trackAppOpenedInBackground(intent, e -> { + assertNull(e); + done.release(); }); + shadowMainLooper().idle(); + // Make sure the callback is called assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).trackAppOpenedInBackground(eq("test"), isNull(String.class)); @@ -245,7 +244,7 @@ public void done(ParseException e) { public void testGetPushHashFromIntentNullIntent() { String pushHash = ParseAnalytics.getPushHashFromIntent(null); - assertEquals(null, pushHash); + assertNull(pushHash); } @Test @@ -259,7 +258,7 @@ public void testGetPushHashFromIntentEmptyIntent() throws Exception { String pushHash = ParseAnalytics.getPushHashFromIntent(intent); - assertEquals(null, pushHash); + assertNull(pushHash); } @Test @@ -285,7 +284,7 @@ public void testGetPushHashFromIntentWrongPushHashIntent() { String pushHash = ParseAnalytics.getPushHashFromIntent(intent); - assertEquals(null, pushHash); + assertNull(pushHash); } @Test diff --git a/parse/src/test/java/com/parse/ParseAuthenticationManagerTest.java b/parse/src/test/java/com/parse/ParseAuthenticationManagerTest.java index b5daa700b..65c1b5528 100644 --- a/parse/src/test/java/com/parse/ParseAuthenticationManagerTest.java +++ b/parse/src/test/java/com/parse/ParseAuthenticationManagerTest.java @@ -8,6 +8,13 @@ */ package com.parse; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; + import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -17,17 +24,10 @@ import java.util.HashMap; import java.util.Map; -import com.parse.boltsinternal.Task; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - public class ParseAuthenticationManagerTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); private ParseAuthenticationManager manager; private ParseCurrentUserController controller; diff --git a/parse/src/test/java/com/parse/ParseByteArrayHttpBodyTest.java b/parse/src/test/java/com/parse/ParseByteArrayHttpBodyTest.java index d8db33678..d47704e46 100644 --- a/parse/src/test/java/com/parse/ParseByteArrayHttpBodyTest.java +++ b/parse/src/test/java/com/parse/ParseByteArrayHttpBodyTest.java @@ -8,14 +8,14 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + import org.junit.Test; import java.io.ByteArrayOutputStream; import java.io.IOException; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - public class ParseByteArrayHttpBodyTest { @Test diff --git a/parse/src/test/java/com/parse/ParseClientConfigurationTest.java b/parse/src/test/java/com/parse/ParseClientConfigurationTest.java index 6d8d96fbd..d429bb7c3 100644 --- a/parse/src/test/java/com/parse/ParseClientConfigurationTest.java +++ b/parse/src/test/java/com/parse/ParseClientConfigurationTest.java @@ -8,16 +8,15 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseClientConfigurationTest { @Test @@ -31,7 +30,7 @@ public void testBuilder() { assertNull(configuration.context); assertEquals(configuration.applicationId, "foo"); assertEquals(configuration.clientKey, "bar"); - assertEquals(configuration.localDataStoreEnabled, true); + assertTrue(configuration.localDataStoreEnabled); } @Test diff --git a/parse/src/test/java/com/parse/ParseCloudCodeControllerTest.java b/parse/src/test/java/com/parse/ParseCloudCodeControllerTest.java index 177ab4ae9..0f0c187b3 100644 --- a/parse/src/test/java/com/parse/ParseCloudCodeControllerTest.java +++ b/parse/src/test/java/com/parse/ParseCloudCodeControllerTest.java @@ -8,6 +8,19 @@ */ package com.parse; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -24,20 +37,6 @@ import java.util.HashMap; import java.util.List; -import com.parse.boltsinternal.Task; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class ParseCloudCodeControllerTest { @Before @@ -131,7 +130,7 @@ public void testCallFunctionInBackgroundSuccessWithResult() throws Exception { ParseCloudCodeController controller = new ParseCloudCodeController(restClient); Task cloudCodeTask = controller.callFunctionInBackground( - "test", new HashMap(), "sessionToken"); + "test", new HashMap<>(), "sessionToken"); ParseTaskUtils.wait(cloudCodeTask); verify(restClient, times(1)).execute(any(ParseHttpRequest.class)); @@ -153,7 +152,7 @@ public void testCallFunctionInBackgroundSuccessWithoutResult() throws Exception ParseCloudCodeController controller = new ParseCloudCodeController(restClient); Task cloudCodeTask = controller.callFunctionInBackground( - "test", new HashMap(), "sessionToken"); + "test", new HashMap<>(), "sessionToken"); ParseTaskUtils.wait(cloudCodeTask); verify(restClient, times(1)).execute(any(ParseHttpRequest.class)); @@ -171,7 +170,7 @@ public void testCallFunctionInBackgroundFailure() throws Exception { ParseCloudCodeController controller = new ParseCloudCodeController(restClient); Task cloudCodeTask = - controller.callFunctionInBackground("test", new HashMap(), "sessionToken"); + controller.callFunctionInBackground("test", new HashMap<>(), "sessionToken"); // Do not use ParseTaskUtils.wait() since we do not want to throw the exception cloudCodeTask.waitForCompletion(); @@ -199,12 +198,12 @@ public void testCallFunctionWithNullResult() throws Exception { ParseCloudCodeController controller = new ParseCloudCodeController(restClient); Task cloudCodeTask = controller.callFunctionInBackground( - "test", new HashMap(), "sessionToken"); + "test", new HashMap<>(), "sessionToken"); ParseTaskUtils.wait(cloudCodeTask); verify(restClient, times(1)).execute(any(ParseHttpRequest.class)); String result = cloudCodeTask.getResult(); - assertEquals(null, result); + assertNull(result); } private ParseHttpClient mockParseHttpClientWithReponse(ParseHttpResponse response) diff --git a/parse/src/test/java/com/parse/ParseCloudTest.java b/parse/src/test/java/com/parse/ParseCloudTest.java index e5e70700a..2aa236829 100644 --- a/parse/src/test/java/com/parse/ParseCloudTest.java +++ b/parse/src/test/java/com/parse/ParseCloudTest.java @@ -8,26 +8,13 @@ */ package com.parse; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; - -import com.parse.boltsinternal.Task; - +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.anyMap; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -36,10 +23,26 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.robolectric.annotation.LooperMode.Mode.PAUSED; +import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; + +import com.parse.boltsinternal.Task; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.LooperMode; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; // For android.os.Looper @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) +@LooperMode(PAUSED) public class ParseCloudTest extends ResetPluginsParseTest { @Before @@ -74,7 +77,7 @@ public void testCallFunctionAsync() throws Exception { ParseTaskUtils.wait(cloudCodeTask); verify(controller, times(1)).callFunctionInBackground(eq("name"), eq(parameters), - isNull(String.class)); + isNull()); assertTrue(cloudCodeTask.isCompleted()); assertNull(cloudCodeTask.getError()); assertThat(cloudCodeTask.getResult(), instanceOf(String.class)); @@ -92,7 +95,7 @@ public void testCallFunctionSync() throws Exception { Object result = ParseCloud.callFunction("name", parameters); verify(controller, times(1)).callFunctionInBackground(eq("name"), eq(parameters), - isNull(String.class)); + isNull()); assertThat(result, instanceOf(String.class)); assertEquals("result", result); } @@ -108,7 +111,7 @@ public void testCallFunctionNullCallback() { ParseCloud.callFunctionInBackground("name", parameters, null); verify(controller, times(1)).callFunctionInBackground(eq("name"), eq(parameters), - isNull(String.class)); + isNull()); } @Test @@ -120,27 +123,26 @@ public void testCallFunctionNormalCallback() throws Exception { parameters.put("key2", "value1"); final Semaphore done = new Semaphore(0); - ParseCloud.callFunctionInBackground("name", parameters, new FunctionCallback() { - @Override - public void done(Object result, ParseException e) { - assertNull(e); - assertThat(result, instanceOf(String.class)); - assertEquals("result", result); - done.release(); - } + ParseCloud.callFunctionInBackground("name", parameters, (result, e) -> { + assertNull(e); + assertThat(result, instanceOf(String.class)); + assertEquals("result", result); + done.release(); }); + shadowMainLooper().idle(); + // Make sure the callback is called assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).callFunctionInBackground(eq("name"), eq(parameters), - isNull(String.class)); + isNull()); } //endregion private ParseCloudCodeController mockParseCloudCodeControllerWithResponse(final T result) { ParseCloudCodeController controller = mock(ParseCloudCodeController.class); - when(controller.callFunctionInBackground(anyString(), anyMap(), anyString())) + when(controller.callFunctionInBackground(anyString(), anyMap(), nullable(String.class))) .thenReturn(Task.forResult(result)); return controller; } diff --git a/parse/src/test/java/com/parse/ParseCoderTest.java b/parse/src/test/java/com/parse/ParseCoderTest.java index 967e55aa7..502725444 100644 --- a/parse/src/test/java/com/parse/ParseCoderTest.java +++ b/parse/src/test/java/com/parse/ParseCoderTest.java @@ -8,17 +8,15 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; + import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static org.junit.Assert.assertEquals; // For android.util.Base64 @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseCoderTest { @Test diff --git a/parse/src/test/java/com/parse/ParseConfigControllerTest.java b/parse/src/test/java/com/parse/ParseConfigControllerTest.java index 4525d897b..6dc65b975 100644 --- a/parse/src/test/java/com/parse/ParseConfigControllerTest.java +++ b/parse/src/test/java/com/parse/ParseConfigControllerTest.java @@ -8,6 +8,21 @@ */ package com.parse; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -28,22 +43,6 @@ import java.util.List; import java.util.Map; -import com.parse.boltsinternal.Task; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class ParseConfigControllerTest { @Rule diff --git a/parse/src/test/java/com/parse/ParseConfigTest.java b/parse/src/test/java/com/parse/ParseConfigTest.java index a6dbc4920..f78543c1a 100644 --- a/parse/src/test/java/com/parse/ParseConfigTest.java +++ b/parse/src/test/java/com/parse/ParseConfigTest.java @@ -8,13 +8,33 @@ */ package com.parse; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.annotation.LooperMode.Mode.PAUSED; +import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + +import com.parse.boltsinternal.Task; + import org.json.JSONArray; import org.json.JSONObject; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import org.skyscreamer.jsonassert.JSONCompareMode; import java.util.ArrayList; @@ -25,28 +45,10 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import com.parse.boltsinternal.Task; - -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - // For android.os.Looper @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) +@LooperMode(PAUSED) public class ParseConfigTest extends ResetPluginsParseTest { @Before @@ -103,7 +105,7 @@ public void testGetInBackgroundSuccess() throws Exception { ParseTaskUtils.wait(configTask); ParseConfig configAgain = configTask.getResult(); - verify(controller, times(1)).getAsync(anyString()); + verify(controller, times(1)).getAsync(nullable(String.class)); assertEquals(1, configAgain.params.size()); assertEquals("value", configAgain.params.get("string")); } @@ -118,7 +120,7 @@ public void testGetInBackgroundFail() throws Exception { Task configTask = ParseConfig.getInBackground(); configTask.waitForCompletion(); - verify(controller, times(1)).getAsync(anyString()); + verify(controller, times(1)).getAsync(nullable(String.class)); assertThat(configTask.getError(), instanceOf(ParseException.class)); assertEquals(ParseException.CONNECTION_FAILED, ((ParseException) configTask.getError()).getCode()); @@ -135,18 +137,17 @@ public void testGetInBackgroundWithCallbackSuccess() throws Exception { ParseCorePlugins.getInstance().registerConfigController(controller); final Semaphore done = new Semaphore(0); - ParseConfig.getInBackground(new ConfigCallback() { - @Override - public void done(ParseConfig config, ParseException e) { - assertEquals(1, config.params.size()); - assertEquals("value", config.params.get("string")); - done.release(); - } + ParseConfig.getInBackground((config1, e) -> { + assertEquals(1, config1.params.size()); + assertEquals("value", config1.params.get("string")); + done.release(); }); + shadowMainLooper().idle(); + // Make sure the callback is called assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); - verify(controller, times(1)).getAsync(anyString()); + verify(controller, times(1)).getAsync(nullable(String.class)); } @Test @@ -156,18 +157,17 @@ public void testGetInBackgroundWithCallbackFail() throws Exception { ParseCorePlugins.getInstance().registerConfigController(controller); final Semaphore done = new Semaphore(0); - ParseConfig.getInBackground(new ConfigCallback() { - @Override - public void done(ParseConfig config, ParseException e) { - assertEquals(ParseException.CONNECTION_FAILED, e.getCode()); - assertEquals("error", e.getMessage()); - done.release(); - } + ParseConfig.getInBackground((config, e) -> { + assertEquals(ParseException.CONNECTION_FAILED, e.getCode()); + assertEquals("error", e.getMessage()); + done.release(); }); + shadowMainLooper().idle(); + // Make sure the callback is called assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); - verify(controller, times(1)).getAsync(anyString()); + verify(controller, times(1)).getAsync(nullable(String.class)); } @Test @@ -181,7 +181,7 @@ public void testGetSyncSuccess() throws Exception { ParseConfig configAgain = ParseConfig.get(); - verify(controller, times(1)).getAsync(anyString()); + verify(controller, times(1)).getAsync(nullable(String.class)); assertEquals(1, configAgain.params.size()); assertEquals("value", configAgain.params.get("string")); } @@ -196,7 +196,7 @@ public void testGetSyncFail() { ParseConfig.get(); fail("Should throw an exception"); } catch (ParseException e) { - verify(controller, times(1)).getAsync(anyString()); + verify(controller, times(1)).getAsync(nullable(String.class)); assertEquals(ParseException.CONNECTION_FAILED, e.getCode()); assertEquals("error", e.getMessage()); } @@ -1007,14 +1007,14 @@ public void testToStringParseGeoPoint() { private ParseConfigController mockParseConfigControllerWithResponse(final ParseConfig result) { ParseConfigController controller = mock(ParseConfigController.class); - when(controller.getAsync(anyString())) + when(controller.getAsync(nullable(String.class))) .thenReturn(Task.forResult(result)); return controller; } private ParseConfigController mockParseConfigControllerWithException(Exception exception) { ParseConfigController controller = mock(ParseConfigController.class); - when(controller.getAsync(anyString())) + when(controller.getAsync(nullable(String.class))) .thenReturn(Task.forError(exception)); return controller; } diff --git a/parse/src/test/java/com/parse/ParseCorePluginsTest.java b/parse/src/test/java/com/parse/ParseCorePluginsTest.java index 4694dfa82..9b7771d47 100644 --- a/parse/src/test/java/com/parse/ParseCorePluginsTest.java +++ b/parse/src/test/java/com/parse/ParseCorePluginsTest.java @@ -8,22 +8,20 @@ */ package com.parse; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; + +import com.parse.boltsinternal.Task; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.util.List; -import com.parse.boltsinternal.Task; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseCorePluginsTest extends ResetPluginsParseTest { @Before diff --git a/parse/src/test/java/com/parse/ParseCountingByteArrayHttpBodyTest.java b/parse/src/test/java/com/parse/ParseCountingByteArrayHttpBodyTest.java index 008d05407..c2118482b 100644 --- a/parse/src/test/java/com/parse/ParseCountingByteArrayHttpBodyTest.java +++ b/parse/src/test/java/com/parse/ParseCountingByteArrayHttpBodyTest.java @@ -8,6 +8,10 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import org.junit.Test; import java.io.ByteArrayOutputStream; @@ -16,9 +20,6 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - public class ParseCountingByteArrayHttpBodyTest { private static byte[] getData() { @@ -62,7 +63,7 @@ public void done(Integer percentDone) { body.writeTo(output); // Check content - assertTrue(Arrays.equals(content, output.toByteArray())); + assertArrayEquals(content, output.toByteArray()); // Check progress callback assertTrue(didReportIntermediateProgress.tryAcquire(5, TimeUnit.SECONDS)); diff --git a/parse/src/test/java/com/parse/ParseCountingFileHttpBodyTest.java b/parse/src/test/java/com/parse/ParseCountingFileHttpBodyTest.java index 3e9bb6bc9..0aa56cedf 100644 --- a/parse/src/test/java/com/parse/ParseCountingFileHttpBodyTest.java +++ b/parse/src/test/java/com/parse/ParseCountingFileHttpBodyTest.java @@ -8,6 +8,10 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -20,14 +24,10 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - public class ParseCountingFileHttpBodyTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); private static String getData() { char[] chars = new char[64 << 14]; // 1MB diff --git a/parse/src/test/java/com/parse/ParseCurrentConfigControllerTest.java b/parse/src/test/java/com/parse/ParseCurrentConfigControllerTest.java index c66b75c46..5b9f0ad3e 100644 --- a/parse/src/test/java/com/parse/ParseCurrentConfigControllerTest.java +++ b/parse/src/test/java/com/parse/ParseCurrentConfigControllerTest.java @@ -8,6 +8,16 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import org.junit.Rule; import org.junit.Test; @@ -20,20 +30,10 @@ import java.util.List; import java.util.Map; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - public class ParseCurrentConfigControllerTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); //region testConstructor diff --git a/parse/src/test/java/com/parse/ParseDateFormatTest.java b/parse/src/test/java/com/parse/ParseDateFormatTest.java index 45fe2033b..d43fad07f 100644 --- a/parse/src/test/java/com/parse/ParseDateFormatTest.java +++ b/parse/src/test/java/com/parse/ParseDateFormatTest.java @@ -8,13 +8,13 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import org.junit.Test; import java.util.Date; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - public class ParseDateFormatTest { @Test public void testParse() { diff --git a/parse/src/test/java/com/parse/ParseDecoderTest.java b/parse/src/test/java/com/parse/ParseDecoderTest.java index 056186083..e5b2ce4f6 100644 --- a/parse/src/test/java/com/parse/ParseDecoderTest.java +++ b/parse/src/test/java/com/parse/ParseDecoderTest.java @@ -8,6 +8,13 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -16,27 +23,18 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - // For android.util.Base64 @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseDecoderTest extends ResetPluginsParseTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); @Test public void testJSONArray() { diff --git a/parse/src/test/java/com/parse/ParseDefaultACLControllerTest.java b/parse/src/test/java/com/parse/ParseDefaultACLControllerTest.java index 8289968e0..aaa02e8fc 100644 --- a/parse/src/test/java/com/parse/ParseDefaultACLControllerTest.java +++ b/parse/src/test/java/com/parse/ParseDefaultACLControllerTest.java @@ -8,14 +8,6 @@ */ package com.parse; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.lang.ref.WeakReference; - -import com.parse.boltsinternal.Task; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; @@ -28,6 +20,14 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.parse.boltsinternal.Task; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.lang.ref.WeakReference; + public class ParseDefaultACLControllerTest { @Before diff --git a/parse/src/test/java/com/parse/ParseDigestUtilsTest.java b/parse/src/test/java/com/parse/ParseDigestUtilsTest.java index 9fc9ed491..a837a3ad4 100644 --- a/parse/src/test/java/com/parse/ParseDigestUtilsTest.java +++ b/parse/src/test/java/com/parse/ParseDigestUtilsTest.java @@ -8,13 +8,13 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; + import org.junit.Test; import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; - public class ParseDigestUtilsTest { @Test diff --git a/parse/src/test/java/com/parse/ParseEncoderTest.java b/parse/src/test/java/com/parse/ParseEncoderTest.java index 5d09f4667..e0962ee8f 100644 --- a/parse/src/test/java/com/parse/ParseEncoderTest.java +++ b/parse/src/test/java/com/parse/ParseEncoderTest.java @@ -8,6 +8,10 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -17,24 +21,18 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - // For android.util.Base64 @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseEncoderTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); ParseEncoderTestClass testClassObject = null; @Before diff --git a/parse/src/test/java/com/parse/ParseFileControllerTest.java b/parse/src/test/java/com/parse/ParseFileControllerTest.java index b31f7e45a..a11e902ee 100644 --- a/parse/src/test/java/com/parse/ParseFileControllerTest.java +++ b/parse/src/test/java/com/parse/ParseFileControllerTest.java @@ -8,6 +8,19 @@ */ package com.parse; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -19,7 +32,6 @@ import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.io.ByteArrayInputStream; import java.io.File; @@ -27,27 +39,12 @@ import java.net.MalformedURLException; import java.net.URL; -import com.parse.boltsinternal.Task; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - // For org.json @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseFileControllerTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before public void setUp() throws MalformedURLException { diff --git a/parse/src/test/java/com/parse/ParseFileHttpBodyTest.java b/parse/src/test/java/com/parse/ParseFileHttpBodyTest.java index a69066858..73d64802d 100644 --- a/parse/src/test/java/com/parse/ParseFileHttpBodyTest.java +++ b/parse/src/test/java/com/parse/ParseFileHttpBodyTest.java @@ -8,6 +8,10 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -18,14 +22,10 @@ import java.io.IOException; import java.io.InputStream; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - public class ParseFileHttpBodyTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); // Generate a test file used for create ParseFileHttpBody, if you change file's content, make sure // you also change the test file content in verifyTestFileContent(). diff --git a/parse/src/test/java/com/parse/ParseFileRequestTest.java b/parse/src/test/java/com/parse/ParseFileRequestTest.java index 621a71149..78be4349b 100644 --- a/parse/src/test/java/com/parse/ParseFileRequestTest.java +++ b/parse/src/test/java/com/parse/ParseFileRequestTest.java @@ -8,6 +8,11 @@ */ package com.parse; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -16,12 +21,6 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; -import com.parse.boltsinternal.Task; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - public class ParseFileRequestTest extends TestCase { @Override diff --git a/parse/src/test/java/com/parse/ParseFileStateTest.java b/parse/src/test/java/com/parse/ParseFileStateTest.java index fd1c56ba8..eed22bf0c 100644 --- a/parse/src/test/java/com/parse/ParseFileStateTest.java +++ b/parse/src/test/java/com/parse/ParseFileStateTest.java @@ -8,6 +8,11 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.robolectric.Shadows.shadowOf; + import android.webkit.MimeTypeMap; import org.junit.After; @@ -15,16 +20,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.robolectric.Shadows.shadowOf; // For android.webkit.MimeTypeMap @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseFileStateTest { @Before @@ -41,7 +39,7 @@ public void tearDown() { public void testDefaults() { ParseFile.State state = new ParseFile.State.Builder().build(); assertEquals("file", state.name()); - assertEquals(null, state.mimeType()); + assertNull(state.mimeType()); assertNull(state.url()); } @@ -84,6 +82,6 @@ public void testMimeTypeNotSetFromExtension() { ParseFile.State state = new ParseFile.State.Builder() .name("test.txt") .build(); - assertEquals(null, state.mimeType()); + assertNull(state.mimeType()); } } diff --git a/parse/src/test/java/com/parse/ParseFileTest.java b/parse/src/test/java/com/parse/ParseFileTest.java index 61ef9bc21..1944f4d46 100644 --- a/parse/src/test/java/com/parse/ParseFileTest.java +++ b/parse/src/test/java/com/parse/ParseFileTest.java @@ -8,8 +8,23 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.os.Parcel; +import com.parse.boltsinternal.Task; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -19,34 +34,17 @@ import org.mockito.ArgumentCaptor; import org.mockito.Matchers; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.io.File; import java.io.InputStream; import java.util.Arrays; import java.util.List; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseFileTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Before public void setup() { @@ -76,12 +74,12 @@ public void testConstructor() throws Exception { parseFile = new ParseFile(data); assertEquals("file", parseFile.getName()); // Default - assertEquals(null, parseFile.getState().mimeType()); + assertNull(parseFile.getState().mimeType()); assertTrue(parseFile.isDirty()); parseFile = new ParseFile(name, data); assertEquals("name", parseFile.getName()); - assertEquals(null, parseFile.getState().mimeType()); + assertNull(parseFile.getState().mimeType()); assertTrue(parseFile.isDirty()); parseFile = new ParseFile(data, contentType); @@ -91,7 +89,7 @@ public void testConstructor() throws Exception { parseFile = new ParseFile(file); assertEquals(name, parseFile.getName()); // Default - assertEquals(null, parseFile.getState().mimeType()); + assertNull(parseFile.getState().mimeType()); assertTrue(parseFile.isDirty()); parseFile = new ParseFile(file, contentType); @@ -187,9 +185,9 @@ public void testSaveAsyncSuccessWithData() throws Exception { when(controller.saveAsync( any(ParseFile.State.class), any(byte[].class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(state)); + nullable(String.class), + nullable(ProgressCallback.class), + nullable(Task.class))).thenReturn(Task.forResult(state)); ParseCorePlugins.getInstance().registerFileController(controller); ParseFile parseFile = new ParseFile(name, data, contentType); @@ -201,9 +199,9 @@ public void testSaveAsyncSuccessWithData() throws Exception { verify(controller, times(1)).saveAsync( stateCaptor.capture(), dataCaptor.capture(), - any(String.class), - any(ProgressCallback.class), - Matchers.>any()); + nullable(String.class), + nullable(ProgressCallback.class), + nullable(Task.class)); assertNull(stateCaptor.getValue().url()); assertEquals(name, stateCaptor.getValue().name()); assertEquals(contentType, stateCaptor.getValue().mimeType()); @@ -225,9 +223,9 @@ public void testSaveAsyncSuccessWithFile() throws Exception { when(controller.saveAsync( any(ParseFile.State.class), any(File.class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(state)); + nullable(String.class), + nullable(ProgressCallback.class), + nullable(Task.class))).thenReturn(Task.forResult(state)); ParseCorePlugins.getInstance().registerFileController(controller); ParseFile parseFile = new ParseFile(file, contentType); @@ -239,9 +237,9 @@ public void testSaveAsyncSuccessWithFile() throws Exception { verify(controller, times(1)).saveAsync( stateCaptor.capture(), fileCaptor.capture(), - any(String.class), - any(ProgressCallback.class), - Matchers.>any()); + nullable(String.class), + nullable(ProgressCallback.class), + nullable(Task.class)); assertNull(stateCaptor.getValue().url()); assertEquals(name, stateCaptor.getValue().name()); assertEquals(contentType, stateCaptor.getValue().mimeType()); @@ -267,9 +265,9 @@ public void testGetDataAsyncSuccess() throws Exception { ParseFileController controller = mock(ParseFileController.class); when(controller.fetchAsync( any(ParseFile.State.class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(file)); + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class))).thenReturn(Task.forResult(file)); ParseCorePlugins.getInstance().registerFileController(controller); String url = "url"; @@ -284,9 +282,9 @@ public void testGetDataAsyncSuccess() throws Exception { ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParseFile.State.class); verify(controller, times(1)).fetchAsync( stateCaptor.capture(), - anyString(), - any(ProgressCallback.class), - Matchers.>any() + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class) ); assertEquals(url, stateCaptor.getValue().url()); // Verify the data we get is correct @@ -300,9 +298,9 @@ public void testGetDataAsyncSuccess() throws Exception { ArgumentCaptor.forClass(ParseFile.State.class); verify(controller, times(2)).fetchAsync( stateCaptorAgain.capture(), - anyString(), - any(ProgressCallback.class), - Matchers.>any() + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class) ); assertEquals(url, stateCaptorAgain.getValue().url()); // Verify the data we get is correct @@ -317,9 +315,9 @@ public void testGetDataStreamAsyncSuccess() throws Exception { ParseFileController controller = mock(ParseFileController.class); when(controller.fetchAsync( any(ParseFile.State.class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(file)); + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class))).thenReturn(Task.forResult(file)); ParseCorePlugins.getInstance().registerFileController(controller); String url = "url"; @@ -334,9 +332,9 @@ public void testGetDataStreamAsyncSuccess() throws Exception { ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParseFile.State.class); verify(controller, times(1)).fetchAsync( stateCaptor.capture(), - anyString(), - any(ProgressCallback.class), - Matchers.>any() + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class) ); assertEquals(url, stateCaptor.getValue().url()); // Verify the data we get is correct @@ -350,9 +348,9 @@ public void testGetDataStreamAsyncSuccess() throws Exception { ArgumentCaptor.forClass(ParseFile.State.class); verify(controller, times(2)).fetchAsync( stateCaptorAgain.capture(), - anyString(), - any(ProgressCallback.class), - Matchers.>any() + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class) ); assertEquals(url, stateCaptorAgain.getValue().url()); // Verify the data we get is correct @@ -367,9 +365,9 @@ public void testGetFileAsyncSuccess() throws Exception { ParseFileController controller = mock(ParseFileController.class); when(controller.fetchAsync( any(ParseFile.State.class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(file)); + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class))).thenReturn(Task.forResult(file)); ParseCorePlugins.getInstance().registerFileController(controller); String url = "url"; @@ -384,9 +382,9 @@ public void testGetFileAsyncSuccess() throws Exception { ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParseFile.State.class); verify(controller, times(1)).fetchAsync( stateCaptor.capture(), - anyString(), - any(ProgressCallback.class), - Matchers.>any() + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class) ); assertEquals(url, stateCaptor.getValue().url()); // Verify the data we get is correct @@ -400,9 +398,9 @@ public void testGetFileAsyncSuccess() throws Exception { ArgumentCaptor.forClass(ParseFile.State.class); verify(controller, times(2)).fetchAsync( stateCaptorAgain.capture(), - anyString(), - any(ProgressCallback.class), - Matchers.>any() + nullable(String.class), + nullable(ProgressCallback.class), + any(Task.class) ); assertEquals(url, stateCaptorAgain.getValue().url()); // Verify the data we get is correct @@ -420,20 +418,20 @@ public void testTaskQueuedMethods() throws Exception { when(controller.saveAsync( any(ParseFile.State.class), any(byte[].class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(state)); + nullable(String.class), + nullable(ProgressCallback.class), + nullable(Task.class))).thenReturn(Task.forResult(state)); when(controller.saveAsync( any(ParseFile.State.class), - any(File.class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(state)); + nullable(File.class), + nullable(String.class), + nullable(ProgressCallback.class), + nullable(Task.class))).thenReturn(Task.forResult(state)); when(controller.fetchAsync( any(ParseFile.State.class), - any(String.class), - any(ProgressCallback.class), - Matchers.>any())).thenReturn(Task.forResult(cachedFile)); + nullable(String.class), + nullable(ProgressCallback.class), + nullable(Task.class))).thenReturn(Task.forResult(cachedFile)); ParseCorePlugins.getInstance().registerFileController(controller); diff --git a/parse/src/test/java/com/parse/ParseFileUtilsTest.java b/parse/src/test/java/com/parse/ParseFileUtilsTest.java index 684f6c3fe..443e0a177 100644 --- a/parse/src/test/java/com/parse/ParseFileUtilsTest.java +++ b/parse/src/test/java/com/parse/ParseFileUtilsTest.java @@ -8,13 +8,15 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + import org.json.JSONObject; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; @@ -23,18 +25,14 @@ import java.io.FileOutputStream; import java.io.InputStream; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseFileUtilsTest { private static final String TEST_STRING = "this is a test string"; private static final String TEST_JSON = "{ \"foo\": \"bar\" }"; @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Test public void testReadFileToString() throws Exception { @@ -42,7 +40,7 @@ public void testReadFileToString() throws Exception { BufferedOutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(file)); - out.write(TEST_STRING.getBytes("UTF-8")); + out.write(TEST_STRING.getBytes()); } finally { ParseIOUtils.closeQuietly(out); } @@ -61,7 +59,7 @@ public void testWriteStringToFile() throws Exception { in = new FileInputStream(file); ByteArrayOutputStream out = new ByteArrayOutputStream(); ParseIOUtils.copy(in, out); - content = new String(out.toByteArray(), "UTF-8"); + content = out.toString(); } finally { ParseIOUtils.closeQuietly(in); } @@ -75,7 +73,7 @@ public void testReadFileToJSONObject() throws Exception { BufferedOutputStream out = null; try { out = new BufferedOutputStream(new FileOutputStream(file)); - out.write(TEST_JSON.getBytes("UTF-8")); + out.write(TEST_JSON.getBytes()); } finally { ParseIOUtils.closeQuietly(out); } diff --git a/parse/src/test/java/com/parse/ParseGeoPointTest.java b/parse/src/test/java/com/parse/ParseGeoPointTest.java index 3aacb7c44..b708e3737 100644 --- a/parse/src/test/java/com/parse/ParseGeoPointTest.java +++ b/parse/src/test/java/com/parse/ParseGeoPointTest.java @@ -8,19 +8,16 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + import android.os.Parcel; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseGeoPointTest { @Test @@ -46,13 +43,13 @@ public void testEquals() { ParseGeoPoint pointB = new ParseGeoPoint(30d, 50d); ParseGeoPoint pointC = new ParseGeoPoint(45d, 45d); - assertTrue(pointA.equals(pointB)); - assertTrue(pointA.equals(pointA)); - assertTrue(pointB.equals(pointA)); + assertEquals(pointA, pointB); + assertEquals(pointA, pointA); + assertEquals(pointB, pointA); - assertFalse(pointA.equals(null)); - assertFalse(pointA.equals(true)); - assertFalse(pointA.equals(pointC)); + assertNotEquals(null, pointA); + assertNotEquals(true, pointA); + assertNotEquals(pointA, pointC); } @Test diff --git a/parse/src/test/java/com/parse/ParseHttpClientTest.java b/parse/src/test/java/com/parse/ParseHttpClientTest.java index 94982a2ed..ab326bb1b 100644 --- a/parse/src/test/java/com/parse/ParseHttpClientTest.java +++ b/parse/src/test/java/com/parse/ParseHttpClientTest.java @@ -8,6 +8,12 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -15,7 +21,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.io.ByteArrayOutputStream; import java.util.HashMap; @@ -30,14 +35,7 @@ import okhttp3.mockwebserver.RecordedRequest; import okio.Buffer; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseHttpClientTest { // We can not use ParameterizedRobolectricTestRunner right now since Robolectric use diff --git a/parse/src/test/java/com/parse/ParseHttpRequestTest.java b/parse/src/test/java/com/parse/ParseHttpRequestTest.java index 05b5a8315..1195be00c 100644 --- a/parse/src/test/java/com/parse/ParseHttpRequestTest.java +++ b/parse/src/test/java/com/parse/ParseHttpRequestTest.java @@ -8,6 +8,9 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + import com.parse.http.ParseHttpBody; import com.parse.http.ParseHttpRequest; @@ -17,9 +20,6 @@ import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; - public class ParseHttpRequestTest { @Test diff --git a/parse/src/test/java/com/parse/ParseHttpResponseTest.java b/parse/src/test/java/com/parse/ParseHttpResponseTest.java index 469562042..f325e3414 100644 --- a/parse/src/test/java/com/parse/ParseHttpResponseTest.java +++ b/parse/src/test/java/com/parse/ParseHttpResponseTest.java @@ -8,6 +8,11 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + import com.parse.http.ParseHttpResponse; import org.junit.Test; @@ -17,11 +22,6 @@ import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; - public class ParseHttpResponseTest { @Test diff --git a/parse/src/test/java/com/parse/ParseImpreciseDateFormatTest.java b/parse/src/test/java/com/parse/ParseImpreciseDateFormatTest.java index a9ddd3b09..89e146957 100644 --- a/parse/src/test/java/com/parse/ParseImpreciseDateFormatTest.java +++ b/parse/src/test/java/com/parse/ParseImpreciseDateFormatTest.java @@ -8,13 +8,13 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import org.junit.Test; import java.util.Date; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - public class ParseImpreciseDateFormatTest { @Test public void testParse() { diff --git a/parse/src/test/java/com/parse/ParseInstallationTest.java b/parse/src/test/java/com/parse/ParseInstallationTest.java index 311232744..f110cedcf 100644 --- a/parse/src/test/java/com/parse/ParseInstallationTest.java +++ b/parse/src/test/java/com/parse/ParseInstallationTest.java @@ -8,38 +8,37 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import com.parse.boltsinternal.Task; + import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; import java.util.Collections; import java.util.Locale; import java.util.TimeZone; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseInstallationTest extends ResetPluginsParseTest { private static final String KEY_INSTALLATION_ID = "installationId"; private static final String KEY_DEVICE_TYPE = "deviceType"; @@ -280,7 +279,7 @@ public void testUpdateBeforeSave() throws Exception { assertEquals(zone, deviceZone); } else { // If it's not updated it's because it was not acceptable. - assertFalse(deviceZone.equals("GMT")); + assertNotEquals("GMT", deviceZone); assertFalse(deviceZone.indexOf("/") > 0); } diff --git a/parse/src/test/java/com/parse/ParseKeyValueCacheTest.java b/parse/src/test/java/com/parse/ParseKeyValueCacheTest.java index 22e026885..dc34f3982 100644 --- a/parse/src/test/java/com/parse/ParseKeyValueCacheTest.java +++ b/parse/src/test/java/com/parse/ParseKeyValueCacheTest.java @@ -8,6 +8,13 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.parse.boltsinternal.Task; + import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -17,19 +24,11 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Callable; - -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; public class ParseKeyValueCacheTest { @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); private File keyValueCacheDir; @Before @@ -57,12 +56,9 @@ public void testMultipleAsynchronousWrites() throws ParseException { List> tasks = new ArrayList<>(); for (int i = 0; i < 1000; i++) { - tasks.add(Task.call(new Callable() { - @Override - public Void call() { - ParseKeyValueCache.saveToKeyValueCache("foo", "test"); - return null; - } + tasks.add(Task.call(() -> { + ParseKeyValueCache.saveToKeyValueCache("foo", "test"); + return null; }, Task.BACKGROUND_EXECUTOR)); } ParseTaskUtils.wait(Task.whenAll(tasks)); diff --git a/parse/src/test/java/com/parse/ParseMatchers.java b/parse/src/test/java/com/parse/ParseMatchers.java index af5258518..579b11959 100644 --- a/parse/src/test/java/com/parse/ParseMatchers.java +++ b/parse/src/test/java/com/parse/ParseMatchers.java @@ -8,12 +8,12 @@ */ package com.parse; +import static org.hamcrest.CoreMatchers.equalTo; + import org.hamcrest.Description; import org.hamcrest.Matcher; import org.junit.internal.matchers.TypeSafeMatcher; -import static org.hamcrest.CoreMatchers.equalTo; - public class ParseMatchers { public static Matcher hasParseErrorCode(int code) { return hasParseErrorCode(equalTo(code)); diff --git a/parse/src/test/java/com/parse/ParseObjectCurrentCoderTest.java b/parse/src/test/java/com/parse/ParseObjectCurrentCoderTest.java index 2ce2cb0d4..175be3033 100644 --- a/parse/src/test/java/com/parse/ParseObjectCurrentCoderTest.java +++ b/parse/src/test/java/com/parse/ParseObjectCurrentCoderTest.java @@ -8,6 +8,9 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + import org.json.JSONArray; import org.json.JSONObject; import org.junit.Test; @@ -18,9 +21,6 @@ import java.util.Locale; import java.util.SimpleTimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - public class ParseObjectCurrentCoderTest { // These magic strings are copied from ParseObjectCurrentCoder, since we do not want to make diff --git a/parse/src/test/java/com/parse/ParseObjectStateTest.java b/parse/src/test/java/com/parse/ParseObjectStateTest.java index 03f55e5b6..3fc84d747 100644 --- a/parse/src/test/java/com/parse/ParseObjectStateTest.java +++ b/parse/src/test/java/com/parse/ParseObjectStateTest.java @@ -8,23 +8,21 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import android.os.Parcel; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.util.Arrays; import java.util.Date; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseObjectStateTest { @Test diff --git a/parse/src/test/java/com/parse/ParseObjectTest.java b/parse/src/test/java/com/parse/ParseObjectTest.java index ae9b096c4..59dab3c21 100644 --- a/parse/src/test/java/com/parse/ParseObjectTest.java +++ b/parse/src/test/java/com/parse/ParseObjectTest.java @@ -8,8 +8,23 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.os.Parcel; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -21,7 +36,6 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; import java.net.URL; import java.util.ArrayList; @@ -34,26 +48,11 @@ import java.util.Map; import java.util.Set; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseObjectTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); private static void mockCurrentUserController() { ParseCurrentUserController userController = mock(ParseCurrentUserController.class); @@ -68,7 +67,7 @@ private static TaskCompletionSource mockObjectControllerForSa ParseObjectController objectController = mock(ParseObjectController.class); when(objectController.saveAsync( any(ParseObject.State.class), any(ParseOperationSet.class), - anyString(), any(ParseDecoder.class)) + nullable(String.class), any(ParseDecoder.class)) ).thenReturn(tcs.getTask()); ParseCorePlugins.getInstance().registerObjectController(objectController); return tcs; @@ -117,8 +116,8 @@ public void testFromJSONPayload() throws JSONException { assertEquals("GameScore", parseObject.getClassName()); assertEquals("TT1ZskATqS", parseObject.getObjectId()); ParseDateFormat format = ParseDateFormat.getInstance(); - assertTrue(parseObject.getCreatedAt().equals(format.parse("2015-06-22T21:23:41.733Z"))); - assertTrue(parseObject.getUpdatedAt().equals(format.parse("2015-06-22T22:06:18.104Z"))); + assertEquals(parseObject.getCreatedAt(), format.parse("2015-06-22T21:23:41.733Z")); + assertEquals(parseObject.getUpdatedAt(), format.parse("2015-06-22T22:06:18.104Z")); Set keys = parseObject.getState().keySet(); assertEquals(0, keys.size()); diff --git a/parse/src/test/java/com/parse/ParseOkHttpClientTest.java b/parse/src/test/java/com/parse/ParseOkHttpClientTest.java index 7d57a62bc..66286d47b 100644 --- a/parse/src/test/java/com/parse/ParseOkHttpClientTest.java +++ b/parse/src/test/java/com/parse/ParseOkHttpClientTest.java @@ -8,13 +8,16 @@ */ package com.parse; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -34,15 +37,10 @@ import okio.Buffer; import okio.BufferedSource; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseOkHttpClientTest { - private MockWebServer server = new MockWebServer(); + private final MockWebServer server = new MockWebServer(); //region testTransferRequest/Response @@ -75,7 +73,7 @@ public void testGetOkHttpRequestType() throws IOException { .build(); okHttpRequest = parseClient.getRequest(parseRequest); assertEquals(ParseHttpRequest.Method.DELETE.toString(), okHttpRequest.method()); - assertEquals(null, okHttpRequest.body()); + assertNull(okHttpRequest.body()); // Put parseRequest = builder diff --git a/parse/src/test/java/com/parse/ParsePolygonTest.java b/parse/src/test/java/com/parse/ParsePolygonTest.java index 412b891e0..a6fb82035 100644 --- a/parse/src/test/java/com/parse/ParsePolygonTest.java +++ b/parse/src/test/java/com/parse/ParsePolygonTest.java @@ -8,23 +8,22 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + import android.os.Parcel; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParsePolygonTest { @Test @@ -82,13 +81,13 @@ public void testEquality() { ParsePolygon polygonB = new ParsePolygon(points); ParsePolygon polygonC = new ParsePolygon(diff); - assertTrue(polygonA.equals(polygonB)); - assertTrue(polygonA.equals(polygonA)); - assertTrue(polygonB.equals(polygonA)); + assertEquals(polygonA, polygonB); + assertEquals(polygonA, polygonA); + assertEquals(polygonB, polygonA); - assertFalse(polygonA.equals(null)); - assertFalse(polygonA.equals(true)); - assertFalse(polygonA.equals(polygonC)); + assertNotEquals(null, polygonA); + assertNotEquals(true, polygonA); + assertNotEquals(polygonA, polygonC); } @Test diff --git a/parse/src/test/java/com/parse/ParsePushControllerTest.java b/parse/src/test/java/com/parse/ParsePushControllerTest.java index d716d4a48..9227e30c4 100644 --- a/parse/src/test/java/com/parse/ParsePushControllerTest.java +++ b/parse/src/test/java/com/parse/ParsePushControllerTest.java @@ -8,6 +8,19 @@ */ package com.parse; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -19,7 +32,6 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import org.skyscreamer.jsonassert.JSONCompareMode; import java.io.ByteArrayInputStream; @@ -29,23 +41,8 @@ import java.util.ArrayList; import java.util.List; -import com.parse.boltsinternal.Task; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - // For SSLSessionCache @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParsePushControllerTest { private static boolean containsString(JSONArray array, String value) throws JSONException { diff --git a/parse/src/test/java/com/parse/ParsePushStateTest.java b/parse/src/test/java/com/parse/ParsePushStateTest.java index d21690bf6..5ff47d847 100644 --- a/parse/src/test/java/com/parse/ParsePushStateTest.java +++ b/parse/src/test/java/com/parse/ParsePushStateTest.java @@ -8,6 +8,15 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import org.json.JSONException; import org.json.JSONObject; import org.junit.Test; @@ -21,14 +30,6 @@ import java.util.List; import java.util.Set; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - public class ParsePushStateTest { //region testDefaults @@ -51,12 +52,12 @@ public void testDefaultsWithData() throws Exception { .data(data) .build(); - assertEquals(null, state.expirationTime()); - assertEquals(null, state.expirationTimeInterval()); - assertEquals(null, state.pushTime()); - assertEquals(null, state.channelSet()); + assertNull(state.expirationTime()); + assertNull(state.expirationTimeInterval()); + assertNull(state.pushTime()); + assertNull(state.channelSet()); JSONAssert.assertEquals(data, state.data(), JSONCompareMode.NON_EXTENSIBLE); - assertEquals(null, state.queryState()); + assertNull(state.queryState()); } //endregion @@ -102,7 +103,7 @@ public void testExpirationTimeNullTime() { .data(new JSONObject()) .build(); - assertEquals(null, state.expirationTime()); + assertNull(state.expirationTime()); } @Test @@ -130,7 +131,7 @@ public void testExpirationTimeIntervalNullInterval() { .data(new JSONObject()) .build(); - assertEquals(null, state.expirationTimeInterval()); + assertNull(state.expirationTimeInterval()); } @Test @@ -158,7 +159,7 @@ public void testPushTimeNullTime() { .data(new JSONObject()) .build(); - assertEquals(null, state.pushTime()); + assertNull(state.pushTime()); } @Test @@ -315,7 +316,7 @@ public void testQueryNotInstallationQuery() { ParsePush.State.Builder builder = new ParsePush.State.Builder(); ParsePush.State state = builder - .query(new ParseQuery("test")) + .query(new ParseQuery<>("test")) .data(new JSONObject()) .build(); } diff --git a/parse/src/test/java/com/parse/ParsePushTest.java b/parse/src/test/java/com/parse/ParsePushTest.java index e818c2e60..8bab29bf6 100644 --- a/parse/src/test/java/com/parse/ParsePushTest.java +++ b/parse/src/test/java/com/parse/ParsePushTest.java @@ -8,6 +8,24 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.robolectric.annotation.LooperMode.Mode.PAUSED; +import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + +import com.parse.boltsinternal.Capture; +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import org.junit.After; import org.junit.Before; @@ -15,7 +33,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import org.skyscreamer.jsonassert.JSONCompareMode; import java.util.ArrayList; @@ -23,23 +41,8 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import com.parse.boltsinternal.Capture; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) +@LooperMode(PAUSED) public class ParsePushTest { @Before @@ -271,13 +274,13 @@ public void testSubscribeInBackgroundWithCallbackSuccess() throws Exception { ParsePush push = new ParsePush(); final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - ParsePush.subscribeInBackground("test", new SaveCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + ParsePush.subscribeInBackground("test", e -> { + exceptionCapture.set(e); + done.release(); }); + + shadowMainLooper().idle(); + assertNull(exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).subscribeInBackground("test"); @@ -307,13 +310,13 @@ public void testSubscribeInBackgroundWithCallbackFail() throws Exception { ParsePush push = new ParsePush(); final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - ParsePush.subscribeInBackground("test", new SaveCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + ParsePush.subscribeInBackground("test", e -> { + exceptionCapture.set(e); + done.release(); }); + + shadowMainLooper().idle(); + assertSame(exception, exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).subscribeInBackground("test"); @@ -341,13 +344,13 @@ public void testUnsubscribeInBackgroundWithCallbackSuccess() throws Exception { final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - ParsePush.unsubscribeInBackground("test", new SaveCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + ParsePush.unsubscribeInBackground("test", e -> { + exceptionCapture.set(e); + done.release(); }); + + shadowMainLooper().idle(); + assertNull(exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).unsubscribeInBackground("test"); @@ -379,13 +382,13 @@ public void testUnsubscribeInBackgroundWithCallbackFail() throws Exception { ParsePush push = new ParsePush(); final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - ParsePush.unsubscribeInBackground("test", new SaveCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + ParsePush.unsubscribeInBackground("test", e -> { + exceptionCapture.set(e); + done.release(); }); + + shadowMainLooper().idle(); + assertSame(exception, exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); verify(controller, times(1)).unsubscribeInBackground("test"); @@ -423,7 +426,7 @@ public void testGetPushController() { public void testSendInBackgroundSuccess() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -441,7 +444,7 @@ public void testSendInBackgroundSuccess() throws Exception { // Make sure controller is executed and state parameter is correct ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); assertEquals(data, state.data(), JSONCompareMode.NON_EXTENSIBLE); assertEquals(2, state.channelSet().size()); @@ -453,7 +456,7 @@ public void testSendInBackgroundSuccess() throws Exception { public void testSendInBackgroundWithCallbackSuccess() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -469,19 +472,18 @@ public void testSendInBackgroundWithCallbackSuccess() throws Exception { .channelSet(channels); final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - push.sendInBackground(new SendCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + push.sendInBackground(e -> { + exceptionCapture.set(e); + done.release(); }); + shadowMainLooper().idle(); + // Make sure controller is executed and state parameter is correct assertNull(exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); assertEquals(data, state.data(), JSONCompareMode.NON_EXTENSIBLE); assertEquals(2, state.channelSet().size()); @@ -494,7 +496,7 @@ public void testSendInBackgroundFail() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); ParseException exception = new ParseException(ParseException.OTHER_CAUSE, "error"); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forError(exception)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -513,7 +515,7 @@ public void testSendInBackgroundFail() throws Exception { // Make sure controller is executed and state parameter is correct ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); assertEquals(data, state.data(), JSONCompareMode.NON_EXTENSIBLE); assertEquals(2, state.channelSet().size()); @@ -529,7 +531,7 @@ public void testSendInBackgroundWithCallbackFail() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); final ParseException exception = new ParseException(ParseException.OTHER_CAUSE, "error"); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forError(exception)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -545,19 +547,18 @@ public void testSendInBackgroundWithCallbackFail() throws Exception { .channelSet(channels); final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - push.sendInBackground(new SendCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + push.sendInBackground(e -> { + exceptionCapture.set(e); + done.release(); }); + shadowMainLooper().idle(); + // Make sure controller is executed and state parameter is correct assertSame(exception, exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); assertEquals(data, state.data(), JSONCompareMode.NON_EXTENSIBLE); assertEquals(2, state.channelSet().size()); @@ -569,7 +570,7 @@ public void done(ParseException e) { public void testSendSuccess() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -587,7 +588,7 @@ public void testSendSuccess() throws Exception { // Make sure controller is executed and state parameter is correct ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); assertEquals(data, state.data(), JSONCompareMode.NON_EXTENSIBLE); assertEquals(2, state.channelSet().size()); @@ -600,7 +601,7 @@ public void testSendFail() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); final ParseException exception = new ParseException(ParseException.OTHER_CAUSE, "error"); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forError(exception)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -622,7 +623,7 @@ public void testSendFail() throws Exception { // Make sure controller is executed and state parameter is correct ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); assertEquals(data, state.data(), JSONCompareMode.NON_EXTENSIBLE); assertEquals(2, state.channelSet().size()); @@ -637,7 +638,7 @@ public void testSendFail() throws Exception { public void testSendMessageInBackground() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -649,7 +650,7 @@ public void testSendMessageInBackground() throws Exception { // Make sure controller is executed and state parameter is correct ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); // Verify query state ParseQuery.State queryState = state.queryState(); @@ -663,7 +664,7 @@ public void testSendMessageInBackground() throws Exception { public void testSendMessageInBackgroundWithCallback() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -673,19 +674,18 @@ public void testSendMessageInBackgroundWithCallback() throws Exception { .whereEqualTo("foo", "bar"); final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - ParsePush.sendMessageInBackground("test", query, new SendCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + ParsePush.sendMessageInBackground("test", query, e -> { + exceptionCapture.set(e); + done.release(); }); + shadowMainLooper().idle(); + // Make sure controller is executed and state parameter is correct assertNull(exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); // Verify query state ParseQuery.State queryState = state.queryState(); @@ -703,7 +703,7 @@ public void done(ParseException e) { public void testSendDataInBackground() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -718,7 +718,7 @@ public void testSendDataInBackground() throws Exception { // Make sure controller is executed and state parameter is correct ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); // Verify query state ParseQuery.State queryState = state.queryState(); @@ -732,7 +732,7 @@ public void testSendDataInBackground() throws Exception { public void testSendDataInBackgroundWithCallback() throws Exception { // Mock controller ParsePushController controller = mock(ParsePushController.class); - when(controller.sendInBackground(any(ParsePush.State.class), anyString())) + when(controller.sendInBackground(any(ParsePush.State.class), nullable(String.class))) .thenReturn(Task.forResult(null)); ParseCorePlugins.getInstance().registerPushController(controller); @@ -745,19 +745,18 @@ public void testSendDataInBackgroundWithCallback() throws Exception { .whereEqualTo("foo", "bar"); final Semaphore done = new Semaphore(0); final Capture exceptionCapture = new Capture<>(); - ParsePush.sendDataInBackground(data, query, new SendCallback() { - @Override - public void done(ParseException e) { - exceptionCapture.set(e); - done.release(); - } + ParsePush.sendDataInBackground(data, query, e -> { + exceptionCapture.set(e); + done.release(); }); + shadowMainLooper().idle(); + // Make sure controller is executed and state parameter is correct assertNull(exceptionCapture.get()); assertTrue(done.tryAcquire(1, 10, TimeUnit.SECONDS)); ArgumentCaptor stateCaptor = ArgumentCaptor.forClass(ParsePush.State.class); - verify(controller, times(1)).sendInBackground(stateCaptor.capture(), anyString()); + verify(controller, times(1)).sendInBackground(stateCaptor.capture(), nullable(String.class)); ParsePush.State state = stateCaptor.getValue(); // Verify query state ParseQuery.State queryState = state.queryState(); diff --git a/parse/src/test/java/com/parse/ParseQueryStateTest.java b/parse/src/test/java/com/parse/ParseQueryStateTest.java index 313f0d9b5..2c9f18f12 100644 --- a/parse/src/test/java/com/parse/ParseQueryStateTest.java +++ b/parse/src/test/java/com/parse/ParseQueryStateTest.java @@ -8,12 +8,16 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + import org.json.JSONException; import org.json.JSONObject; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; @@ -24,13 +28,7 @@ import java.util.Iterator; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseQueryStateTest extends ResetPluginsParseTest { @Test @@ -216,7 +214,7 @@ public void testOrIsMutable() { @Test(expected = IllegalArgumentException.class) public void testOrThrowsWithEmptyList() { - ParseQuery.State.Builder.or(new ArrayList>()).build(); + ParseQuery.State.Builder.or(new ArrayList<>()).build(); } @Test(expected = IllegalArgumentException.class) diff --git a/parse/src/test/java/com/parse/ParseQueryTest.java b/parse/src/test/java/com/parse/ParseQueryTest.java index 5ba86a89b..65466aa11 100644 --- a/parse/src/test/java/com/parse/ParseQueryTest.java +++ b/parse/src/test/java/com/parse/ParseQueryTest.java @@ -8,8 +8,26 @@ */ package com.parse; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import androidx.annotation.NonNull; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; +import com.parse.boltsinternal.TaskCompletionSource; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -24,24 +42,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Pattern; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; -import com.parse.boltsinternal.TaskCompletionSource; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class ParseQueryTest { private static void verifyCondition(ParseQuery query, String key, Object value) { @@ -854,12 +854,7 @@ private static class TestQueryController implements ParseQueryController { private Task toAwait = Task.forResult(null); public Task await(final Task task) { - toAwait = toAwait.continueWithTask(new Continuation>() { - @Override - public Task then(Task ignored) { - return task; - } - }); + toAwait = toAwait.continueWithTask(ignored -> task); return toAwait; } @@ -867,21 +862,15 @@ public Task then(Task ignored) { public Task> findAsync(ParseQuery.State state, ParseUser user, Task cancellationToken) { final AtomicBoolean cancelled = new AtomicBoolean(false); - cancellationToken.continueWith(new Continuation() { - @Override - public Void then(Task task) { - cancelled.set(true); - return null; - } + cancellationToken.continueWith((Continuation) task -> { + cancelled.set(true); + return null; }); - return await(Task.forResult(null).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (cancelled.get()) { - return Task.cancelled(); - } - return task; + return await(Task.forResult(null).continueWithTask(task -> { + if (cancelled.get()) { + return Task.cancelled(); } + return task; })).cast(); } @@ -889,21 +878,15 @@ public Task then(Task task) { public Task countAsync(ParseQuery.State state, ParseUser user, Task cancellationToken) { final AtomicBoolean cancelled = new AtomicBoolean(false); - cancellationToken.continueWith(new Continuation() { - @Override - public Void then(Task task) { - cancelled.set(true); - return null; - } + cancellationToken.continueWith((Continuation) task -> { + cancelled.set(true); + return null; }); - return await(Task.forResult(null).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (cancelled.get()) { - return Task.cancelled(); - } - return task; + return await(Task.forResult(null).continueWithTask(task -> { + if (cancelled.get()) { + return Task.cancelled(); } + return task; })).cast(); } @@ -911,21 +894,15 @@ public Task then(Task task) { public Task getFirstAsync(ParseQuery.State state, ParseUser user, Task cancellationToken) { final AtomicBoolean cancelled = new AtomicBoolean(false); - cancellationToken.continueWith(new Continuation() { - @Override - public Void then(Task task) { - cancelled.set(true); - return null; - } + cancellationToken.continueWith((Continuation) task -> { + cancelled.set(true); + return null; }); - return await(Task.forResult(null).continueWithTask(new Continuation>() { - @Override - public Task then(Task task) { - if (cancelled.get()) { - return Task.cancelled(); - } - return task; + return await(Task.forResult(null).continueWithTask(task -> { + if (cancelled.get()) { + return Task.cancelled(); } + return task; })).cast(); } } diff --git a/parse/src/test/java/com/parse/ParseRESTCommandTest.java b/parse/src/test/java/com/parse/ParseRESTCommandTest.java index 7f8747cfb..b3c02f59b 100644 --- a/parse/src/test/java/com/parse/ParseRESTCommandTest.java +++ b/parse/src/test/java/com/parse/ParseRESTCommandTest.java @@ -8,6 +8,21 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -20,7 +35,6 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import org.skyscreamer.jsonassert.JSONCompareMode; import java.io.ByteArrayInputStream; @@ -28,30 +42,13 @@ import java.io.InputStream; import java.net.URL; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - // For org.json @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) @SuppressWarnings("ThrowableResultOfMethodCallIgnored") public class ParseRESTCommandTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); private static ParseHttpResponse newMockParseHttpResponse(int statusCode, JSONObject body) { return newMockParseHttpResponse(statusCode, body.toString()); diff --git a/parse/src/test/java/com/parse/ParseRESTQueryCommandTest.java b/parse/src/test/java/com/parse/ParseRESTQueryCommandTest.java index beca26387..fe31ca6ff 100644 --- a/parse/src/test/java/com/parse/ParseRESTQueryCommandTest.java +++ b/parse/src/test/java/com/parse/ParseRESTQueryCommandTest.java @@ -8,6 +8,11 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + import com.parse.http.ParseHttpRequest; import org.json.JSONArray; @@ -23,11 +28,6 @@ import java.util.Collections; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - public class ParseRESTQueryCommandTest { @Before diff --git a/parse/src/test/java/com/parse/ParseRESTUserCommandTest.java b/parse/src/test/java/com/parse/ParseRESTUserCommandTest.java index bb0b23a51..296b53543 100644 --- a/parse/src/test/java/com/parse/ParseRESTUserCommandTest.java +++ b/parse/src/test/java/com/parse/ParseRESTUserCommandTest.java @@ -8,6 +8,10 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -23,10 +27,6 @@ import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - public class ParseRESTUserCommandTest { @Before diff --git a/parse/src/test/java/com/parse/ParseRelationTest.java b/parse/src/test/java/com/parse/ParseRelationTest.java index edc89c6f4..61aadc23b 100644 --- a/parse/src/test/java/com/parse/ParseRelationTest.java +++ b/parse/src/test/java/com/parse/ParseRelationTest.java @@ -8,6 +8,15 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; + import android.os.Parcel; import org.json.JSONArray; @@ -17,24 +26,13 @@ import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; -import org.robolectric.annotation.Config; import org.skyscreamer.jsonassert.JSONCompareMode; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import static org.skyscreamer.jsonassert.JSONAssert.assertEquals; - @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) public class ParseRelationTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); //region testConstructor diff --git a/parse/src/test/java/com/parse/ParseRequestTest.java b/parse/src/test/java/com/parse/ParseRequestTest.java index 39f723062..87e592313 100644 --- a/parse/src/test/java/com/parse/ParseRequestTest.java +++ b/parse/src/test/java/com/parse/ParseRequestTest.java @@ -8,6 +8,16 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpBody; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -26,23 +36,12 @@ import java.util.LinkedList; import java.util.List; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - public class ParseRequestTest { private static byte[] data; @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); + public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @BeforeClass public static void setUpClass() { @@ -121,7 +120,7 @@ public void testDownloadProgress() throws Exception { } private static class TestProgressCallback implements ProgressCallback { - List history = new LinkedList<>(); + final List history = new LinkedList<>(); @Override public void done(Integer percentDone) { diff --git a/parse/src/test/java/com/parse/ParseRoleTest.java b/parse/src/test/java/com/parse/ParseRoleTest.java index 06573f1ab..a1431754a 100644 --- a/parse/src/test/java/com/parse/ParseRoleTest.java +++ b/parse/src/test/java/com/parse/ParseRoleTest.java @@ -8,15 +8,15 @@ */ package com.parse; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThat; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + public class ParseRoleTest { @Before diff --git a/parse/src/test/java/com/parse/ParseSessionTest.java b/parse/src/test/java/com/parse/ParseSessionTest.java index bfe105479..4222447f0 100644 --- a/parse/src/test/java/com/parse/ParseSessionTest.java +++ b/parse/src/test/java/com/parse/ParseSessionTest.java @@ -8,14 +8,14 @@ */ package com.parse; +import static org.junit.Assert.assertTrue; + import org.junit.After; import org.junit.Before; import org.junit.Test; import java.util.Collections; -import static org.junit.Assert.assertTrue; - public class ParseSessionTest { @Before diff --git a/parse/src/test/java/com/parse/ParseTaskUtilsTest.java b/parse/src/test/java/com/parse/ParseTaskUtilsTest.java index 173415618..7c5fa3c15 100644 --- a/parse/src/test/java/com/parse/ParseTaskUtilsTest.java +++ b/parse/src/test/java/com/parse/ParseTaskUtilsTest.java @@ -8,15 +8,14 @@ */ package com.parse; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.concurrent.Callable; +import static org.junit.Assert.assertTrue; import com.parse.boltsinternal.AggregateException; import com.parse.boltsinternal.Task; -import static org.junit.Assert.assertTrue; +import org.junit.Test; + +import java.util.ArrayList; public class ParseTaskUtilsTest { /** @@ -30,15 +29,12 @@ public void testWaitForTaskWrapsAggregateExceptionAsParseException() { final ArrayList> tasks = new ArrayList<>(); for (int i = 0; i < 20; i++) { final int number = i; - Task task = Task.callInBackground(new Callable() { - @Override - public Void call() throws Exception { - Thread.sleep((long) (Math.random() * 100)); - if (number == 10 || number == 11) { - throw error; - } - return null; + Task task = Task.callInBackground(() -> { + Thread.sleep((long) (Math.random() * 100)); + if (number == 10 || number == 11) { + throw error; } + return null; }); tasks.add(task); } diff --git a/parse/src/test/java/com/parse/ParseTestUtils.java b/parse/src/test/java/com/parse/ParseTestUtils.java index 501e65c21..f076e5721 100644 --- a/parse/src/test/java/com/parse/ParseTestUtils.java +++ b/parse/src/test/java/com/parse/ParseTestUtils.java @@ -8,8 +8,13 @@ */ package com.parse; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.content.Context; +import com.parse.boltsinternal.Task; import com.parse.http.ParseHttpRequest; import com.parse.http.ParseHttpResponse; @@ -19,12 +24,6 @@ import java.io.File; import java.io.IOException; -import com.parse.boltsinternal.Task; - -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - final class ParseTestUtils { /** diff --git a/parse/src/test/java/com/parse/ParseTextUtilsTest.java b/parse/src/test/java/com/parse/ParseTextUtilsTest.java index 833743d77..cf5143440 100644 --- a/parse/src/test/java/com/parse/ParseTextUtilsTest.java +++ b/parse/src/test/java/com/parse/ParseTextUtilsTest.java @@ -8,15 +8,15 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + import org.junit.Test; import java.util.Arrays; import java.util.Collections; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - public class ParseTextUtilsTest { //region testJoin diff --git a/parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java b/parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java index 7940faf48..e3e15ebfb 100644 --- a/parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java +++ b/parse/src/test/java/com/parse/ParseUserCurrentCoderTest.java @@ -8,16 +8,16 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + import org.json.JSONObject; import org.junit.Test; import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; - public class ParseUserCurrentCoderTest { private static final String KEY_AUTH_DATA = "auth_data"; diff --git a/parse/src/test/java/com/parse/ParseUserTest.java b/parse/src/test/java/com/parse/ParseUserTest.java index 3c65c2b8b..7499575fd 100644 --- a/parse/src/test/java/com/parse/ParseUserTest.java +++ b/parse/src/test/java/com/parse/ParseUserTest.java @@ -8,9 +8,36 @@ */ package com.parse; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyBoolean; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; +import static org.robolectric.annotation.LooperMode.Mode.PAUSED; +import static org.robolectric.shadows.ShadowLooper.shadowMainLooper; + import android.Manifest; import android.os.Parcel; +import com.parse.boltsinternal.Capture; +import com.parse.boltsinternal.Continuation; +import com.parse.boltsinternal.Task; + import org.json.JSONObject; import org.junit.After; import org.junit.Before; @@ -23,7 +50,7 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; -import org.robolectric.annotation.Config; +import org.robolectric.annotation.LooperMode; import java.util.Collections; import java.util.Date; @@ -33,37 +60,13 @@ import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import com.parse.boltsinternal.Capture; -import com.parse.boltsinternal.Continuation; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - // For ParseExecutors.main() @RunWith(RobolectricTestRunner.class) -@Config(constants = BuildConfig.class, sdk = TestHelper.ROBOLECTRIC_SDK_VERSION) +@LooperMode(PAUSED) public class ParseUserTest extends ResetPluginsParseTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); private static void setLazy(ParseUser user) { Map anonymousAuthData = new HashMap<>(); @@ -281,7 +284,7 @@ public void testSignUpAsyncWithMergeInDiskAnonymousUser() throws Exception { when(currentUser.isLazy()).thenReturn(false); when(currentUser.isLinked(ParseAnonymousUtils.AUTH_TYPE)).thenReturn(true); when(currentUser.getSessionToken()).thenReturn("oldSessionToken"); - when(currentUser.getAuthData()).thenReturn(new HashMap>()); + when(currentUser.getAuthData()).thenReturn(new HashMap<>()); when(currentUser.saveAsync(anyString(), eq(false), Matchers.>any())) .thenReturn(Task.forResult(null)); ParseUser.State state = new ParseUser.State.Builder() @@ -380,7 +383,7 @@ public void testSignUpAsyncWithNoCurrentUserAndSignUpSuccess() throws Exception .sessionToken("newSessionToken") .build(); when(userController.signUpAsync( - any(ParseUser.State.class), any(ParseOperationSet.class), anyString())) + any(ParseUser.State.class), any(ParseOperationSet.class), nullable(String.class))) .thenReturn(Task.forResult(newUserState)); ParseCorePlugins.getInstance().registerUserController(userController); @@ -392,7 +395,7 @@ public void testSignUpAsyncWithNoCurrentUserAndSignUpSuccess() throws Exception // Make sure we sign up the user verify(userController, times(1)).signUpAsync( - any(ParseUser.State.class), any(ParseOperationSet.class), anyString()); + any(ParseUser.State.class), any(ParseOperationSet.class), nullable(String.class)); // Make sure user's data is correct assertEquals("newSessionToken", user.getSessionToken()); assertEquals("newValue", user.getString("newKey")); @@ -416,7 +419,7 @@ public void testSignUpAsyncWithNoCurrentUserAndSignUpFailure() { ParseUserController userController = mock(ParseUserController.class); ParseException signUpException = new ParseException(ParseException.OTHER_CAUSE, "test"); when(userController.signUpAsync( - any(ParseUser.State.class), any(ParseOperationSet.class), anyString())) + any(ParseUser.State.class), any(ParseOperationSet.class), nullable(String.class))) .thenReturn(Task.forError(signUpException)); ParseCorePlugins.getInstance().registerUserController(userController); @@ -429,7 +432,7 @@ public void testSignUpAsyncWithNoCurrentUserAndSignUpFailure() { // Make sure we sign up the user verify(userController, times(1)).signUpAsync( - any(ParseUser.State.class), any(ParseOperationSet.class), anyString()); + any(ParseUser.State.class), any(ParseOperationSet.class), nullable(String.class)); // Make sure user's data is correct assertEquals("value", user.getString("key")); // Make sure we never set the current user @@ -476,7 +479,7 @@ public void testLoginWithAsyncWithoutExistingLazyUser() throws ParseException { public void testLoginWithAsyncWithLinkedLazyUser() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); - currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap()); + currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<>()); setLazy(currentUser); ParseUser partialMockCurrentUser = spy(currentUser); when(partialMockCurrentUser.getSessionToken()).thenReturn("oldSessionToken"); @@ -540,7 +543,7 @@ public void testLoginWithAsyncWithLinkedNotLazyUser() throws Exception { // Register a mock currentUserController to make getCurrentUser work ParseUser.State state = new ParseUser.State.Builder() .objectId("objectId") // Make it not lazy - .putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap()) + .putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<>()) .build(); ParseUser currentUser = ParseUser.from(state); ParseUser partialMockCurrentUser = spy(currentUser); // ParseUser.mutex @@ -578,7 +581,7 @@ public void testLoginWithAsyncWithLinkedNotLazyUserLinkFailure() throws Exceptio ParseCorePlugins.getInstance().registerUserController(userController); // Register a mock currentUserController to make getCurrentUser work ParseUser currentUser = new ParseUser(); - currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap()); + currentUser.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<>()); currentUser.setObjectId("objectId"); // Make it not lazy. ParseUser partialMockCurrentUser = spy(currentUser); when(partialMockCurrentUser.getSessionToken()).thenReturn("sessionToken"); @@ -668,7 +671,7 @@ public void testlinkWithInBackgroundWithSaveAsyncSuccess() throws Exception { user.setIsCurrentUser(true); // To verify stripAnonymity user.setObjectId("objectId"); - user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap()); + user.putAuthData(ParseAnonymousUtils.AUTH_TYPE, new HashMap<>()); ParseUser partialMockUser = spy(user); doReturn(Task.forResult(null)) .when(partialMockUser) @@ -741,7 +744,7 @@ public void testlinkWithInBackgroundWithSaveAsyncFailure() throws Exception { public void testResolveLazinessAsyncWithAuthDataAndNotNewUser() throws Exception { ParseUser user = new ParseUser(); setLazy(user); - user.putAuthData("facebook", new HashMap()); + user.putAuthData("facebook", new HashMap<>()); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder() @@ -781,7 +784,7 @@ public void testResolveLazinessAsyncWithAuthDataAndNotNewUser() throws Exception public void testResolveLazinessAsyncWithAuthDataAndNewUser() throws Exception { ParseUser user = new ParseUser(); setLazy(user); - user.putAuthData("facebook", new HashMap()); + user.putAuthData("facebook", new HashMap<>()); // Register a mock userController to make logIn work ParseUserController userController = mock(ParseUserController.class); ParseUser.State newUserState = new ParseUser.State.Builder() @@ -819,7 +822,7 @@ public void testResolveLazinessAsyncWithAuthDataAndNewUser() throws Exception { public void testResolveLazinessAsyncWithAuthDataAndNotNewUserAndLDSEnabled() throws Exception { ParseUser user = new ParseUser(); setLazy(user); - user.putAuthData("facebook", new HashMap()); + user.putAuthData("facebook", new HashMap<>()); // To verify handleSaveResultAsync is not called user.setPassword("password"); // Register a mock userController to make logIn work @@ -1219,17 +1222,16 @@ public void testLogInWithCallback() throws Exception { ParseCorePlugins.getInstance().registerUserController(userController); final Semaphore done = new Semaphore(0); - ParseUser.logInInBackground("userName", "password", new LogInCallback() { - @Override - public void done(ParseUser user, ParseException e) { - done.release(); - assertNull(e); - // Make sure user's data is correct - assertEquals("newSessionToken", user.getSessionToken()); - assertEquals("newValue", user.get("newKey")); - } + ParseUser.logInInBackground("userName", "password", (user, e) -> { + done.release(); + assertNull(e); + // Make sure user's data is correct + assertEquals("newSessionToken", user.getSessionToken()); + assertEquals("newValue", user.get("newKey")); }); + shadowMainLooper().idle(); + assertTrue(done.tryAcquire(5, TimeUnit.SECONDS)); // Make sure user is login verify(userController, times(1)).logInAsync("userName", "password"); @@ -1295,15 +1297,12 @@ public void testBecomeWithCallback() { ParseCorePlugins.getInstance().registerUserController(userController); final Semaphore done = new Semaphore(0); - ParseUser.becomeInBackground("sessionToken", new LogInCallback() { - @Override - public void done(ParseUser user, ParseException e) { - done.release(); - assertNull(e); - // Make sure user's data is correct - assertEquals("sessionToken", user.getSessionToken()); - assertEquals("value", user.get("key")); - } + ParseUser.becomeInBackground("sessionToken", (user, e) -> { + done.release(); + assertNull(e); + // Make sure user's data is correct + assertEquals("sessionToken", user.getSessionToken()); + assertEquals("value", user.get("key")); }); // Make sure we call getUserAsync @@ -1567,7 +1566,7 @@ public void testSaveEventuallyWhenServerError() throws Exception { .grantPermissions(Manifest.permission.ACCESS_NETWORK_STATE); Parse.Configuration configuration = new Parse.Configuration.Builder(RuntimeEnvironment.application) - .applicationId(BuildConfig.APPLICATION_ID) + .applicationId(BuildConfig.LIBRARY_PACKAGE_NAME) .server("https://api.parse.com/1") .enableLocalDataStore() .build(); @@ -1598,13 +1597,10 @@ public void testSaveEventuallyWhenServerError() throws Exception { final CountDownLatch saveCountDown1 = new CountDownLatch(1); final Capture exceptionCapture = new Capture<>(); - user.saveInBackground().continueWith(new Continuation() { - @Override - public Void then(Task task) { - exceptionCapture.set(task.getError()); - saveCountDown1.countDown(); - return null; - } + user.saveInBackground().continueWith((Continuation) task -> { + exceptionCapture.set(task.getError()); + saveCountDown1.countDown(); + return null; }); assertTrue(saveCountDown1.await(5, TimeUnit.SECONDS)); assertNull(exceptionCapture.get()); @@ -1620,13 +1616,10 @@ public Void then(Task task) { restClient, mockResponse, 400, "Bad Request"); final CountDownLatch saveEventuallyCountDown = new CountDownLatch(1); - user.saveEventually().continueWith(new Continuation() { - @Override - public Void then(Task task) { - exceptionCapture.set(task.getError()); - saveEventuallyCountDown.countDown(); - return null; - } + user.saveEventually().continueWith((Continuation) task -> { + exceptionCapture.set(task.getError()); + saveEventuallyCountDown.countDown(); + return null; }); assertTrue(saveEventuallyCountDown.await(5, TimeUnit.SECONDS)); assertTrue(exceptionCapture.get() instanceof ParseException); @@ -1650,13 +1643,10 @@ public Void then(Task task) { restClient, mockResponse, 200, "OK"); final CountDownLatch saveCountDown2 = new CountDownLatch(1); - user.saveInBackground().continueWith(new Continuation() { - @Override - public Void then(Task task) { - exceptionCapture.set(task.getError()); - saveCountDown2.countDown(); - return null; - } + user.saveInBackground().continueWith((Continuation) task -> { + exceptionCapture.set(task.getError()); + saveCountDown2.countDown(); + return null; }); assertTrue(saveCountDown2.await(5, TimeUnit.SECONDS)); diff --git a/parse/src/test/java/com/parse/PointerEncoderTest.java b/parse/src/test/java/com/parse/PointerEncoderTest.java index 21005dca3..0e24189c7 100644 --- a/parse/src/test/java/com/parse/PointerEncoderTest.java +++ b/parse/src/test/java/com/parse/PointerEncoderTest.java @@ -8,17 +8,17 @@ */ package com.parse; +import static org.junit.Assert.assertNotNull; + import org.json.JSONObject; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import static org.junit.Assert.assertNotNull; - public class PointerEncoderTest { @Rule - public ExpectedException thrown = ExpectedException.none(); + public final ExpectedException thrown = ExpectedException.none(); @Test public void testEncodeRelatedObjectWithoutObjectId() { diff --git a/parse/src/test/java/com/parse/SubclassTest.java b/parse/src/test/java/com/parse/SubclassTest.java index 0e8054594..28e78a683 100644 --- a/parse/src/test/java/com/parse/SubclassTest.java +++ b/parse/src/test/java/com/parse/SubclassTest.java @@ -8,10 +8,6 @@ */ package com.parse; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -19,6 +15,10 @@ import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + public class SubclassTest extends ResetPluginsParseTest { @Before public void setUp() throws Exception { diff --git a/parse/src/test/java/com/parse/TaskQueueTestHelper.java b/parse/src/test/java/com/parse/TaskQueueTestHelper.java index 5fa8e0296..72b3f8c10 100644 --- a/parse/src/test/java/com/parse/TaskQueueTestHelper.java +++ b/parse/src/test/java/com/parse/TaskQueueTestHelper.java @@ -8,13 +8,12 @@ */ package com.parse; -import java.util.ArrayList; -import java.util.List; - -import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; import com.parse.boltsinternal.TaskCompletionSource; +import java.util.ArrayList; +import java.util.List; + /** * Helper class to step through a {@link TaskQueue}. *

@@ -37,12 +36,7 @@ public TaskQueueTestHelper(TaskQueue taskQueue) { public void enqueue() { synchronized (lock) { final TaskCompletionSource tcs = new TaskCompletionSource(); - taskQueue.enqueue(new Continuation>() { - @Override - public Task then(Task task) { - return tcs.getTask(); - } - }); + taskQueue.enqueue(task -> tcs.getTask()); pendingTasks.add(tcs); } } diff --git a/rxjava/build.gradle b/rxjava/build.gradle index e1c160fc3..d752dff26 100644 --- a/rxjava/build.gradle +++ b/rxjava/build.gradle @@ -1,5 +1,8 @@ apply plugin: "com.android.library" apply plugin: "kotlin-android" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" + android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -26,12 +29,18 @@ android { } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = "1.8" + } } dependencies { - api "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" api "io.reactivex.rxjava3:rxjava:3.0.4" implementation project(":parse") -} - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" +} \ No newline at end of file diff --git a/twitter/build.gradle b/twitter/build.gradle index 76e3a3404..da7f604ad 100644 --- a/twitter/build.gradle +++ b/twitter/build.gradle @@ -1,4 +1,6 @@ apply plugin: "com.android.library" +apply plugin: "io.freefair.android-javadoc-jar" +apply plugin: "io.freefair.android-sources-jar" android { compileSdkVersion rootProject.ext.compileSdkVersion @@ -17,16 +19,19 @@ android { lintOptions { abortOnError false } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { - api "androidx.appcompat:appcompat:1.1.0" + api "androidx.appcompat:appcompat:1.3.1" api "oauth.signpost:signpost-core:1.2.1.2" api "se.akerfeldt:okhttp-signpost:1.1.0" implementation project(":parse") - testImplementation "junit:junit:4.13" - testImplementation "org.mockito:mockito-core:1.10.19" + testImplementation "junit:junit:4.13.2" + testImplementation "org.mockito:mockito-core:3.9.0" } - -apply from: "https://raw.githubusercontent.com/Commit451/gradle-android-javadocs/1.1.0/gradle-android-javadocs.gradle" diff --git a/twitter/src/main/AndroidManifest.xml b/twitter/src/main/AndroidManifest.xml index c5ae2f108..8d42f0441 100644 --- a/twitter/src/main/AndroidManifest.xml +++ b/twitter/src/main/AndroidManifest.xml @@ -6,4 +6,4 @@ ~ LICENSE file in the root directory of this source tree. An additional grant ~ of patent rights can be found in the PATENTS file in the same directory. --> - + diff --git a/twitter/src/main/java/com/parse/twitter/OAuth1FlowDialog.java b/twitter/src/main/java/com/parse/twitter/OAuth1FlowDialog.java index 59befab9b..92f8b2d6a 100644 --- a/twitter/src/main/java/com/parse/twitter/OAuth1FlowDialog.java +++ b/twitter/src/main/java/com/parse/twitter/OAuth1FlowDialog.java @@ -10,18 +10,18 @@ import android.annotation.SuppressLint; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; -import androidx.appcompat.app.AppCompatDialog; import android.view.View; import android.view.Window; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.ProgressBar; +import androidx.appcompat.app.AppCompatDialog; + /** * For internal use. */ @@ -41,12 +41,7 @@ class OAuth1FlowDialog extends AppCompatDialog { this.callbackUrl = callbackUrl; this.serviceUrlIdentifier = serviceUrlIdentifier; this.handler = resultHandler; - this.setOnCancelListener(new OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - handler.onCancel(); - } - }); + this.setOnCancelListener(dialog -> handler.onCancel()); } @SuppressLint("SetJavaScriptEnabled") diff --git a/twitter/src/main/java/com/parse/twitter/ParseTwitterUtils.java b/twitter/src/main/java/com/parse/twitter/ParseTwitterUtils.java index fcc9f051d..84ccc44f9 100644 --- a/twitter/src/main/java/com/parse/twitter/ParseTwitterUtils.java +++ b/twitter/src/main/java/com/parse/twitter/ParseTwitterUtils.java @@ -15,14 +15,13 @@ import com.parse.ParseException; import com.parse.ParseUser; import com.parse.SaveCallback; - -import java.util.Map; -import java.util.concurrent.CancellationException; - import com.parse.boltsinternal.AggregateException; import com.parse.boltsinternal.Continuation; import com.parse.boltsinternal.Task; +import java.util.Map; +import java.util.concurrent.CancellationException; + /** * Provides a set of utilities for using Parse with Twitter. */ @@ -36,6 +35,10 @@ public final class ParseTwitterUtils { static TwitterController controller; static ParseUserDelegate userDelegate = new ParseUserDelegateImpl(); + private ParseTwitterUtils() { + // do nothing + } + private static TwitterController getTwitterController() { synchronized (lock) { if (controller == null) { @@ -86,15 +89,12 @@ public static void initialize(String consumerKey, String consumerSecret, String controller.initialize(consumerKey, consumerSecret); } - userDelegate.registerAuthenticationCallback(AUTH_TYPE, new AuthenticationCallback() { - @Override - public boolean onRestore(Map authData) { - try { - getTwitterController().setAuthData(authData); - return true; - } catch (Exception e) { - return false; - } + userDelegate.registerAuthenticationCallback(AUTH_TYPE, authData -> { + try { + getTwitterController().setAuthData(authData); + return true; + } catch (Exception e) { + return false; } }); @@ -127,12 +127,7 @@ public static boolean isLinked(ParseUser user) { */ public static Task linkInBackground(Context context, final ParseUser user) { checkInitialization(); - return getTwitterController().authenticateAsync(context).onSuccessTask(new Continuation, Task>() { - @Override - public Task then(Task> task) { - return user.linkWithInBackground(AUTH_TYPE, task.getResult()); - } - }); + return getTwitterController().authenticateAsync(context).onSuccessTask(task -> user.linkWithInBackground(AUTH_TYPE, task.getResult())); } /** @@ -268,12 +263,7 @@ public static void logIn(String twitterId, String screenName, String authToken, */ public static Task logInInBackground(Context context) { checkInitialization(); - return getTwitterController().authenticateAsync(context).onSuccessTask(new Continuation, Task>() { - @Override - public Task then(Task> task) { - return userDelegate.logInWithInBackground(AUTH_TYPE, task.getResult()); - } - }); + return getTwitterController().authenticateAsync(context).onSuccessTask(task -> userDelegate.logInWithInBackground(AUTH_TYPE, task.getResult())); } /** @@ -311,6 +301,8 @@ public static Task unlinkInBackground(ParseUser user) { return user.unlinkFromInBackground(AUTH_TYPE); } + //region TaskUtils + /** * Unlinks a user from a Twitter account in the background. Unlinking a user will save the user's * data. @@ -323,8 +315,6 @@ public static void unlinkInBackground(ParseUser user, SaveCallback callback) { callbackOnMainThreadAsync(unlinkInBackground(user), callback, false); } - //region TaskUtils - /** * Converts a task execution into a synchronous action. */ @@ -375,6 +365,8 @@ private static Task callbackOnMainThreadAsync( return callbackOnMainThreadInternalAsync(task, callback, reportCancellation); } + //endregion + /** * Calls the callback after a task completes on the main thread, returning a Task that completes * with the same result as the input task after the callback has been run. If reportCancellation @@ -386,50 +378,38 @@ private static Task callbackOnMainThreadInternalAsync( return task; } final Task.TaskCompletionSource tcs = Task.create(); - task.continueWith(new Continuation() { - @Override - public Void then(final Task task) throws Exception { - if (task.isCancelled() && !reportCancellation) { - tcs.setCancelled(); - return null; - } - Task.UI_THREAD_EXECUTOR.execute(new Runnable() { - @Override - public void run() { - try { - Exception error = task.getError(); - if (error != null && !(error instanceof ParseException)) { - error = new ParseException(error); - } - if (callback instanceof SaveCallback) { - ((SaveCallback) callback).done((ParseException) error); - } else if (callback instanceof LogInCallback) { - ((LogInCallback) callback).done( - (ParseUser) task.getResult(), (ParseException) error); - } - } finally { - if (task.isCancelled()) { - tcs.setCancelled(); - } else if (task.isFaulted()) { - tcs.setError(task.getError()); - } else { - tcs.setResult(task.getResult()); - } - } - } - }); + task.continueWith((Continuation) task1 -> { + if (task1.isCancelled() && !reportCancellation) { + tcs.setCancelled(); return null; } + Task.UI_THREAD_EXECUTOR.execute(() -> { + try { + Exception error = task1.getError(); + if (error != null && !(error instanceof ParseException)) { + error = new ParseException(error); + } + if (callback instanceof SaveCallback) { + ((SaveCallback) callback).done((ParseException) error); + } else if (callback instanceof LogInCallback) { + ((LogInCallback) callback).done( + (ParseUser) task1.getResult(), (ParseException) error); + } + } finally { + if (task1.isCancelled()) { + tcs.setCancelled(); + } else if (task1.isFaulted()) { + tcs.setError(task1.getError()); + } else { + tcs.setResult(task1.getResult()); + } + } + }); + return null; }); return tcs.getTask(); } - //endregion - - private ParseTwitterUtils() { - // do nothing - } - interface ParseUserDelegate { void registerAuthenticationCallback(String authType, AuthenticationCallback callback); diff --git a/twitter/src/main/java/com/parse/twitter/Twitter.java b/twitter/src/main/java/com/parse/twitter/Twitter.java index 2af3f4fe8..b90e430d9 100644 --- a/twitter/src/main/java/com/parse/twitter/Twitter.java +++ b/twitter/src/main/java/com/parse/twitter/Twitter.java @@ -31,12 +31,10 @@ public class Twitter { private static final String VERIFIER_PARAM = "oauth_verifier"; private static final String USER_ID_PARAM = "user_id"; private static final String SCREEN_NAME_PARAM = "screen_name"; - + private final String callbackUrl; // App configuration for enabling authentication. private String consumerKey; private String consumerSecret; - private String callbackUrl; - // User information. private String authToken; private String authTokenSecret; diff --git a/twitter/src/main/java/com/parse/twitter/TwitterController.java b/twitter/src/main/java/com/parse/twitter/TwitterController.java index 0e0665d94..ba9c7e31c 100644 --- a/twitter/src/main/java/com/parse/twitter/TwitterController.java +++ b/twitter/src/main/java/com/parse/twitter/TwitterController.java @@ -11,12 +11,11 @@ import android.content.Context; import com.parse.ParseException; +import com.parse.boltsinternal.Task; import java.util.HashMap; import java.util.Map; -import com.parse.boltsinternal.Task; - class TwitterController { private static final String CONSUMER_KEY_KEY = "consumer_key"; diff --git a/twitter/src/test/java/com/parse/twitter/ParseTwitterUtilsTest.java b/twitter/src/test/java/com/parse/twitter/ParseTwitterUtilsTest.java index 2ee17ff98..0a423bc8a 100644 --- a/twitter/src/test/java/com/parse/twitter/ParseTwitterUtilsTest.java +++ b/twitter/src/test/java/com/parse/twitter/ParseTwitterUtilsTest.java @@ -8,10 +8,23 @@ */ package com.parse.twitter; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMapOf; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import android.content.Context; import com.parse.AuthenticationCallback; import com.parse.ParseUser; +import com.parse.boltsinternal.Task; import org.junit.After; import org.junit.Before; @@ -24,20 +37,6 @@ import java.util.HashMap; import java.util.Map; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyMapOf; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - @RunWith(MockitoJUnitRunner.class) public class ParseTwitterUtilsTest { diff --git a/twitter/src/test/java/com/parse/twitter/TwitterControllerTest.java b/twitter/src/test/java/com/parse/twitter/TwitterControllerTest.java index 27879654d..6128abc9a 100644 --- a/twitter/src/test/java/com/parse/twitter/TwitterControllerTest.java +++ b/twitter/src/test/java/com/parse/twitter/TwitterControllerTest.java @@ -8,8 +8,20 @@ */ package com.parse.twitter; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + import android.content.Context; +import com.parse.boltsinternal.Task; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -20,18 +32,6 @@ import java.util.HashMap; import java.util.Map; -import com.parse.boltsinternal.Task; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - @RunWith(MockitoJUnitRunner.class) public class TwitterControllerTest {