Remove APIs marked as deprecated for removal
Closes gh-33809
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -35,9 +35,10 @@ import org.springframework.util.ResourceUtils;
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
* @since 6.0
|
||||
*/
|
||||
public class FilePatternResourceHintsRegistrar {
|
||||
public final class FilePatternResourceHintsRegistrar {
|
||||
|
||||
private final List<String> classpathLocations;
|
||||
|
||||
@@ -46,26 +47,16 @@ public class FilePatternResourceHintsRegistrar {
|
||||
private final List<String> fileExtensions;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new instance for the specified file prefixes, classpath locations,
|
||||
* and file extensions.
|
||||
* @param filePrefixes the file prefixes
|
||||
* @param classpathLocations the classpath locations
|
||||
* @param fileExtensions the file extensions (starting with a dot)
|
||||
* @deprecated as of 6.0.12 in favor of {@linkplain #forClassPathLocations(String...) the builder}
|
||||
*/
|
||||
@Deprecated(since = "6.0.12", forRemoval = true)
|
||||
public FilePatternResourceHintsRegistrar(List<String> filePrefixes, List<String> classpathLocations,
|
||||
private FilePatternResourceHintsRegistrar(List<String> filePrefixes, List<String> classpathLocations,
|
||||
List<String> fileExtensions) {
|
||||
|
||||
this.classpathLocations = validateClasspathLocations(classpathLocations);
|
||||
this.classpathLocations = validateClassPathLocations(classpathLocations);
|
||||
this.filePrefixes = validateFilePrefixes(filePrefixes);
|
||||
this.fileExtensions = validateFileExtensions(fileExtensions);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated(since = "6.0.12", forRemoval = true)
|
||||
public void registerHints(ResourceHints hints, @Nullable ClassLoader classLoader) {
|
||||
private void registerHints(ResourceHints hints, @Nullable ClassLoader classLoader) {
|
||||
ClassLoader classLoaderToUse = (classLoader != null ? classLoader : getClass().getClassLoader());
|
||||
List<String> includes = new ArrayList<>();
|
||||
for (String location : this.classpathLocations) {
|
||||
@@ -85,7 +76,7 @@ public class FilePatternResourceHintsRegistrar {
|
||||
|
||||
/**
|
||||
* Configure the registrar with the specified
|
||||
* {@linkplain Builder#withClasspathLocations(String...) classpath locations}.
|
||||
* {@linkplain Builder#withClassPathLocations(String...) classpath locations}.
|
||||
* @param classpathLocations the classpath locations
|
||||
* @return a {@link Builder} to further configure the registrar
|
||||
* @since 6.0.12
|
||||
@@ -97,17 +88,17 @@ public class FilePatternResourceHintsRegistrar {
|
||||
|
||||
/**
|
||||
* Configure the registrar with the specified
|
||||
* {@linkplain Builder#withClasspathLocations(List) classpath locations}.
|
||||
* {@linkplain Builder#withClassPathLocations(List) classpath locations}.
|
||||
* @param classpathLocations the classpath locations
|
||||
* @return a {@link Builder} to further configure the registrar
|
||||
* @since 6.0.12
|
||||
* @see #forClassPathLocations(String...)
|
||||
*/
|
||||
public static Builder forClassPathLocations(List<String> classpathLocations) {
|
||||
return new Builder().withClasspathLocations(classpathLocations);
|
||||
return new Builder().withClassPathLocations(classpathLocations);
|
||||
}
|
||||
|
||||
private static List<String> validateClasspathLocations(List<String> classpathLocations) {
|
||||
private static List<String> validateClassPathLocations(List<String> classpathLocations) {
|
||||
Assert.notEmpty(classpathLocations, "At least one classpath location must be specified");
|
||||
List<String> parsedLocations = new ArrayList<>();
|
||||
for (String location : classpathLocations) {
|
||||
@@ -162,15 +153,20 @@ public class FilePatternResourceHintsRegistrar {
|
||||
|
||||
/**
|
||||
* Consider the specified classpath locations.
|
||||
* <p>A location can either be a special {@value ResourceUtils#CLASSPATH_URL_PREFIX}
|
||||
* pseudo location or a standard location, such as {@code com/example/resources}.
|
||||
* An empty String represents the root of the classpath.
|
||||
* @param classpathLocations the classpath locations to consider
|
||||
* @return this builder
|
||||
* @see #withClasspathLocations(List)
|
||||
* @deprecated in favor of {@link #withClassPathLocations(String...)}
|
||||
*/
|
||||
@Deprecated(since = "7.0", forRemoval = true)
|
||||
public Builder withClasspathLocations(String... classpathLocations) {
|
||||
return withClasspathLocations(Arrays.asList(classpathLocations));
|
||||
return withClassPathLocations(Arrays.asList(classpathLocations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider the specified classpath locations.
|
||||
* @deprecated in favor of {@link #withClassPathLocations(List)}
|
||||
*/
|
||||
@Deprecated(since = "7.0", forRemoval = true)
|
||||
public Builder withClasspathLocations(List<String> classpathLocations) {
|
||||
return withClassPathLocations(classpathLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,10 +176,25 @@ public class FilePatternResourceHintsRegistrar {
|
||||
* An empty String represents the root of the classpath.
|
||||
* @param classpathLocations the classpath locations to consider
|
||||
* @return this builder
|
||||
* @see #withClasspathLocations(String...)
|
||||
* @since 7.0
|
||||
* @see #withClassPathLocations(List)
|
||||
*/
|
||||
public Builder withClasspathLocations(List<String> classpathLocations) {
|
||||
this.classpathLocations.addAll(validateClasspathLocations(classpathLocations));
|
||||
public Builder withClassPathLocations(String... classpathLocations) {
|
||||
return withClassPathLocations(Arrays.asList(classpathLocations));
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider the specified classpath locations.
|
||||
* <p>A location can either be a special {@value ResourceUtils#CLASSPATH_URL_PREFIX}
|
||||
* pseudo location or a standard location, such as {@code com/example/resources}.
|
||||
* An empty String represents the root of the classpath.
|
||||
* @param classpathLocations the classpath locations to consider
|
||||
* @return this builder
|
||||
* @since 7.0
|
||||
* @see #withClassPathLocations(String...)
|
||||
*/
|
||||
public Builder withClassPathLocations(List<String> classpathLocations) {
|
||||
this.classpathLocations.addAll(validateClassPathLocations(classpathLocations));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -235,7 +246,6 @@ public class FilePatternResourceHintsRegistrar {
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private FilePatternResourceHintsRegistrar build() {
|
||||
return new FilePatternResourceHintsRegistrar(this.filePrefixes,
|
||||
this.classpathLocations, this.fileExtensions);
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.task;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* Extension of the {@link AsyncTaskExecutor} interface, adding the capability to submit
|
||||
* tasks for {@code ListenableFutures}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link AsyncTaskExecutor#submitCompletable(Runnable)} and
|
||||
* {@link AsyncTaskExecutor#submitCompletable(Callable)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public interface AsyncListenableTaskExecutor extends AsyncTaskExecutor {
|
||||
|
||||
/**
|
||||
* Submit a {@code Runnable} task for execution, receiving a {@code ListenableFuture}
|
||||
* representing that task. The Future will return a {@code null} result upon completion.
|
||||
* @param task the {@code Runnable} to execute (never {@code null})
|
||||
* @return a {@code ListenableFuture} representing pending completion of the task
|
||||
* @throws TaskRejectedException if the given task was not accepted
|
||||
* @deprecated in favor of {@link AsyncTaskExecutor#submitCompletable(Runnable)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
org.springframework.util.concurrent.ListenableFuture<?> submitListenable(Runnable task);
|
||||
|
||||
/**
|
||||
* Submit a {@code Callable} task for execution, receiving a {@code ListenableFuture}
|
||||
* representing that task. The Future will return the Callable's result upon
|
||||
* completion.
|
||||
* @param task the {@code Callable} to execute (never {@code null})
|
||||
* @return a {@code ListenableFuture} representing pending completion of the task
|
||||
* @throws TaskRejectedException if the given task was not accepted
|
||||
* @deprecated in favor of {@link AsyncTaskExecutor#submitCompletable(Callable)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
<T> org.springframework.util.concurrent.ListenableFuture<T> submitListenable(Callable<T> task);
|
||||
|
||||
}
|
||||
@@ -28,8 +28,6 @@ import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ConcurrencyThrottleSupport;
|
||||
import org.springframework.util.CustomizableThreadCreator;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
/**
|
||||
* {@link TaskExecutor} implementation that fires up a new Thread for each task,
|
||||
@@ -58,9 +56,9 @@ import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
* @see org.springframework.scheduling.concurrent.SimpleAsyncTaskScheduler
|
||||
* @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
|
||||
*/
|
||||
@SuppressWarnings({"serial", "removal"})
|
||||
@SuppressWarnings("serial")
|
||||
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
|
||||
implements AsyncListenableTaskExecutor, Serializable, AutoCloseable {
|
||||
implements AsyncTaskExecutor, Serializable, AutoCloseable {
|
||||
|
||||
/**
|
||||
* Permit any number of concurrent invocations: that is, don't throttle concurrency.
|
||||
@@ -294,22 +292,6 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
|
||||
return future;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public ListenableFuture<?> submitListenable(Runnable task) {
|
||||
ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
|
||||
execute(future, TIMEOUT_INDEFINITE);
|
||||
return future;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
|
||||
ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
|
||||
execute(future, TIMEOUT_INDEFINITE);
|
||||
return future;
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method for the actual execution of a task.
|
||||
* <p>The default implementation creates a new Thread and starts it.
|
||||
|
||||
@@ -23,13 +23,11 @@ import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
import org.springframework.core.task.AsyncListenableTaskExecutor;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskDecorator;
|
||||
import org.springframework.core.task.TaskRejectedException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
|
||||
/**
|
||||
* Adapter that takes a JDK {@code java.util.concurrent.Executor} and
|
||||
@@ -43,8 +41,8 @@ import org.springframework.util.concurrent.ListenableFutureTask;
|
||||
* @see java.util.concurrent.ExecutorService
|
||||
* @see java.util.concurrent.Executors
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "removal"})
|
||||
public class TaskExecutorAdapter implements AsyncListenableTaskExecutor {
|
||||
@SuppressWarnings("deprecation")
|
||||
public class TaskExecutorAdapter implements AsyncTaskExecutor {
|
||||
|
||||
private final Executor concurrentExecutor;
|
||||
|
||||
@@ -133,30 +131,6 @@ public class TaskExecutorAdapter implements AsyncListenableTaskExecutor {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<?> submitListenable(Runnable task) {
|
||||
try {
|
||||
ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
|
||||
doExecute(this.concurrentExecutor, this.taskDecorator, future);
|
||||
return future;
|
||||
}
|
||||
catch (RejectedExecutionException ex) {
|
||||
throw new TaskRejectedException(this.concurrentExecutor, task, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
|
||||
try {
|
||||
ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
|
||||
doExecute(this.concurrentExecutor, this.taskDecorator, future);
|
||||
return future;
|
||||
}
|
||||
catch (RejectedExecutionException ex) {
|
||||
throw new TaskRejectedException(this.concurrentExecutor, task, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Actually execute the given {@code Runnable} (which may be a user-supplied task
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.nio.charset.Charset;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
@@ -695,48 +694,4 @@ public class MimeType implements Comparable<MimeType>, Serializable {
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Comparator to sort {@link MimeType MimeTypes} in order of specificity.
|
||||
*
|
||||
* @param <T> the type of mime types that may be compared by this comparator
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static class SpecificityComparator<T extends MimeType> implements Comparator<T> {
|
||||
|
||||
@Override
|
||||
public int compare(T mimeType1, T mimeType2) {
|
||||
if (mimeType1.isWildcardType() && !mimeType2.isWildcardType()) { // */* < audio/*
|
||||
return 1;
|
||||
}
|
||||
else if (mimeType2.isWildcardType() && !mimeType1.isWildcardType()) { // audio/* > */*
|
||||
return -1;
|
||||
}
|
||||
else if (!mimeType1.getType().equals(mimeType2.getType())) { // audio/basic == text/html
|
||||
return 0;
|
||||
}
|
||||
else { // mediaType1.getType().equals(mediaType2.getType())
|
||||
if (mimeType1.isWildcardSubtype() && !mimeType2.isWildcardSubtype()) { // audio/* < audio/basic
|
||||
return 1;
|
||||
}
|
||||
else if (mimeType2.isWildcardSubtype() && !mimeType1.isWildcardSubtype()) { // audio/basic > audio/*
|
||||
return -1;
|
||||
}
|
||||
else if (!mimeType1.getSubtype().equals(mimeType2.getSubtype())) { // audio/basic == audio/wave
|
||||
return 0;
|
||||
}
|
||||
else { // mediaType2.getSubtype().equals(mediaType2.getSubtype())
|
||||
return compareParameters(mimeType1, mimeType2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected int compareParameters(T mimeType1, T mimeType2) {
|
||||
int paramsSize1 = mimeType1.getParameters().size();
|
||||
int paramsSize2 = mimeType2.getParameters().size();
|
||||
return Integer.compare(paramsSize2, paramsSize1); // audio/basic;level=1 < audio/basic
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,6 @@ import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@@ -51,14 +50,6 @@ public abstract class MimeTypeUtils {
|
||||
'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U',
|
||||
'V', 'W', 'X', 'Y', 'Z'};
|
||||
|
||||
/**
|
||||
* Comparator formally used by {@link #sortBySpecificity(List)}.
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@SuppressWarnings("removal")
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public static final Comparator<MimeType> SPECIFICITY_COMPARATOR = new MimeType.SpecificityComparator<>();
|
||||
|
||||
/**
|
||||
* Public constant mime type that includes all media ranges (i.e. "*/*").
|
||||
*/
|
||||
|
||||
@@ -49,24 +49,6 @@ public class PropertyPlaceholderHelper {
|
||||
this(placeholderPrefix, placeholderSuffix, null, null, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and suffix.
|
||||
* @param placeholderPrefix the prefix that denotes the start of a placeholder
|
||||
* @param placeholderSuffix the suffix that denotes the end of a placeholder
|
||||
* @param valueSeparator the separating character between the placeholder variable
|
||||
* and the associated default value, if any
|
||||
* @param ignoreUnresolvablePlaceholders indicates whether unresolvable placeholders should
|
||||
* be ignored ({@code true}) or cause an exception ({@code false})
|
||||
* @deprecated as of 6.2, in favor of
|
||||
* {@link PropertyPlaceholderHelper#PropertyPlaceholderHelper(String, String, String, Character, boolean)}
|
||||
*/
|
||||
@Deprecated(since = "6.2", forRemoval = true)
|
||||
public PropertyPlaceholderHelper(String placeholderPrefix, String placeholderSuffix,
|
||||
@Nullable String valueSeparator, boolean ignoreUnresolvablePlaceholders) {
|
||||
|
||||
this(placeholderPrefix, placeholderSuffix, valueSeparator, null, ignoreUnresolvablePlaceholders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@code PropertyPlaceholderHelper} that uses the supplied prefix and suffix.
|
||||
* @param placeholderPrefix the prefix that denotes the start of a placeholder
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionStage;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* Adapts a {@link CompletableFuture} or {@link CompletionStage} into a
|
||||
* Spring {@link ListenableFuture}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.2
|
||||
* @param <T> the result type returned by this Future's {@code get} method
|
||||
* @deprecated as of 6.0, with no concrete replacement
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public class CompletableToListenableFutureAdapter<T> implements ListenableFuture<T> {
|
||||
|
||||
private final CompletableFuture<T> completableFuture;
|
||||
|
||||
private final ListenableFutureCallbackRegistry<T> callbacks = new ListenableFutureCallbackRegistry<>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new adapter for the given {@link CompletionStage}.
|
||||
* @since 4.3.7
|
||||
*/
|
||||
public CompletableToListenableFutureAdapter(CompletionStage<T> completionStage) {
|
||||
this(completionStage.toCompletableFuture());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new adapter for the given {@link CompletableFuture}.
|
||||
*/
|
||||
public CompletableToListenableFutureAdapter(CompletableFuture<T> completableFuture) {
|
||||
this.completableFuture = completableFuture;
|
||||
this.completableFuture.whenComplete((result, ex) -> {
|
||||
if (ex != null) {
|
||||
this.callbacks.failure(ex);
|
||||
}
|
||||
else {
|
||||
this.callbacks.success(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addCallback(ListenableFutureCallback<? super T> callback) {
|
||||
this.callbacks.addCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) {
|
||||
this.callbacks.addSuccessCallback(successCallback);
|
||||
this.callbacks.addFailureCallback(failureCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<T> completable() {
|
||||
return this.completableFuture;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return this.completableFuture.cancel(mayInterruptIfRunning);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.completableFuture.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return this.completableFuture.isDone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return this.completableFuture.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return this.completableFuture.get(timeout, unit);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Failure callback for a {@link ListenableFuture}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.1
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link java.util.concurrent.CompletableFuture#whenComplete(BiConsumer)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@FunctionalInterface
|
||||
public interface FailureCallback {
|
||||
|
||||
/**
|
||||
* Called when the {@link ListenableFuture} completes with failure.
|
||||
* <p>Note that Exceptions raised by this method are ignored.
|
||||
* @param ex the failure
|
||||
*/
|
||||
void onFailure(Throwable ex);
|
||||
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Extend {@link Future} with the capability to accept completion callbacks.
|
||||
* If the future has completed when the callback is added, the callback is
|
||||
* triggered immediately.
|
||||
*
|
||||
* <p>Inspired by {@code com.google.common.util.concurrent.ListenableFuture}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @param <T> the result type returned by this Future's {@code get} method
|
||||
* @deprecated as of 6.0, in favor of {@link CompletableFuture}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
public interface ListenableFuture<T> extends Future<T> {
|
||||
|
||||
/**
|
||||
* Register the given {@code ListenableFutureCallback}.
|
||||
* @param callback the callback to register
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link CompletableFuture#whenComplete(BiConsumer)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
void addCallback(ListenableFutureCallback<? super T> callback);
|
||||
|
||||
/**
|
||||
* Java 8 lambda-friendly alternative with success and failure callbacks.
|
||||
* @param successCallback the success callback
|
||||
* @param failureCallback the failure callback
|
||||
* @since 4.1
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link CompletableFuture#whenComplete(BiConsumer)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback);
|
||||
|
||||
|
||||
/**
|
||||
* Expose this {@link ListenableFuture} as a JDK {@link CompletableFuture}.
|
||||
* @since 5.0
|
||||
*/
|
||||
@SuppressWarnings("NullAway")
|
||||
default CompletableFuture<T> completable() {
|
||||
CompletableFuture<T> completable = new DelegatingCompletableFuture<>(this);
|
||||
addCallback(completable::complete, completable::completeExceptionally);
|
||||
return completable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract class that adapts a {@link ListenableFuture} parameterized over S into a
|
||||
* {@code ListenableFuture} parameterized over T. All methods are delegated to the
|
||||
* adaptee, where {@link #get()}, {@link #get(long, java.util.concurrent.TimeUnit)},
|
||||
* and {@link ListenableFutureCallback#onSuccess(Object)} call {@link #adapt(Object)}
|
||||
* on the adaptee's result.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @param <T> the type of this {@code Future}
|
||||
* @param <S> the type of the adaptee's {@code Future}
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link java.util.concurrent.CompletableFuture}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public abstract class ListenableFutureAdapter<T, S> extends FutureAdapter<T, S> implements ListenableFuture<T> {
|
||||
|
||||
/**
|
||||
* Construct a new {@code ListenableFutureAdapter} with the given adaptee.
|
||||
* @param adaptee the future to adapt to
|
||||
*/
|
||||
protected ListenableFutureAdapter(ListenableFuture<S> adaptee) {
|
||||
super(adaptee);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addCallback(final ListenableFutureCallback<? super T> callback) {
|
||||
addCallback(callback, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(final SuccessCallback<? super T> successCallback, final FailureCallback failureCallback) {
|
||||
ListenableFuture<S> listenableAdaptee = (ListenableFuture<S>) getAdaptee();
|
||||
listenableAdaptee.addCallback(new ListenableFutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable S result) {
|
||||
T adapted = null;
|
||||
if (result != null) {
|
||||
try {
|
||||
adapted = adaptInternal(result);
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
onFailure(cause != null ? cause : ex);
|
||||
return;
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
onFailure(ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
successCallback.onSuccess(adapted);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
failureCallback.onFailure(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
/**
|
||||
* Callback mechanism for the outcome, success or failure, from a
|
||||
* {@link ListenableFuture}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.0
|
||||
* @param <T> the result type
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link java.util.concurrent.CompletableFuture#whenComplete(BiConsumer)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public interface ListenableFutureCallback<T> extends SuccessCallback<T>, FailureCallback {
|
||||
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Helper class for {@link ListenableFuture} implementations that maintains a queue
|
||||
* of success and failure callbacks and helps to notify them.
|
||||
*
|
||||
* <p>Inspired by {@code com.google.common.util.concurrent.ExecutionList}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
* @param <T> the callback result type
|
||||
* @deprecated as of 6.0, with no concrete replacement
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public class ListenableFutureCallbackRegistry<T> {
|
||||
|
||||
private final Queue<SuccessCallback<? super T>> successCallbacks = new ArrayDeque<>(1);
|
||||
|
||||
private final Queue<FailureCallback> failureCallbacks = new ArrayDeque<>(1);
|
||||
|
||||
private State state = State.NEW;
|
||||
|
||||
@Nullable
|
||||
private Object result;
|
||||
|
||||
private final Object mutex = new Object();
|
||||
|
||||
|
||||
/**
|
||||
* Add the given callback to this registry.
|
||||
* @param callback the callback to add
|
||||
*/
|
||||
public void addCallback(ListenableFutureCallback<? super T> callback) {
|
||||
Assert.notNull(callback, "'callback' must not be null");
|
||||
synchronized (this.mutex) {
|
||||
switch (this.state) {
|
||||
case NEW -> {
|
||||
this.successCallbacks.add(callback);
|
||||
this.failureCallbacks.add(callback);
|
||||
}
|
||||
case SUCCESS -> notifySuccess(callback);
|
||||
case FAILURE -> notifyFailure(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void notifySuccess(SuccessCallback<? super T> callback) {
|
||||
try {
|
||||
callback.onSuccess((T) this.result);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyFailure(FailureCallback callback) {
|
||||
Assert.state(this.result instanceof Throwable, "No Throwable result for failure state");
|
||||
try {
|
||||
callback.onFailure((Throwable) this.result);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given success callback to this registry.
|
||||
* @param callback the success callback to add
|
||||
* @since 4.1
|
||||
*/
|
||||
public void addSuccessCallback(SuccessCallback<? super T> callback) {
|
||||
Assert.notNull(callback, "'callback' must not be null");
|
||||
synchronized (this.mutex) {
|
||||
switch (this.state) {
|
||||
case NEW -> this.successCallbacks.add(callback);
|
||||
case SUCCESS -> notifySuccess(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given failure callback to this registry.
|
||||
* @param callback the failure callback to add
|
||||
* @since 4.1
|
||||
*/
|
||||
public void addFailureCallback(FailureCallback callback) {
|
||||
Assert.notNull(callback, "'callback' must not be null");
|
||||
synchronized (this.mutex) {
|
||||
switch (this.state) {
|
||||
case NEW -> this.failureCallbacks.add(callback);
|
||||
case FAILURE -> notifyFailure(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a {@link ListenableFutureCallback#onSuccess(Object)} call on all
|
||||
* added callbacks with the given result.
|
||||
* @param result the result to trigger the callbacks with
|
||||
*/
|
||||
public void success(@Nullable T result) {
|
||||
synchronized (this.mutex) {
|
||||
this.state = State.SUCCESS;
|
||||
this.result = result;
|
||||
SuccessCallback<? super T> callback;
|
||||
while ((callback = this.successCallbacks.poll()) != null) {
|
||||
notifySuccess(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger a {@link ListenableFutureCallback#onFailure(Throwable)} call on all
|
||||
* added callbacks with the given {@code Throwable}.
|
||||
* @param ex the exception to trigger the callbacks with
|
||||
*/
|
||||
public void failure(Throwable ex) {
|
||||
synchronized (this.mutex) {
|
||||
this.state = State.FAILURE;
|
||||
this.result = ex;
|
||||
FailureCallback callback;
|
||||
while ((callback = this.failureCallbacks.poll()) != null) {
|
||||
notifyFailure(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private enum State {NEW, SUCCESS, FAILURE}
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Extension of {@link FutureTask} that implements {@link ListenableFuture}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 4.0
|
||||
* @param <T> the result type returned by this Future's {@code get} method
|
||||
* @deprecated as of 6.0, with no concrete replacement
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public class ListenableFutureTask<T> extends FutureTask<T> implements ListenableFuture<T> {
|
||||
|
||||
private final ListenableFutureCallbackRegistry<T> callbacks = new ListenableFutureCallbackRegistry<>();
|
||||
|
||||
|
||||
/**
|
||||
* Create a new {@code ListenableFutureTask} that will, upon running,
|
||||
* execute the given {@link Callable}.
|
||||
* @param callable the callable task
|
||||
*/
|
||||
public ListenableFutureTask(Callable<T> callable) {
|
||||
super(callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ListenableFutureTask} that will, upon running,
|
||||
* execute the given {@link Runnable}, and arrange that {@link #get()}
|
||||
* will return the given result on successful completion.
|
||||
* @param runnable the runnable task
|
||||
* @param result the result to return on successful completion
|
||||
*/
|
||||
public ListenableFutureTask(Runnable runnable, @Nullable T result) {
|
||||
super(runnable, result);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addCallback(ListenableFutureCallback<? super T> callback) {
|
||||
this.callbacks.addCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) {
|
||||
this.callbacks.addSuccessCallback(successCallback);
|
||||
this.callbacks.addFailureCallback(failureCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public CompletableFuture<T> completable() {
|
||||
CompletableFuture<T> completable = new DelegatingCompletableFuture<>(this);
|
||||
this.callbacks.addSuccessCallback(completable::complete);
|
||||
this.callbacks.addFailureCallback(completable::completeExceptionally);
|
||||
return completable;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
Throwable cause;
|
||||
try {
|
||||
T result = get();
|
||||
this.callbacks.success(result);
|
||||
return;
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
Thread.currentThread().interrupt();
|
||||
return;
|
||||
}
|
||||
catch (ExecutionException ex) {
|
||||
cause = ex.getCause();
|
||||
if (cause == null) {
|
||||
cause = ex;
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
cause = ex;
|
||||
}
|
||||
this.callbacks.failure(cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
/**
|
||||
* Adapts a {@link Mono} into a {@link ListenableFuture} by obtaining a
|
||||
* {@code CompletableFuture} from the {@code Mono} via {@link Mono#toFuture()}
|
||||
* and then adapting it with {@link CompletableToListenableFutureAdapter}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Stephane Maldini
|
||||
* @since 5.1
|
||||
* @param <T> the object type
|
||||
* @deprecated as of 6.0, in favor of {@link Mono#toFuture()}
|
||||
*/
|
||||
@Deprecated(since = "6.0")
|
||||
@SuppressWarnings("removal")
|
||||
public class MonoToListenableFutureAdapter<T> extends CompletableToListenableFutureAdapter<T> {
|
||||
|
||||
public MonoToListenableFutureAdapter(Mono<T> mono) {
|
||||
super(mono.toFuture());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link ListenableFuture} whose value can be set via {@link #set(Object)}
|
||||
* or {@link #setException(Throwable)}. It may also get cancelled.
|
||||
*
|
||||
* <p>Inspired by {@code com.google.common.util.concurrent.SettableFuture}.
|
||||
*
|
||||
* @author Mattias Severson
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.1
|
||||
* @param <T> the result type returned by this Future's {@code get} method
|
||||
* @deprecated as of 6.0, in favor of {@link CompletableFuture}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@SuppressWarnings("removal")
|
||||
public class SettableListenableFuture<T> implements ListenableFuture<T> {
|
||||
|
||||
private static final Callable<Object> DUMMY_CALLABLE = () -> {
|
||||
throw new IllegalStateException("Should never be called");
|
||||
};
|
||||
|
||||
|
||||
private final SettableTask<T> settableTask = new SettableTask<>();
|
||||
|
||||
|
||||
/**
|
||||
* Set the value of this future. This method will return {@code true} if the
|
||||
* value was set successfully, or {@code false} if the future has already been
|
||||
* set or cancelled.
|
||||
* @param value the value that will be set
|
||||
* @return {@code true} if the value was successfully set, else {@code false}
|
||||
*/
|
||||
public boolean set(@Nullable T value) {
|
||||
return this.settableTask.setResultValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the exception of this future. This method will return {@code true} if the
|
||||
* exception was set successfully, or {@code false} if the future has already been
|
||||
* set or cancelled.
|
||||
* @param exception the value that will be set
|
||||
* @return {@code true} if the exception was successfully set, else {@code false}
|
||||
*/
|
||||
public boolean setException(Throwable exception) {
|
||||
Assert.notNull(exception, "Exception must not be null");
|
||||
return this.settableTask.setExceptionResult(exception);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addCallback(ListenableFutureCallback<? super T> callback) {
|
||||
this.settableTask.addCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) {
|
||||
this.settableTask.addCallback(successCallback, failureCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<T> completable() {
|
||||
return this.settableTask.completable();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
boolean cancelled = this.settableTask.cancel(mayInterruptIfRunning);
|
||||
if (cancelled && mayInterruptIfRunning) {
|
||||
interruptTask();
|
||||
}
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return this.settableTask.isCancelled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDone() {
|
||||
return this.settableTask.isDone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value.
|
||||
* <p>This method returns the value if it has been set via {@link #set(Object)},
|
||||
* throws an {@link java.util.concurrent.ExecutionException} if an exception has
|
||||
* been set via {@link #setException(Throwable)}, or throws a
|
||||
* {@link java.util.concurrent.CancellationException} if the future has been cancelled.
|
||||
* @return the value associated with this future
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public T get() throws InterruptedException, ExecutionException {
|
||||
return this.settableTask.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value.
|
||||
* <p>This method returns the value if it has been set via {@link #set(Object)},
|
||||
* throws an {@link java.util.concurrent.ExecutionException} if an exception has
|
||||
* been set via {@link #setException(Throwable)}, or throws a
|
||||
* {@link java.util.concurrent.CancellationException} if the future has been cancelled.
|
||||
* @param timeout the maximum time to wait
|
||||
* @param unit the unit of the timeout argument
|
||||
* @return the value associated with this future
|
||||
*/
|
||||
@Nullable
|
||||
@Override
|
||||
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
return this.settableTask.get(timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this method to implement interruption of the future's
|
||||
* computation. The method is invoked automatically by a successful call to
|
||||
* {@link #cancel(boolean) cancel(true)}.
|
||||
* <p>The default implementation is empty.
|
||||
*/
|
||||
protected void interruptTask() {
|
||||
}
|
||||
|
||||
|
||||
private static class SettableTask<T> extends ListenableFutureTask<T> {
|
||||
|
||||
@Nullable
|
||||
private volatile Thread completingThread;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public SettableTask() {
|
||||
super((Callable<T>) DUMMY_CALLABLE);
|
||||
}
|
||||
|
||||
public boolean setResultValue(@Nullable T value) {
|
||||
set(value);
|
||||
return checkCompletingThread();
|
||||
}
|
||||
|
||||
public boolean setExceptionResult(Throwable exception) {
|
||||
setException(exception);
|
||||
return checkCompletingThread();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done() {
|
||||
if (!isCancelled()) {
|
||||
// Implicitly invoked by set/setException: store current thread for
|
||||
// determining whether the given result has actually triggered completion
|
||||
// (since FutureTask.set/setException unfortunately don't expose that)
|
||||
this.completingThread = Thread.currentThread();
|
||||
}
|
||||
super.done();
|
||||
}
|
||||
|
||||
private boolean checkCompletingThread() {
|
||||
boolean check = (this.completingThread == Thread.currentThread());
|
||||
if (check) {
|
||||
this.completingThread = null; // only first match actually counts
|
||||
}
|
||||
return check;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Success callback for a {@link ListenableFuture}.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @since 4.1
|
||||
* @param <T> the result type
|
||||
* @deprecated as of 6.0, in favor of
|
||||
* {@link java.util.concurrent.CompletableFuture#whenComplete(BiConsumer)}
|
||||
*/
|
||||
@Deprecated(since = "6.0", forRemoval = true)
|
||||
@FunctionalInterface
|
||||
public interface SuccessCallback<T> {
|
||||
|
||||
/**
|
||||
* Called when the {@link ListenableFuture} completes with success.
|
||||
* <p>Note that Exceptions raised by this method are ignored.
|
||||
* @param result the result
|
||||
*/
|
||||
void onSuccess(@Nullable T result);
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -78,7 +78,7 @@ class FilePatternResourceHintsRegistrarTests {
|
||||
|
||||
@Test
|
||||
void registerWithMultipleClasspathLocations() {
|
||||
FilePatternResourceHintsRegistrar.forClassPathLocations("").withClasspathLocations("META-INF")
|
||||
FilePatternResourceHintsRegistrar.forClassPathLocations("").withClassPathLocations("META-INF")
|
||||
.withFilePrefixes("test").withFileExtensions(".txt")
|
||||
.registerHints(this.hints, null);
|
||||
assertThat(this.hints.resourcePatternHints()).singleElement()
|
||||
@@ -133,7 +133,7 @@ class FilePatternResourceHintsRegistrarTests {
|
||||
@Test
|
||||
void registerWithNonExistingLocationDoesNotRegisterHint() {
|
||||
FilePatternResourceHintsRegistrar.forClassPathLocations("does-not-exist/")
|
||||
.withClasspathLocations("another-does-not-exist/")
|
||||
.withClassPathLocations("another-does-not-exist/")
|
||||
.withFilePrefixes("test").withFileExtensions(".txt")
|
||||
.registerHints(this.hints, null);
|
||||
assertThat(this.hints.resourcePatternHints()).isEmpty();
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
* @author Sebastien Deleuze
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "removal"})
|
||||
class ListenableFutureTaskTests {
|
||||
|
||||
@Test
|
||||
void success() throws Exception {
|
||||
final String s = "Hello World";
|
||||
Callable<String> callable = () -> s;
|
||||
|
||||
ListenableFutureTask<String> task = new ListenableFutureTask<>(callable);
|
||||
task.addCallback(new ListenableFutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
assertThat(result).isEqualTo(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
throw new AssertionError(ex.getMessage(), ex);
|
||||
}
|
||||
});
|
||||
task.run();
|
||||
|
||||
assertThat(task.get()).isSameAs(s);
|
||||
assertThat(task.completable().get()).isSameAs(s);
|
||||
task.completable().thenAccept(v -> assertThat(v).isSameAs(s));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failure() {
|
||||
final String s = "Hello World";
|
||||
Callable<String> callable = () -> {
|
||||
throw new IOException(s);
|
||||
};
|
||||
|
||||
ListenableFutureTask<String> task = new ListenableFutureTask<>(callable);
|
||||
task.addCallback(new ListenableFutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
fail("onSuccess not expected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
assertThat(ex.getMessage()).isEqualTo(s);
|
||||
}
|
||||
});
|
||||
task.run();
|
||||
|
||||
assertThatExceptionOfType(ExecutionException.class)
|
||||
.isThrownBy(task::get)
|
||||
.havingCause()
|
||||
.withMessage(s);
|
||||
assertThatExceptionOfType(ExecutionException.class)
|
||||
.isThrownBy(task.completable()::get)
|
||||
.havingCause()
|
||||
.withMessage(s);
|
||||
}
|
||||
|
||||
@Test
|
||||
void successWithLambdas() throws Exception {
|
||||
final String s = "Hello World";
|
||||
Callable<String> callable = () -> s;
|
||||
|
||||
SuccessCallback<String> successCallback = mock();
|
||||
FailureCallback failureCallback = mock();
|
||||
ListenableFutureTask<String> task = new ListenableFutureTask<>(callable);
|
||||
task.addCallback(successCallback, failureCallback);
|
||||
task.run();
|
||||
verify(successCallback).onSuccess(s);
|
||||
verifyNoInteractions(failureCallback);
|
||||
|
||||
assertThat(task.get()).isSameAs(s);
|
||||
assertThat(task.completable().get()).isSameAs(s);
|
||||
task.completable().thenAccept(v -> assertThat(v).isSameAs(s));
|
||||
}
|
||||
|
||||
@Test
|
||||
void failureWithLambdas() {
|
||||
final String s = "Hello World";
|
||||
IOException ex = new IOException(s);
|
||||
Callable<String> callable = () -> {
|
||||
throw ex;
|
||||
};
|
||||
|
||||
SuccessCallback<String> successCallback = mock();
|
||||
FailureCallback failureCallback = mock();
|
||||
ListenableFutureTask<String> task = new ListenableFutureTask<>(callable);
|
||||
task.addCallback(successCallback, failureCallback);
|
||||
task.run();
|
||||
verify(failureCallback).onFailure(ex);
|
||||
verifyNoInteractions(successCallback);
|
||||
|
||||
assertThatExceptionOfType(ExecutionException.class)
|
||||
.isThrownBy(task::get)
|
||||
.havingCause()
|
||||
.withMessage(s);
|
||||
assertThatExceptionOfType(ExecutionException.class)
|
||||
.isThrownBy(task.completable()::get)
|
||||
.havingCause()
|
||||
.withMessage(s);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link MonoToListenableFutureAdapter}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "removal"})
|
||||
class MonoToListenableFutureAdapterTests {
|
||||
|
||||
@Test
|
||||
void success() {
|
||||
String expected = "one";
|
||||
AtomicReference<Object> actual = new AtomicReference<>();
|
||||
ListenableFuture<String> future = new MonoToListenableFutureAdapter<>(Mono.just(expected));
|
||||
future.addCallback(actual::set, actual::set);
|
||||
|
||||
assertThat(actual.get()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
void failure() {
|
||||
Throwable expected = new IllegalStateException("oops");
|
||||
AtomicReference<Object> actual = new AtomicReference<>();
|
||||
ListenableFuture<String> future = new MonoToListenableFutureAdapter<>(Mono.error(expected));
|
||||
future.addCallback(actual::set, actual::set);
|
||||
|
||||
assertThat(actual.get()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancellation() {
|
||||
Mono<Long> mono = Mono.delay(Duration.ofSeconds(60));
|
||||
Future<Long> future = new MonoToListenableFutureAdapter<>(mono);
|
||||
|
||||
assertThat(future.cancel(true)).isTrue();
|
||||
assertThat(future.isCancelled()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancellationAfterTerminated() {
|
||||
Future<Void> future = new MonoToListenableFutureAdapter<>(Mono.empty());
|
||||
|
||||
assertThat(future.cancel(true)).as("Should return false if task already completed").isFalse();
|
||||
assertThat(future.isCancelled()).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,414 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.util.concurrent;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
/**
|
||||
* @author Mattias Severson
|
||||
* @author Juergen Hoeller
|
||||
*/
|
||||
@SuppressWarnings({"deprecation", "removal"})
|
||||
class SettableListenableFutureTests {
|
||||
|
||||
private final SettableListenableFuture<String> settableListenableFuture = new SettableListenableFuture<>();
|
||||
|
||||
|
||||
@Test
|
||||
void validateInitialValues() {
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsSetValue() throws ExecutionException, InterruptedException {
|
||||
String string = "hello";
|
||||
assertThat(settableListenableFuture.set(string)).isTrue();
|
||||
assertThat(settableListenableFuture.get()).isEqualTo(string);
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void returnsSetValueFromCompletable() throws ExecutionException, InterruptedException {
|
||||
String string = "hello";
|
||||
assertThat(settableListenableFuture.set(string)).isTrue();
|
||||
Future<String> completable = settableListenableFuture.completable();
|
||||
assertThat(completable.get()).isEqualTo(string);
|
||||
assertThat(completable.isCancelled()).isFalse();
|
||||
assertThat(completable.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setValueUpdatesDoneStatus() {
|
||||
settableListenableFuture.set("hello");
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwsSetExceptionWrappedInExecutionException() {
|
||||
Throwable exception = new RuntimeException();
|
||||
assertThat(settableListenableFuture.setException(exception)).isTrue();
|
||||
|
||||
assertThatExceptionOfType(ExecutionException.class).isThrownBy(
|
||||
settableListenableFuture::get)
|
||||
.withCause(exception);
|
||||
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwsSetExceptionWrappedInExecutionExceptionFromCompletable() {
|
||||
Throwable exception = new RuntimeException();
|
||||
assertThat(settableListenableFuture.setException(exception)).isTrue();
|
||||
Future<String> completable = settableListenableFuture.completable();
|
||||
|
||||
assertThatExceptionOfType(ExecutionException.class).isThrownBy(
|
||||
completable::get)
|
||||
.withCause(exception);
|
||||
|
||||
assertThat(completable.isCancelled()).isFalse();
|
||||
assertThat(completable.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwsSetErrorWrappedInExecutionException() {
|
||||
Throwable exception = new OutOfMemoryError();
|
||||
assertThat(settableListenableFuture.setException(exception)).isTrue();
|
||||
|
||||
assertThatExceptionOfType(ExecutionException.class).isThrownBy(
|
||||
settableListenableFuture::get)
|
||||
.withCause(exception);
|
||||
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwsSetErrorWrappedInExecutionExceptionFromCompletable() {
|
||||
Throwable exception = new OutOfMemoryError();
|
||||
assertThat(settableListenableFuture.setException(exception)).isTrue();
|
||||
Future<String> completable = settableListenableFuture.completable();
|
||||
|
||||
assertThatExceptionOfType(ExecutionException.class).isThrownBy(
|
||||
completable::get)
|
||||
.withCause(exception);
|
||||
|
||||
assertThat(completable.isCancelled()).isFalse();
|
||||
assertThat(completable.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setValueTriggersCallback() {
|
||||
String string = "hello";
|
||||
final String[] callbackHolder = new String[1];
|
||||
|
||||
settableListenableFuture.addCallback(new ListenableFutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
callbackHolder[0] = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
throw new AssertionError("Expected onSuccess() to be called", ex);
|
||||
}
|
||||
});
|
||||
|
||||
settableListenableFuture.set(string);
|
||||
assertThat(callbackHolder[0]).isEqualTo(string);
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setValueTriggersCallbackOnlyOnce() {
|
||||
String string = "hello";
|
||||
final String[] callbackHolder = new String[1];
|
||||
|
||||
settableListenableFuture.addCallback(new ListenableFutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
callbackHolder[0] = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
throw new AssertionError("Expected onSuccess() to be called", ex);
|
||||
}
|
||||
});
|
||||
|
||||
settableListenableFuture.set(string);
|
||||
assertThat(settableListenableFuture.set("good bye")).isFalse();
|
||||
assertThat(callbackHolder[0]).isEqualTo(string);
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setExceptionTriggersCallback() {
|
||||
Throwable exception = new RuntimeException();
|
||||
final Throwable[] callbackHolder = new Throwable[1];
|
||||
|
||||
settableListenableFuture.addCallback(new ListenableFutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
fail("Expected onFailure() to be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
callbackHolder[0] = ex;
|
||||
}
|
||||
});
|
||||
|
||||
settableListenableFuture.setException(exception);
|
||||
assertThat(callbackHolder[0]).isEqualTo(exception);
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setExceptionTriggersCallbackOnlyOnce() {
|
||||
Throwable exception = new RuntimeException();
|
||||
final Throwable[] callbackHolder = new Throwable[1];
|
||||
|
||||
settableListenableFuture.addCallback(new ListenableFutureCallback<>() {
|
||||
@Override
|
||||
public void onSuccess(String result) {
|
||||
fail("Expected onFailure() to be called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable ex) {
|
||||
callbackHolder[0] = ex;
|
||||
}
|
||||
});
|
||||
|
||||
settableListenableFuture.setException(exception);
|
||||
assertThat(settableListenableFuture.setException(new IllegalArgumentException())).isFalse();
|
||||
assertThat(callbackHolder[0]).isEqualTo(exception);
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullIsAcceptedAsValueToSet() throws ExecutionException, InterruptedException {
|
||||
settableListenableFuture.set(null);
|
||||
assertThat(settableListenableFuture.get()).isNull();
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWaitsForCompletion() throws ExecutionException, InterruptedException {
|
||||
final String string = "hello";
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(20L);
|
||||
settableListenableFuture.set(string);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}).start();
|
||||
|
||||
String value = settableListenableFuture.get();
|
||||
assertThat(value).isEqualTo(string);
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithTimeoutThrowsTimeoutException() {
|
||||
assertThatExceptionOfType(TimeoutException.class).isThrownBy(() ->
|
||||
settableListenableFuture.get(1L, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWithTimeoutWaitsForCompletion() throws ExecutionException, InterruptedException, TimeoutException {
|
||||
final String string = "hello";
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(20L);
|
||||
settableListenableFuture.set(string);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}).start();
|
||||
|
||||
String value = settableListenableFuture.get(500L, TimeUnit.MILLISECONDS);
|
||||
assertThat(value).isEqualTo(string);
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelPreventsValueFromBeingSet() {
|
||||
assertThat(settableListenableFuture.cancel(true)).isTrue();
|
||||
assertThat(settableListenableFuture.set("hello")).isFalse();
|
||||
assertThat(settableListenableFuture.isCancelled()).isTrue();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelSetsFutureToDone() {
|
||||
settableListenableFuture.cancel(true);
|
||||
assertThat(settableListenableFuture.isCancelled()).isTrue();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelWithMayInterruptIfRunningTrueCallsOverriddenMethod() {
|
||||
InterruptibleSettableListenableFuture interruptibleFuture = new InterruptibleSettableListenableFuture();
|
||||
assertThat(interruptibleFuture.cancel(true)).isTrue();
|
||||
assertThat(interruptibleFuture.calledInterruptTask()).isTrue();
|
||||
assertThat(interruptibleFuture.isCancelled()).isTrue();
|
||||
assertThat(interruptibleFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelWithMayInterruptIfRunningFalseDoesNotCallOverriddenMethod() {
|
||||
InterruptibleSettableListenableFuture interruptibleFuture = new InterruptibleSettableListenableFuture();
|
||||
assertThat(interruptibleFuture.cancel(false)).isTrue();
|
||||
assertThat(interruptibleFuture.calledInterruptTask()).isFalse();
|
||||
assertThat(interruptibleFuture.isCancelled()).isTrue();
|
||||
assertThat(interruptibleFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPreventsCancel() {
|
||||
assertThat(settableListenableFuture.set("hello")).isTrue();
|
||||
assertThat(settableListenableFuture.cancel(true)).isFalse();
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelPreventsExceptionFromBeingSet() {
|
||||
assertThat(settableListenableFuture.cancel(true)).isTrue();
|
||||
assertThat(settableListenableFuture.setException(new RuntimeException())).isFalse();
|
||||
assertThat(settableListenableFuture.isCancelled()).isTrue();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void setExceptionPreventsCancel() {
|
||||
assertThat(settableListenableFuture.setException(new RuntimeException())).isTrue();
|
||||
assertThat(settableListenableFuture.cancel(true)).isFalse();
|
||||
assertThat(settableListenableFuture.isCancelled()).isFalse();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelStateThrowsExceptionWhenCallingGet() {
|
||||
settableListenableFuture.cancel(true);
|
||||
|
||||
assertThatExceptionOfType(CancellationException.class).isThrownBy(settableListenableFuture::get);
|
||||
|
||||
assertThat(settableListenableFuture.isCancelled()).isTrue();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void cancelStateThrowsExceptionWhenCallingGetWithTimeout() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(20L);
|
||||
settableListenableFuture.cancel(true);
|
||||
}
|
||||
catch (InterruptedException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}).start();
|
||||
|
||||
assertThatExceptionOfType(CancellationException.class).isThrownBy(() ->
|
||||
settableListenableFuture.get(500L, TimeUnit.MILLISECONDS));
|
||||
|
||||
assertThat(settableListenableFuture.isCancelled()).isTrue();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public void cancelDoesNotNotifyCallbacksOnSet() {
|
||||
ListenableFutureCallback callback = mock();
|
||||
settableListenableFuture.addCallback(callback);
|
||||
settableListenableFuture.cancel(true);
|
||||
|
||||
verify(callback).onFailure(any(CancellationException.class));
|
||||
verifyNoMoreInteractions(callback);
|
||||
|
||||
settableListenableFuture.set("hello");
|
||||
verifyNoMoreInteractions(callback);
|
||||
|
||||
assertThat(settableListenableFuture.isCancelled()).isTrue();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public void cancelDoesNotNotifyCallbacksOnSetException() {
|
||||
ListenableFutureCallback callback = mock();
|
||||
settableListenableFuture.addCallback(callback);
|
||||
settableListenableFuture.cancel(true);
|
||||
|
||||
verify(callback).onFailure(any(CancellationException.class));
|
||||
verifyNoMoreInteractions(callback);
|
||||
|
||||
settableListenableFuture.setException(new RuntimeException());
|
||||
verifyNoMoreInteractions(callback);
|
||||
|
||||
assertThat(settableListenableFuture.isCancelled()).isTrue();
|
||||
assertThat(settableListenableFuture.isDone()).isTrue();
|
||||
}
|
||||
|
||||
|
||||
private static class InterruptibleSettableListenableFuture extends SettableListenableFuture<String> {
|
||||
|
||||
private boolean interrupted = false;
|
||||
|
||||
@Override
|
||||
protected void interruptTask() {
|
||||
interrupted = true;
|
||||
}
|
||||
|
||||
boolean calledInterruptTask() {
|
||||
return interrupted;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user