Prepare bolts to be safe to use it from Kotlin

Summary:
In this diff I analyzed bolts library to ensure it's ready to be used from kotlin.
I won't convert bolts to kotlin, but this is necessary to be able to convert its callsites (ReactHost) to kotlin

bypass-github-export-checks

changelog: [internal] internal

Reviewed By: fkgozali

Differential Revision: D46194127

fbshipit-source-id: 609e356230b1c87fe26571b811d23430d0168276
This commit is contained in:
David Vacca
2023-05-30 13:13:36 -07:00
committed by Facebook GitHub Bot
parent 88eef42cab
commit dfb42a3946
12 changed files with 82 additions and 53 deletions
@@ -7,6 +7,8 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -24,7 +26,7 @@ public class AggregateException extends Exception {
private static final String DEFAULT_MESSAGE = "There were multiple errors.";
private List<Throwable> innerThrowables;
@NonNull private final List<Throwable> innerThrowables;
/**
* Constructs a new {@code AggregateException} with the current stack trace, the specified detail
@@ -33,7 +35,7 @@ public class AggregateException extends Exception {
* @param detailMessage The detail message for this exception.
* @param innerThrowables The exceptions that are the cause of the current exception.
*/
public AggregateException(String detailMessage, Throwable[] innerThrowables) {
public AggregateException(@NonNull String detailMessage, @NonNull Throwable[] innerThrowables) {
this(detailMessage, Arrays.asList(innerThrowables));
}
@@ -44,11 +46,13 @@ public class AggregateException extends Exception {
* @param detailMessage The detail message for this exception.
* @param innerThrowables The exceptions that are the cause of the current exception.
*/
public AggregateException(String detailMessage, List<? extends Throwable> innerThrowables) {
public AggregateException(
@NonNull String detailMessage, @Nullable List<? extends Throwable> innerThrowables) {
super(
detailMessage,
innerThrowables != null && innerThrowables.size() > 0 ? innerThrowables.get(0) : null);
this.innerThrowables = Collections.unmodifiableList(innerThrowables);
this.innerThrowables =
Collections.unmodifiableList(innerThrowables != null ? innerThrowables : new ArrayList<>());
}
/**
@@ -57,7 +61,7 @@ public class AggregateException extends Exception {
*
* @param innerThrowables The exceptions that are the cause of the current exception.
*/
public AggregateException(List<? extends Throwable> innerThrowables) {
public AggregateException(@Nullable List<? extends Throwable> innerThrowables) {
this(DEFAULT_MESSAGE, innerThrowables);
}
@@ -65,12 +69,12 @@ public class AggregateException extends Exception {
* Returns a read-only {@link List} of the {@link Throwable} instances that caused the current
* exception.
*/
public List<Throwable> getInnerThrowables() {
public @NonNull List<Throwable> getInnerThrowables() {
return innerThrowables;
}
@Override
public void printStackTrace(PrintStream err) {
public void printStackTrace(@NonNull PrintStream err) {
super.printStackTrace(err);
int currentIndex = -1;
@@ -85,7 +89,7 @@ public class AggregateException extends Exception {
}
@Override
public void printStackTrace(PrintWriter err) {
public void printStackTrace(@NonNull PrintWriter err) {
super.printStackTrace(err);
int currentIndex = -1;
@@ -101,7 +105,7 @@ public class AggregateException extends Exception {
/** @deprecated Please use {@link #getInnerThrowables()} instead. */
@Deprecated
public List<Exception> getErrors() {
public @NonNull List<Exception> getErrors() {
List<Exception> errors = new ArrayList<Exception>();
if (innerThrowables == null) {
return errors;
@@ -119,7 +123,7 @@ public class AggregateException extends Exception {
/** @deprecated Please use {@link #getInnerThrowables()} instead. */
@Deprecated
public Throwable[] getCauses() {
public @NonNull Throwable[] getCauses() {
return innerThrowables.toArray(new Throwable[innerThrowables.size()]);
}
}
@@ -11,6 +11,7 @@ import android.annotation.SuppressLint;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
@@ -32,11 +33,12 @@ import java.util.concurrent.TimeUnit;
* 0 and maxPoolSize is Integer.MAX_VALUE. This is dangerous because it can create an unchecked
* amount of threads.
*/
/* package */ final class AndroidExecutors {
/* package */
final class AndroidExecutors {
private static final AndroidExecutors INSTANCE = new AndroidExecutors();
private final Executor uiThread;
@NonNull private final Executor uiThread;
private AndroidExecutors() {
uiThread = new UIThreadExecutor();
@@ -64,7 +66,7 @@ import java.util.concurrent.TimeUnit;
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
public static @NonNull ExecutorService newCachedThreadPool() {
ThreadPoolExecutor executor =
new ThreadPoolExecutor(
CORE_POOL_SIZE,
@@ -89,7 +91,7 @@ import java.util.concurrent.TimeUnit;
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
public static @NonNull ExecutorService newCachedThreadPool(@NonNull ThreadFactory threadFactory) {
ThreadPoolExecutor executor =
new ThreadPoolExecutor(
CORE_POOL_SIZE,
@@ -114,21 +116,21 @@ import java.util.concurrent.TimeUnit;
* @param value true if should time out, else false
*/
@SuppressLint("NewApi")
public static void allowCoreThreadTimeout(ThreadPoolExecutor executor, boolean value) {
public static void allowCoreThreadTimeout(@NonNull ThreadPoolExecutor executor, boolean value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
executor.allowCoreThreadTimeOut(value);
}
}
/** An {@link java.util.concurrent.Executor} that executes tasks on the UI thread. */
public static Executor uiThread() {
public static @NonNull Executor uiThread() {
return INSTANCE.uiThread;
}
/** An {@link java.util.concurrent.Executor} that runs tasks on the UI thread. */
private static class UIThreadExecutor implements Executor {
@Override
public void execute(Runnable command) {
public void execute(@NonNull Runnable command) {
new Handler(Looper.getMainLooper()).post(command);
}
}
@@ -7,6 +7,7 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.NonNull;
import java.util.Locale;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
@@ -14,7 +15,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/** Collection of {@link Executor}s to use in conjunction with {@link Task}. */
/* package */ final class BoltsExecutors {
/* package */
final class BoltsExecutors {
private static final BoltsExecutors INSTANCE = new BoltsExecutors();
@@ -26,9 +28,9 @@ import java.util.concurrent.ScheduledExecutorService;
return javaRuntimeName.toLowerCase(Locale.US).contains("android");
}
private final ExecutorService background;
private final ScheduledExecutorService scheduled;
private final Executor immediate;
private final @NonNull ExecutorService background;
private final @NonNull ScheduledExecutorService scheduled;
private final @NonNull Executor immediate;
private BoltsExecutors() {
background =
@@ -40,11 +42,11 @@ import java.util.concurrent.ScheduledExecutorService;
}
/** An {@link java.util.concurrent.Executor} that executes tasks in parallel. */
public static ExecutorService background() {
public static @NonNull ExecutorService background() {
return INSTANCE.background;
}
/* package */ static ScheduledExecutorService scheduled() {
/* package */ static @NonNull ScheduledExecutorService scheduled() {
return INSTANCE.scheduled;
}
@@ -53,7 +55,7 @@ import java.util.concurrent.ScheduledExecutorService;
* stack runs too deep, at which point it will delegate to {@link BoltsExecutors#background} in
* order to trim the stack.
*/
/* package */ static Executor immediate() {
/* package */ static @NonNull Executor immediate() {
return INSTANCE.immediate;
}
@@ -102,7 +104,7 @@ import java.util.concurrent.ScheduledExecutorService;
}
@Override
public void execute(Runnable command) {
public void execute(@NonNull Runnable command) {
int depth = incrementDepth();
try {
if (depth <= MAX_DEPTH) {
@@ -7,6 +7,7 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.NonNull;
import java.util.Locale;
import java.util.concurrent.CancellationException;
@@ -29,7 +30,7 @@ public class CancellationToken {
private final CancellationTokenSource tokenSource;
/* package */ CancellationToken(CancellationTokenSource tokenSource) {
/* package */ CancellationToken(@NonNull CancellationTokenSource tokenSource) {
this.tokenSource = tokenSource;
}
@@ -49,7 +50,7 @@ public class CancellationToken {
* @return a {@link CancellationTokenRegistration} instance that can be used to unregister the
* action.
*/
public CancellationTokenRegistration register(Runnable action) {
public @NonNull CancellationTokenRegistration register(@NonNull Runnable action) {
return tokenSource.register(action);
}
@@ -7,6 +7,8 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.Closeable;
/**
@@ -17,12 +19,12 @@ import java.io.Closeable;
public class CancellationTokenRegistration implements Closeable {
private final Object lock = new Object();
private CancellationTokenSource tokenSource;
private Runnable action;
private @Nullable CancellationTokenSource tokenSource;
private @Nullable Runnable action;
private boolean closed;
/* package */ CancellationTokenRegistration(
CancellationTokenSource tokenSource, Runnable action) {
@NonNull CancellationTokenSource tokenSource, @NonNull Runnable action) {
this.tokenSource = tokenSource;
this.action = action;
}
@@ -7,6 +7,8 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
@@ -27,9 +29,9 @@ import java.util.concurrent.TimeUnit;
public class CancellationTokenSource implements Closeable {
private final Object lock = new Object();
private final List<CancellationTokenRegistration> registrations = new ArrayList<>();
private final ScheduledExecutorService executor = BoltsExecutors.scheduled();
private ScheduledFuture<?> scheduledCancellation;
private final @NonNull List<CancellationTokenRegistration> registrations = new ArrayList<>();
private final @NonNull ScheduledExecutorService executor = BoltsExecutors.scheduled();
@Nullable private ScheduledFuture<?> scheduledCancellation;
private boolean cancellationRequested;
private boolean closed;
@@ -48,7 +50,7 @@ public class CancellationTokenSource implements Closeable {
}
/** @return the token that can be passed to asynchronous method to control cancellation. */
public CancellationToken getToken() {
public @NonNull CancellationToken getToken() {
synchronized (lock) {
throwIfClosed();
return new CancellationToken(this);
@@ -84,7 +86,7 @@ public class CancellationTokenSource implements Closeable {
cancelAfter(delay, TimeUnit.MILLISECONDS);
}
private void cancelAfter(long delay, TimeUnit timeUnit) {
private void cancelAfter(long delay, @NonNull TimeUnit timeUnit) {
if (delay < -1) {
throw new IllegalArgumentException("Delay must be >= -1");
}
@@ -137,7 +139,8 @@ public class CancellationTokenSource implements Closeable {
}
}
/* package */ CancellationTokenRegistration register(Runnable action) {
/* package */ @NonNull
CancellationTokenRegistration register(@NonNull Runnable action) {
CancellationTokenRegistration ctr;
synchronized (lock) {
throwIfClosed();
@@ -165,7 +168,7 @@ public class CancellationTokenSource implements Closeable {
}
}
/* package */ void unregister(CancellationTokenRegistration registration) {
/* package */ void unregister(@NonNull CancellationTokenRegistration registration) {
synchronized (lock) {
throwIfClosed();
registrations.remove(registration);
@@ -178,7 +181,7 @@ public class CancellationTokenSource implements Closeable {
// to be synchronized with state changes you should provide external synchronization.
// If this is invoked without external synchronization there is a probability the token becomes
// cancelled concurrently.
private void notifyListeners(List<CancellationTokenRegistration> registrations) {
private void notifyListeners(@NonNull List<CancellationTokenRegistration> registrations) {
for (CancellationTokenRegistration registration : registrations) {
registration.runAction();
}
@@ -7,25 +7,27 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.Nullable;
/**
* Provides a class that can be used for capturing variables in an anonymous class implementation.
*
* @param <T>
*/
public class Capture<T> {
private T value;
private @Nullable T value;
public Capture() {}
public Capture(T value) {
public Capture(@Nullable T value) {
this.value = value;
}
public T get() {
public @Nullable T get() {
return value;
}
public void set(T value) {
public void set(@Nullable T value) {
this.value = value;
}
}
@@ -7,6 +7,9 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* A function to be called after a task completes.
*
@@ -16,5 +19,6 @@ package com.facebook.react.bridgeless.internal.bolts;
* @see Task
*/
public interface Continuation<TTaskResult, TContinuationResult> {
TContinuationResult then(Task<TTaskResult> task) throws Exception;
@Nullable
TContinuationResult then(@NonNull Task<TTaskResult> task) throws Exception;
}
@@ -7,13 +7,15 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.Nullable;
/**
* This is a wrapper class for emphasizing that task failed due to bad {@code Executor}, rather than
* the continuation block it self.
*/
public class ExecutorException extends RuntimeException {
public ExecutorException(Exception e) {
public ExecutorException(@Nullable Exception e) {
super("An exception was thrown by an Executor", e);
}
}
@@ -7,6 +7,9 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
/**
* Allows safe orchestration of a task's completion, preventing the consumer from prematurely
* completing the task. Essentially, it represents the producer side of a Task<TResult>, providing
@@ -15,7 +18,7 @@ package com.facebook.react.bridgeless.internal.bolts;
*/
public class TaskCompletionSource<TResult> {
private final Task<TResult> task;
@NonNull private final Task<TResult> task;
/**
* Creates a TaskCompletionSource that orchestrates a Task. This allows the creator of a task to
@@ -26,7 +29,7 @@ public class TaskCompletionSource<TResult> {
}
/** @return the Task associated with this TaskCompletionSource. */
public Task<TResult> getTask() {
public @NonNull Task<TResult> getTask() {
return task;
}
@@ -36,12 +39,12 @@ public class TaskCompletionSource<TResult> {
}
/** Sets the result on the Task if the Task hasn't already been completed. */
public boolean trySetResult(TResult result) {
public boolean trySetResult(@Nullable TResult result) {
return task.trySetResult(result);
}
/** Sets the error on the Task if the Task hasn't already been completed. */
public boolean trySetError(Exception error) {
public boolean trySetError(@Nullable Exception error) {
return task.trySetError(error);
}
@@ -53,14 +56,14 @@ public class TaskCompletionSource<TResult> {
}
/** Sets the result of the Task, throwing if the Task has already been completed. */
public void setResult(TResult result) {
public void setResult(@Nullable TResult result) {
if (!trySetResult(result)) {
throw new IllegalStateException("Cannot set the result of a completed task.");
}
}
/** Sets the error of the Task, throwing if the Task has already been completed. */
public void setError(Exception error) {
public void setError(@Nullable Exception error) {
if (!trySetError(error)) {
throw new IllegalStateException("Cannot set the error on a completed task.");
}
@@ -7,15 +7,17 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.Nullable;
/**
* This class is used to retain a faulted task until either its error is observed or it is
* finalized. If it is finalized with a task, then the uncaught exception handler is exected with an
* UnobservedTaskException.
*/
class UnobservedErrorNotifier {
private Task<?> task;
@Nullable private Task<?> task;
public UnobservedErrorNotifier(Task<?> task) {
public UnobservedErrorNotifier(@Nullable Task<?> task) {
this.task = task;
}
@@ -7,9 +7,11 @@
package com.facebook.react.bridgeless.internal.bolts;
import androidx.annotation.Nullable;
/** Used to signify that a Task's error went unobserved. */
public class UnobservedTaskException extends RuntimeException {
public UnobservedTaskException(Throwable cause) {
public UnobservedTaskException(@Nullable Throwable cause) {
super(cause);
}
}