Remove APIs marked as deprecated for removal

Closes gh-33809
This commit is contained in:
Juergen Hoeller 2024-12-04 13:19:39 +01:00
parent 078d683f47
commit 2b9010c2a2
150 changed files with 141 additions and 5922 deletions

View File

@ -647,13 +647,12 @@ For https://www.webjars.org/documentation[WebJars], versioned URLs like
`/webjars/jquery/1.2.0/jquery.min.js` are the recommended and most efficient way to use them.
The related resource location is configured out of the box with Spring Boot (or can be configured
manually via `ResourceHandlerRegistry`) and does not require to add the
`org.webjars:webjars-locator-core` dependency.
`org.webjars:webjars-locator-lite` dependency.
Version-less URLs like `/webjars/jquery/jquery.min.js` are supported through the
`WebJarsResourceResolver` which is automatically registered when the
`org.webjars:webjars-locator-core` library is present on the classpath, at the cost of a
classpath scanning that could slow down application startup. The resolver can re-write URLs to
include the version of the jar and can also match against incoming URLs without versions
`org.webjars:webjars-locator-lite` library is present on the classpath. The resolver can re-write
URLs to include the version of the jar and can also match against incoming URLs without versions
-- for example, from `/webjars/jquery/jquery.min.js` to `/webjars/jquery/1.2.0/jquery.min.js`.
TIP: The Java configuration based on `ResourceHandlerRegistry` provides further options

View File

@ -48,13 +48,12 @@ For https://www.webjars.org/documentation[WebJars], versioned URLs like
`/webjars/jquery/1.2.0/jquery.min.js` are the recommended and most efficient way to use them.
The related resource location is configured out of the box with Spring Boot (or can be configured
manually via `ResourceHandlerRegistry`) and does not require to add the
`org.webjars:webjars-locator-core` dependency.
`org.webjars:webjars-locator-lite` dependency.
Version-less URLs like `/webjars/jquery/jquery.min.js` are supported through the
`WebJarsResourceResolver` which is automatically registered when the
`org.webjars:webjars-locator-core` library is present on the classpath, at the cost of a
classpath scanning that could slow down application startup. The resolver can re-write URLs to
include the version of the jar and can also match against incoming URLs without versions
`org.webjars:webjars-locator-lite` library is present on the classpath. The resolver can re-write
URLs to include the version of the jar and can also match against incoming URLs without versions
-- for example, from `/webjars/jquery/jquery.min.js` to `/webjars/jquery/1.2.0/jquery.min.js`.
TIP: The Java configuration based on `ResourceHandlerRegistry` provides further options

View File

@ -38,7 +38,6 @@ dependencies {
api("com.oracle.database.jdbc:ojdbc11:21.9.0.0")
api("com.rometools:rome:1.19.0")
api("com.squareup.okhttp3:mockwebserver:3.14.9")
api("com.squareup.okhttp3:okhttp:3.14.9")
api("com.sun.activation:jakarta.activation:2.0.1")
api("com.sun.xml.bind:jaxb-core:3.0.2")
api("com.sun.xml.bind:jaxb-impl:3.0.2")
@ -142,7 +141,6 @@ dependencies {
api("org.slf4j:slf4j-api:2.0.16")
api("org.testng:testng:7.10.2")
api("org.webjars:underscorejs:1.8.3")
api("org.webjars:webjars-locator-core:0.55")
api("org.webjars:webjars-locator-lite:1.0.0")
api("org.xmlunit:xmlunit-assertj:2.10.0")
api("org.xmlunit:xmlunit-matchers:2.10.0")

View File

@ -281,15 +281,11 @@ public abstract class AsyncExecutionAspectSupport implements BeanFactoryAware {
* @param returnType the declared return type (potentially a {@link Future} variant)
* @return the execution result (potentially a corresponding {@link Future} handle)
*/
@SuppressWarnings("removal")
@Nullable
protected Object doSubmit(Callable<Object> task, AsyncTaskExecutor executor, Class<?> returnType) {
if (CompletableFuture.class.isAssignableFrom(returnType)) {
return executor.submitCompletable(task);
}
else if (org.springframework.util.concurrent.ListenableFuture.class.isAssignableFrom(returnType)) {
return ((org.springframework.core.task.AsyncListenableTaskExecutor) executor).submitListenable(task);
}
else if (Future.class.isAssignableFrom(returnType)) {
return executor.submit(task);
}

View File

@ -35,7 +35,6 @@ import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.concurrent.ListenableFuture;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.core.testfixture.TestGroup.LONG_RUNNING;
@ -136,10 +135,7 @@ public class AnnotationAsyncExecutionAspectTests {
assertThat(defaultThread.get()).isNotEqualTo(Thread.currentThread());
assertThat(defaultThread.get().getName()).doesNotStartWith("e1-");
ListenableFuture<Thread> e1Thread = obj.e1Work();
assertThat(e1Thread.get().getName()).startsWith("e1-");
CompletableFuture<Thread> e1OtherThread = obj.e1OtherWork();
CompletableFuture<Thread> e1OtherThread = obj.e1Work();
assertThat(e1OtherThread.get().getName()).startsWith("e1-");
}
@ -269,12 +265,7 @@ public class AnnotationAsyncExecutionAspectTests {
}
@Async("e1")
public ListenableFuture<Thread> e1Work() {
return new AsyncResult<>(Thread.currentThread());
}
@Async("e1")
public CompletableFuture<Thread> e1OtherWork() {
public CompletableFuture<Thread> e1Work() {
return CompletableFuture.completedFuture(Thread.currentThread());
}
}

View File

@ -171,30 +171,6 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
return new BeanInstanceSupplier<>(this.lookup, generator, null, this.shortcutBeanNames);
}
/**
* Return a new {@link BeanInstanceSupplier} instance that uses the specified
* {@code generator} supplier to instantiate the underlying bean.
* @param generator a {@link ThrowingSupplier} to instantiate the underlying bean
* @return a new {@link BeanInstanceSupplier} instance with the specified generator
* @deprecated in favor of {@link #withGenerator(ThrowingFunction)}
*/
@Deprecated(since = "6.0.11", forRemoval = true)
public BeanInstanceSupplier<T> withGenerator(ThrowingSupplier<T> generator) {
Assert.notNull(generator, "'generator' must not be null");
return new BeanInstanceSupplier<>(this.lookup, registeredBean -> generator.get(),
null, this.shortcutBeanNames);
}
/**
* Return a new {@link BeanInstanceSupplier} instance
* that uses direct bean name injection shortcuts for specific parameters.
* @deprecated in favor of {@link #withShortcut(String...)}
*/
@Deprecated(since = "6.2", forRemoval = true)
public BeanInstanceSupplier<T> withShortcuts(String... beanNames) {
return withShortcut(beanNames);
}
/**
* Return a new {@link BeanInstanceSupplier} instance that uses
* direct bean name injection shortcuts for specific parameters.

View File

@ -55,23 +55,6 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
return currentlyInvokedFactoryMethod.get();
}
/**
* Set the factory method currently being invoked or {@code null} to remove
* the current value, if any.
* @param method the factory method currently being invoked or {@code null}
* @since 6.0
* @deprecated in favor of {@link #instantiateWithFactoryMethod(Method, Supplier)}
*/
@Deprecated(since = "6.2", forRemoval = true)
public static void setCurrentlyInvokedFactoryMethod(@Nullable Method method) {
if (method != null) {
currentlyInvokedFactoryMethod.set(method);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
/**
* Invoke the given {@code instanceSupplier} with the factory method exposed
* as being invoked.

View File

@ -62,7 +62,6 @@ import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.function.ThrowingBiFunction;
import org.springframework.util.function.ThrowingFunction;
import org.springframework.util.function.ThrowingSupplier;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -180,16 +179,6 @@ class BeanInstanceSupplierTests {
.withMessage("'generator' must not be null");
}
@Test
@Deprecated
@SuppressWarnings("removal")
void withGeneratorWhenSupplierIsNullThrowsException() {
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier.forConstructor();
assertThatIllegalArgumentException()
.isThrownBy(() -> resolver.withGenerator((ThrowingSupplier<Object>) null))
.withMessage("'generator' must not be null");
}
@Test
void getWithConstructorDoesNotSetResolvedFactoryMethod() {
BeanInstanceSupplier<SingleArgConstructor> resolver = BeanInstanceSupplier.forConstructor(String.class);
@ -236,18 +225,6 @@ class BeanInstanceSupplierTests {
assertThat(resolver.get(registerBean)).isInstanceOf(String.class).isEqualTo("1");
}
@Test
@Deprecated
@SuppressWarnings("removal")
void getWithGeneratorCallsSupplier() {
BeanRegistrar registrar = new BeanRegistrar(SingleArgConstructor.class);
this.beanFactory.registerSingleton("one", "1");
RegisteredBean registerBean = registrar.registerBean(this.beanFactory);
BeanInstanceSupplier<String> resolver = BeanInstanceSupplier.<String>forConstructor(String.class)
.withGenerator(() -> "1");
assertThat(resolver.get(registerBean)).isInstanceOf(String.class).isEqualTo("1");
}
@Test
void getWhenRegisteredBeanIsNullThrowsException() {
BeanInstanceSupplier<Object> resolver = BeanInstanceSupplier.forConstructor(String.class);

View File

@ -25,12 +25,10 @@ import org.quartz.simpl.SimpleThreadPool;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.SchedulingTaskExecutor;
import org.springframework.util.Assert;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;
/**
* Subclass of Quartz's SimpleThreadPool that implements Spring's
@ -47,9 +45,9 @@ import org.springframework.util.concurrent.ListenableFutureTask;
* @see org.springframework.core.task.TaskExecutor
* @see SchedulerFactoryBean#setTaskExecutor
*/
@SuppressWarnings({"deprecation", "removal"})
@SuppressWarnings("deprecation")
public class SimpleThreadPoolTaskExecutor extends SimpleThreadPool
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, InitializingBean, DisposableBean {
implements AsyncTaskExecutor, SchedulingTaskExecutor, InitializingBean, DisposableBean {
private boolean waitForJobsToCompleteOnShutdown = false;
@ -91,20 +89,6 @@ public class SimpleThreadPoolTaskExecutor extends SimpleThreadPool
return future;
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
execute(future);
return future;
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
execute(future);
return future;
}
@Override
public void destroy() {

View File

@ -310,7 +310,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
return new Object[] {event};
}
@SuppressWarnings({"removal", "unchecked", "deprecation"})
protected void handleResult(Object result) {
if (reactiveStreamsPresent && new ReactiveResultHandler().subscribeToPublisher(result)) {
if (logger.isTraceEnabled()) {
@ -327,9 +326,6 @@ public class ApplicationListenerMethodAdapter implements GenericApplicationListe
}
});
}
else if (result instanceof org.springframework.util.concurrent.ListenableFuture<?> listenableFuture) {
listenableFuture.addCallback(this::publishEvents, this::handleAsyncError);
}
else {
publishEvents(result);
}

View File

@ -22,10 +22,6 @@ import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.springframework.lang.Nullable;
import org.springframework.util.concurrent.FailureCallback;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.util.concurrent.SuccessCallback;
/**
* A pass-through {@code Future} handle that can be used for method signatures
@ -46,8 +42,7 @@ import org.springframework.util.concurrent.SuccessCallback;
* @deprecated as of 6.0, in favor of {@link CompletableFuture}
*/
@Deprecated(since = "6.0")
@SuppressWarnings("removal")
public class AsyncResult<V> implements ListenableFuture<V> {
public class AsyncResult<V> implements Future<V> {
@Nullable
private final V value;
@ -105,38 +100,6 @@ public class AsyncResult<V> implements ListenableFuture<V> {
return get();
}
@Override
public void addCallback(ListenableFutureCallback<? super V> callback) {
addCallback(callback, callback);
}
@Override
public void addCallback(SuccessCallback<? super V> successCallback, FailureCallback failureCallback) {
try {
if (this.executionException != null) {
failureCallback.onFailure(exposedException(this.executionException));
}
else {
successCallback.onSuccess(this.value);
}
}
catch (Throwable ex) {
// Ignore
}
}
@Override
public CompletableFuture<V> completable() {
if (this.executionException != null) {
CompletableFuture<V> completable = new CompletableFuture<>();
completable.completeExceptionally(exposedException(this.executionException));
return completable;
}
else {
return CompletableFuture.completedFuture(this.value);
}
}
/**
* Create a new async result which exposes the given value from {@link Future#get()}.
@ -144,7 +107,7 @@ public class AsyncResult<V> implements ListenableFuture<V> {
* @since 4.2
* @see Future#get()
*/
public static <V> org.springframework.util.concurrent.ListenableFuture<V> forValue(V value) {
public static <V> Future<V> forValue(V value) {
return new AsyncResult<>(value, null);
}
@ -156,7 +119,7 @@ public class AsyncResult<V> implements ListenableFuture<V> {
* @since 4.2
* @see ExecutionException
*/
public static <V> org.springframework.util.concurrent.ListenableFuture<V> forExecutionException(Throwable ex) {
public static <V> Future<V> forExecutionException(Throwable ex) {
return new AsyncResult<>(null, ex);
}

View File

@ -26,14 +26,13 @@ import java.util.concurrent.Future;
import jakarta.enterprise.concurrent.ManagedExecutors;
import jakarta.enterprise.concurrent.ManagedTask;
import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.TaskDecorator;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.SchedulingAwareRunnable;
import org.springframework.scheduling.SchedulingTaskExecutor;
import org.springframework.util.ClassUtils;
import org.springframework.util.concurrent.ListenableFuture;
/**
* Adapter that takes a {@code java.util.concurrent.Executor} and exposes
@ -62,8 +61,8 @@ import org.springframework.util.concurrent.ListenableFuture;
* @see DefaultManagedTaskExecutor
* @see ThreadPoolTaskExecutor
*/
@SuppressWarnings({"deprecation", "removal"})
public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
@SuppressWarnings("deprecation")
public class ConcurrentTaskExecutor implements AsyncTaskExecutor, SchedulingTaskExecutor {
private static final Executor STUB_EXECUTOR = (task -> {
throw new IllegalStateException("Executor not configured");
@ -172,16 +171,6 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
return this.adaptedExecutor.submit(task);
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
return this.adaptedExecutor.submitListenable(task);
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return this.adaptedExecutor.submitListenable(task);
}
private TaskExecutorAdapter getAdaptedExecutor(Executor originalExecutor) {
TaskExecutorAdapter adapter =
@ -224,16 +213,6 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche
public <T> Future<T> submit(Callable<T> task) {
return super.submit(ManagedTaskBuilder.buildManagedTask(task, task.toString()));
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
return super.submitListenable(ManagedTaskBuilder.buildManagedTask(task, task.toString()));
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(ManagedTaskBuilder.buildManagedTask(task, task.toString()));
}
}

View File

@ -218,18 +218,6 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T
return super.submit(new DelegatingErrorHandlingCallable<>(task, this.errorHandler));
}
@SuppressWarnings({"deprecation", "removal"})
@Override
public org.springframework.util.concurrent.ListenableFuture<?> submitListenable(Runnable task) {
return super.submitListenable(TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, false));
}
@SuppressWarnings({"deprecation", "removal"})
@Override
public <T> org.springframework.util.concurrent.ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new DelegatingErrorHandlingCallable<>(task, this.errorHandler));
}
@Override
@Nullable
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {

View File

@ -269,18 +269,6 @@ public class SimpleAsyncTaskScheduler extends SimpleAsyncTaskExecutor implements
return super.submit(new DelegatingErrorHandlingCallable<>(task, this.errorHandler));
}
@SuppressWarnings({"deprecation", "removal"})
@Override
public org.springframework.util.concurrent.ListenableFuture<?> submitListenable(Runnable task) {
return super.submitListenable(TaskUtils.decorateTaskWithErrorHandler(task, this.errorHandler, false));
}
@SuppressWarnings({"deprecation", "removal"})
@Override
public <T> org.springframework.util.concurrent.ListenableFuture<T> submitListenable(Callable<T> task) {
return super.submitListenable(new DelegatingErrorHandlingCallable<>(task, this.errorHandler));
}
@Override
@Nullable
public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {

View File

@ -30,15 +30,13 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
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.scheduling.SchedulingTaskExecutor;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;
/**
* JavaBean that allows for configuring a {@link java.util.concurrent.ThreadPoolExecutor}
@ -80,9 +78,9 @@ import org.springframework.util.concurrent.ListenableFutureTask;
* @see ThreadPoolExecutorFactoryBean
* @see ConcurrentTaskExecutor
*/
@SuppressWarnings({"serial", "deprecation", "removal"})
@SuppressWarnings({"serial", "deprecation"})
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
implements AsyncTaskExecutor, SchedulingTaskExecutor {
private final Object poolSizeMonitor = new Object();
@ -414,32 +412,6 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
}
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
ExecutorService executor = getThreadPoolExecutor();
try {
ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
executor.execute(future);
return future;
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(executor, task, ex);
}
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
ExecutorService executor = getThreadPoolExecutor();
try {
ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
executor.execute(future);
return future;
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(executor, task, ex);
}
}
@Override
protected void cancelRemainingTask(Runnable task) {
super.cancelRemainingTask(task);

View File

@ -19,7 +19,6 @@ package org.springframework.scheduling.concurrent;
import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
@ -36,7 +35,7 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
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;
@ -45,10 +44,7 @@ import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.support.TaskUtils;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrentReferenceHashMap;
import org.springframework.util.ErrorHandler;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;
/**
* A standard implementation of Spring's {@link TaskScheduler} interface, wrapping
@ -74,9 +70,9 @@ import org.springframework.util.concurrent.ListenableFutureTask;
* @see ThreadPoolTaskExecutor
* @see SimpleAsyncTaskScheduler
*/
@SuppressWarnings({"serial", "deprecation", "removal"})
@SuppressWarnings({"serial", "deprecation"})
public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, TaskScheduler {
implements AsyncTaskExecutor, SchedulingTaskExecutor, TaskScheduler {
private static final TimeUnit NANO = TimeUnit.NANOSECONDS;
@ -100,10 +96,6 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
@Nullable
private ScheduledExecutorService scheduledExecutor;
// Underlying ScheduledFutureTask to user-level ListenableFuture handle, if any
private final Map<Object, ListenableFuture<?>> listenableFutureMap =
new ConcurrentReferenceHashMap<>(16, ConcurrentReferenceHashMap.ReferenceType.WEAK);
/**
* Set the ScheduledExecutorService's pool size.
@ -357,49 +349,6 @@ public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
}
}
@Override
public ListenableFuture<?> submitListenable(Runnable task) {
ExecutorService executor = getScheduledExecutor();
try {
ListenableFutureTask<Object> listenableFuture = new ListenableFutureTask<>(task, null);
executeAndTrack(executor, listenableFuture);
return listenableFuture;
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(executor, task, ex);
}
}
@Override
public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
ExecutorService executor = getScheduledExecutor();
try {
ListenableFutureTask<T> listenableFuture = new ListenableFutureTask<>(task);
executeAndTrack(executor, listenableFuture);
return listenableFuture;
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException(executor, task, ex);
}
}
private void executeAndTrack(ExecutorService executor, ListenableFutureTask<?> listenableFuture) {
Future<?> scheduledFuture = executor.submit(errorHandlingTask(listenableFuture, false));
this.listenableFutureMap.put(scheduledFuture, listenableFuture);
listenableFuture.addCallback(result -> this.listenableFutureMap.remove(scheduledFuture),
ex -> this.listenableFutureMap.remove(scheduledFuture));
}
@Override
protected void cancelRemainingTask(Runnable task) {
super.cancelRemainingTask(task);
// Cancel associated user-level ListenableFuture handle as well
ListenableFuture<?> listenableFuture = this.listenableFutureMap.get(task);
if (listenableFuture != null) {
listenableFuture.cancel(true);
}
}
// TaskScheduler implementation

View File

@ -81,19 +81,6 @@ public interface MethodValidationResult {
*/
List<ParameterValidationResult> getParameterValidationResults();
/**
* Return all validation results. This includes both method parameters with
* errors directly on them, and Object method parameters with nested errors
* on their fields and properties.
* @see #getValueResults()
* @see #getBeanResults()
* @deprecated deprecated in favor of {@link #getParameterValidationResults()}
*/
@Deprecated(since = "6.2", forRemoval = true)
default List<ParameterValidationResult> getAllValidationResults() {
return getParameterValidationResults();
}
/**
* Return the subset of {@link #getParameterValidationResults() allValidationResults}
* that includes method parameters with validation errors directly on method

View File

@ -85,35 +85,6 @@ public class ParameterValidationResult {
this.sourceLookup = sourceLookup;
}
/**
* Create a {@code ParameterValidationResult}.
* @deprecated in favor of
* {@link ParameterValidationResult#ParameterValidationResult(MethodParameter, Object, Collection, Object, Integer, Object, BiFunction)}
*/
@Deprecated(since = "6.2", forRemoval = true)
public ParameterValidationResult(
MethodParameter param, @Nullable Object arg, Collection<? extends MessageSourceResolvable> errors,
@Nullable Object container, @Nullable Integer index, @Nullable Object key) {
this(param, arg, errors, container, index, key, (error, sourceType) -> {
throw new IllegalArgumentException("No source object of the given type");
});
}
/**
* Create a {@code ParameterValidationResult}.
* @deprecated in favor of
* {@link ParameterValidationResult#ParameterValidationResult(MethodParameter, Object, Collection, Object, Integer, Object, BiFunction)}
*/
@Deprecated(since = "6.1.3", forRemoval = true)
public ParameterValidationResult(
MethodParameter param, @Nullable Object arg, Collection<? extends MessageSourceResolvable> errors) {
this(param, arg, errors, null, null, null, (error, sourceType) -> {
throw new IllegalArgumentException("No source object of the given type");
});
}
/**
* The method parameter the validation results are for.

View File

@ -279,25 +279,6 @@ class AnnotationDrivenEventListenerTests {
this.eventCollector.assertTotalEventsCount(2);
}
@Test
@SuppressWarnings({"deprecation", "removal"})
void listenableFutureReply() {
load(TestEventListener.class, ReplyEventListener.class);
org.springframework.util.concurrent.SettableListenableFuture<String> future =
new org.springframework.util.concurrent.SettableListenableFuture<>();
future.set("dummy");
AnotherTestEvent event = new AnotherTestEvent(this, future);
ReplyEventListener replyEventListener = this.context.getBean(ReplyEventListener.class);
TestEventListener listener = this.context.getBean(TestEventListener.class);
this.eventCollector.assertNoEventReceived(listener);
this.eventCollector.assertNoEventReceived(replyEventListener);
this.context.publishEvent(event);
this.eventCollector.assertEvent(replyEventListener, event);
this.eventCollector.assertEvent(listener, "dummy"); // reply
this.eventCollector.assertTotalEventsCount(2);
}
@Test
void completableFutureReply() {
load(TestEventListener.class, ReplyEventListener.class);

View File

@ -200,20 +200,6 @@ class AsyncAnnotationBeanPostProcessorTests {
assertFutureWithException(result, exceptionHandler);
}
@Test
@SuppressWarnings("resource")
public void handleExceptionWithListenableFuture() {
ConfigurableApplicationContext context =
new AnnotationConfigApplicationContext(ConfigWithExceptionHandler.class);
ITestBean testBean = context.getBean("target", ITestBean.class);
TestableAsyncUncaughtExceptionHandler exceptionHandler =
context.getBean("exceptionHandler", TestableAsyncUncaughtExceptionHandler.class);
assertThat(exceptionHandler.isCalled()).as("handler should not have been called yet").isFalse();
Future<Object> result = testBean.failWithListenableFuture();
assertFutureWithException(result, exceptionHandler);
}
private void assertFutureWithException(Future<Object> result,
TestableAsyncUncaughtExceptionHandler exceptionHandler) {
assertThatExceptionOfType(ExecutionException.class).isThrownBy(
@ -275,9 +261,6 @@ class AsyncAnnotationBeanPostProcessorTests {
Future<Object> failWithFuture();
@SuppressWarnings({"deprecation", "removal"})
org.springframework.util.concurrent.ListenableFuture<Object> failWithListenableFuture();
void failWithVoid();
void await(long timeout);
@ -308,13 +291,6 @@ class AsyncAnnotationBeanPostProcessorTests {
throw new UnsupportedOperationException("failWithFuture");
}
@Async
@Override
@SuppressWarnings({"deprecation", "removal"})
public org.springframework.util.concurrent.ListenableFuture<Object> failWithListenableFuture() {
throw new UnsupportedOperationException("failWithListenableFuture");
}
@Async
@Override
public void failWithVoid() {

View File

@ -42,7 +42,6 @@ import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.concurrent.ListenableFuture;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -51,7 +50,6 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
* @author Juergen Hoeller
* @author Chris Beams
*/
@SuppressWarnings({"resource", "deprecation", "removal"})
class AsyncExecutionTests {
private static String originalThreadName;
@ -81,8 +79,6 @@ class AsyncExecutionTests {
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertThat(future.get()).isEqualTo("20");
ListenableFuture<String> listenableFuture = asyncTest.returnSomethingListenable(20);
assertThat(listenableFuture.get()).isEqualTo("20");
CompletableFuture<String> completableFuture = asyncTest.returnSomethingCompletable(20);
assertThat(completableFuture.get()).isEqualTo("20");
@ -94,14 +90,6 @@ class AsyncExecutionTests {
asyncTest.returnSomething(-1).get())
.withCauseInstanceOf(IOException.class);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
asyncTest.returnSomethingListenable(0).get())
.withCauseInstanceOf(IllegalArgumentException.class);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
asyncTest.returnSomethingListenable(-1).get())
.withCauseInstanceOf(IOException.class);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
asyncTest.returnSomethingCompletable(0).get())
.withCauseInstanceOf(IllegalArgumentException.class);
@ -174,8 +162,6 @@ class AsyncExecutionTests {
asyncTest.doSomething(10);
Future<String> future = asyncTest.returnSomething(20);
assertThat(future.get()).isEqualTo("20");
ListenableFuture<String> listenableFuture = asyncTest.returnSomethingListenable(20);
assertThat(listenableFuture.get()).isEqualTo("20");
CompletableFuture<String> completableFuture = asyncTest.returnSomethingCompletable(20);
assertThat(completableFuture.get()).isEqualTo("20");
@ -183,10 +169,6 @@ class AsyncExecutionTests {
asyncTest.returnSomething(0).get())
.withCauseInstanceOf(IllegalArgumentException.class);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
asyncTest.returnSomethingListenable(0).get())
.withCauseInstanceOf(IllegalArgumentException.class);
assertThatExceptionOfType(ExecutionException.class).isThrownBy(() ->
asyncTest.returnSomethingCompletable(0).get())
.withCauseInstanceOf(IllegalArgumentException.class);
@ -419,18 +401,6 @@ class AsyncExecutionTests {
return AsyncResult.forValue(Integer.toString(i));
}
@Async
public ListenableFuture<String> returnSomethingListenable(int i) {
assertThat(Thread.currentThread().getName()).isNotEqualTo(originalThreadName);
if (i == 0) {
throw new IllegalArgumentException();
}
else if (i < 0) {
return AsyncResult.forExecutionException(new IOException());
}
return new AsyncResult<>(Integer.toString(i));
}
@Async
public CompletableFuture<String> returnSomethingCompletable(int i) {
assertThat(Thread.currentThread().getName()).isNotEqualTo(originalThreadName);
@ -505,14 +475,6 @@ class AsyncExecutionTests {
return new AsyncResult<>(Integer.toString(i));
}
public ListenableFuture<String> returnSomethingListenable(int i) {
assertThat(Thread.currentThread().getName()).isNotEqualTo(originalThreadName);
if (i == 0) {
throw new IllegalArgumentException();
}
return new AsyncResult<>(Integer.toString(i));
}
@Async
public CompletableFuture<String> returnSomethingCompletable(int i) {
assertThat(Thread.currentThread().getName()).isNotEqualTo(originalThreadName);

View File

@ -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.scheduling.annotation;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
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;
/**
* @author Juergen Hoeller
*/
class AsyncResultTests {
@Test
@SuppressWarnings({ "deprecation", "removal" })
public void asyncResultWithCallbackAndValue() throws Exception {
String value = "val";
final Set<String> values = new HashSet<>(1);
org.springframework.util.concurrent.ListenableFuture<String> future = AsyncResult.forValue(value);
future.addCallback(new org.springframework.util.concurrent.ListenableFutureCallback<>() {
@Override
public void onSuccess(String result) {
values.add(result);
}
@Override
public void onFailure(Throwable ex) {
throw new AssertionError("Failure callback not expected: " + ex, ex);
}
});
assertThat(values).singleElement().isSameAs(value);
assertThat(future.get()).isSameAs(value);
assertThat(future.completable().get()).isSameAs(value);
future.completable().thenAccept(v -> assertThat(v).isSameAs(value));
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
public void asyncResultWithCallbackAndException() {
IOException ex = new IOException();
final Set<Throwable> values = new HashSet<>(1);
org.springframework.util.concurrent.ListenableFuture<String> future = AsyncResult.forExecutionException(ex);
future.addCallback(new org.springframework.util.concurrent.ListenableFutureCallback<>() {
@Override
public void onSuccess(String result) {
throw new AssertionError("Success callback not expected: " + result);
}
@Override
public void onFailure(Throwable ex) {
values.add(ex);
}
});
assertThat(values).singleElement().isSameAs(ex);
assertThatExceptionOfType(ExecutionException.class)
.isThrownBy(future::get)
.withCause(ex);
assertThatExceptionOfType(ExecutionException.class)
.isThrownBy(future.completable()::get)
.withCause(ex);
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
public void asyncResultWithSeparateCallbacksAndValue() throws Exception {
String value = "val";
final Set<String> values = new HashSet<>(1);
org.springframework.util.concurrent.ListenableFuture<String> future = AsyncResult.forValue(value);
future.addCallback(values::add, ex -> new AssertionError("Failure callback not expected: " + ex));
assertThat(values).singleElement().isSameAs(value);
assertThat(future.get()).isSameAs(value);
assertThat(future.completable().get()).isSameAs(value);
future.completable().thenAccept(v -> assertThat(v).isSameAs(value));
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
public void asyncResultWithSeparateCallbacksAndException() {
IOException ex = new IOException();
final Set<Throwable> values = new HashSet<>(1);
org.springframework.util.concurrent.ListenableFuture<String> future = AsyncResult.forExecutionException(ex);
future.addCallback(result -> new AssertionError("Success callback not expected: " + result), values::add);
assertThat(values).singleElement().isSameAs(ex);
assertThatExceptionOfType(ExecutionException.class)
.isThrownBy(future::get)
.withCause(ex);
assertThatExceptionOfType(ExecutionException.class)
.isThrownBy(future.completable()::get)
.withCause(ex);
}
}

View File

@ -35,6 +35,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.lang.Nullable;
import static org.assertj.core.api.Assertions.assertThat;
@ -47,8 +48,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
abstract class AbstractSchedulingTaskExecutorTests {
@SuppressWarnings("removal")
private org.springframework.core.task.AsyncListenableTaskExecutor executor;
private AsyncTaskExecutor executor;
protected String testName;
@ -64,8 +64,7 @@ abstract class AbstractSchedulingTaskExecutorTests {
this.executor = buildExecutor();
}
@SuppressWarnings("removal")
protected abstract org.springframework.core.task.AsyncListenableTaskExecutor buildExecutor();
protected abstract AsyncTaskExecutor buildExecutor();
@AfterEach
void shutdownExecutor() throws Exception {
@ -124,22 +123,6 @@ abstract class AbstractSchedulingTaskExecutorTests {
});
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
void submitListenableRunnable() {
TestTask task = new TestTask(this.testName, 1);
// Act
org.springframework.util.concurrent.ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.atMost(5, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(future::isDone);
assertThat(outcome).isNull();
assertThreadNamePrefix(task);
}
@Test
void submitCompletableRunnable() {
TestTask task = new TestTask(this.testName, 1);
@ -155,21 +138,6 @@ abstract class AbstractSchedulingTaskExecutorTests {
assertThreadNamePrefix(task);
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
void submitFailingListenableRunnable() {
TestTask task = new TestTask(this.testName, 0);
org.springframework.util.concurrent.ListenableFuture<?> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(5, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.getClass()).isSameAs(RuntimeException.class);
}
@Test
void submitFailingCompletableRunnable() {
TestTask task = new TestTask(this.testName, 0);
@ -184,43 +152,15 @@ abstract class AbstractSchedulingTaskExecutorTests {
assertThat(outcome.getClass()).isSameAs(CompletionException.class);
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
void submitListenableRunnableWithGetAfterShutdown() throws Exception {
org.springframework.util.concurrent.ListenableFuture<?> future1 = executor.submitListenable(new TestTask(this.testName, -1));
org.springframework.util.concurrent.ListenableFuture<?> future2 = executor.submitListenable(new TestTask(this.testName, -1));
shutdownExecutor();
try {
future1.get(1000, TimeUnit.MILLISECONDS);
}
catch (Exception ex) {
// ignore
}
Awaitility.await()
.atMost(5, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() -> assertThatExceptionOfType(CancellationException.class)
.isThrownBy(() -> future2.get(1000, TimeUnit.MILLISECONDS)));
}
@Test
void submitCompletableRunnableWithGetAfterShutdown() throws Exception {
CompletableFuture<?> future1 = executor.submitCompletable(new TestTask(this.testName, -1));
CompletableFuture<?> future2 = executor.submitCompletable(new TestTask(this.testName, -1));
shutdownExecutor();
try {
assertThatExceptionOfType(TimeoutException.class).isThrownBy(() -> {
future1.get(1000, TimeUnit.MILLISECONDS);
}
catch (Exception ex) {
// ignore
}
Awaitility.await()
.atMost(5, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() -> assertThatExceptionOfType(TimeoutException.class)
.isThrownBy(() -> future2.get(1000, TimeUnit.MILLISECONDS)));
future2.get(1000, TimeUnit.MILLISECONDS);
});
}
@Test
@ -245,57 +185,6 @@ abstract class AbstractSchedulingTaskExecutorTests {
Future<?> future1 = executor.submit(new TestCallable(this.testName, -1));
Future<?> future2 = executor.submit(new TestCallable(this.testName, -1));
shutdownExecutor();
try {
future1.get(1000, TimeUnit.MILLISECONDS);
}
catch (Exception ex) {
// ignore
}
Awaitility.await()
.atMost(5, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.untilAsserted(() -> assertThatExceptionOfType(CancellationException.class)
.isThrownBy(() -> future2.get(1000, TimeUnit.MILLISECONDS)));
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
void submitListenableCallable() {
TestCallable task = new TestCallable(this.testName, 1);
// Act
org.springframework.util.concurrent.ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.atMost(5, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.toString().substring(0, this.threadNamePrefix.length())).isEqualTo(this.threadNamePrefix);
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
void submitFailingListenableCallable() {
TestCallable task = new TestCallable(this.testName, 0);
// Act
org.springframework.util.concurrent.ListenableFuture<String> future = executor.submitListenable(task);
future.addCallback(result -> outcome = result, ex -> outcome = ex);
// Assert
Awaitility.await()
.dontCatchUncaughtExceptions()
.atMost(5, TimeUnit.SECONDS)
.pollInterval(10, TimeUnit.MILLISECONDS)
.until(() -> future.isDone() && outcome != null);
assertThat(outcome.getClass()).isSameAs(RuntimeException.class);
}
@Test
@SuppressWarnings({ "deprecation", "removal" })
void submitListenableCallableWithGetAfterShutdown() throws Exception {
org.springframework.util.concurrent.ListenableFuture<?> future1 = executor.submitListenable(new TestCallable(this.testName, -1));
org.springframework.util.concurrent.ListenableFuture<?> future2 = executor.submitListenable(new TestCallable(this.testName, -1));
shutdownExecutor();
assertThatExceptionOfType(CancellationException.class).isThrownBy(() -> {
future1.get(1000, TimeUnit.MILLISECONDS);
future2.get(1000, TimeUnit.MILLISECONDS);

View File

@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.core.task.NoOpRunnable;
import org.springframework.core.task.TaskDecorator;
import org.springframework.util.Assert;
@ -42,8 +43,7 @@ class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
@Override
@SuppressWarnings("removal")
protected org.springframework.core.task.AsyncListenableTaskExecutor buildExecutor() {
protected AsyncTaskExecutor buildExecutor() {
concurrentExecutor.setThreadFactory(new CustomizableThreadFactory(this.threadNamePrefix));
return new ConcurrentTaskExecutor(concurrentExecutor);
}

View File

@ -31,6 +31,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.util.ErrorHandler;
@ -52,8 +53,7 @@ class ConcurrentTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
@Override
@SuppressWarnings("removal")
protected org.springframework.core.task.AsyncListenableTaskExecutor buildExecutor() {
protected AsyncTaskExecutor buildExecutor() {
threadFactory.setThreadNamePrefix(this.threadNamePrefix);
scheduler.setTaskDecorator(runnable -> () -> {
taskRun.set(true);
@ -79,26 +79,12 @@ class ConcurrentTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
// decorated Future cannot be cancelled on shutdown with ConcurrentTaskScheduler (see above)
}
@Test
@SuppressWarnings("deprecation")
@Override
void submitListenableRunnableWithGetAfterShutdown() {
// decorated Future cannot be cancelled on shutdown with ConcurrentTaskScheduler (see above)
}
@Test
@Override
void submitCallableWithGetAfterShutdown() {
// decorated Future cannot be cancelled on shutdown with ConcurrentTaskScheduler (see above)
}
@Test
@SuppressWarnings("deprecation")
@Override
void submitListenableCallableWithGetAfterShutdown() {
// decorated Future cannot be cancelled on shutdown with ConcurrentTaskScheduler (see above)
}
@Test
void executeFailingRunnableWithErrorHandler() {

View File

@ -16,6 +16,7 @@
package org.springframework.scheduling.concurrent;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.support.DelegatingErrorHandlingRunnable;
import org.springframework.scheduling.support.TaskUtils;
@ -26,8 +27,7 @@ import org.springframework.scheduling.support.TaskUtils;
class DecoratedThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
@Override
@SuppressWarnings("removal")
protected org.springframework.core.task.AsyncListenableTaskExecutor buildExecutor() {
protected AsyncTaskExecutor buildExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setTaskDecorator(runnable ->
new DelegatingErrorHandlingRunnable(runnable, TaskUtils.LOG_AND_PROPAGATE_ERROR_HANDLER));

View File

@ -27,6 +27,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.util.ErrorHandler;
@ -45,8 +46,7 @@ class SimpleAsyncTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests
@Override
@SuppressWarnings("removal")
protected org.springframework.core.task.AsyncListenableTaskExecutor buildExecutor() {
protected AsyncTaskExecutor buildExecutor() {
scheduler.setTaskDecorator(runnable -> () -> {
taskRun.set(true);
runnable.run();
@ -62,12 +62,6 @@ class SimpleAsyncTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests
// decorated Future cannot be cancelled on shutdown with SimpleAsyncTaskScheduler
}
@Test
@Override
void submitListenableRunnableWithGetAfterShutdown() {
// decorated Future cannot be cancelled on shutdown with SimpleAsyncTaskScheduler
}
@Test
@Override
void submitCompletableRunnableWithGetAfterShutdown() {
@ -80,13 +74,6 @@ class SimpleAsyncTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests
// decorated Future cannot be cancelled on shutdown with SimpleAsyncTaskScheduler
}
@Test
@SuppressWarnings("deprecation")
@Override
void submitListenableCallableWithGetAfterShutdown() {
// decorated Future cannot be cancelled on shutdown with SimpleAsyncTaskScheduler
}
@Test
@Override
void submitCompletableCallableWithGetAfterShutdown() {

View File

@ -23,6 +23,8 @@ import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@ -41,8 +43,7 @@ class ThreadPoolTaskExecutorTests extends AbstractSchedulingTaskExecutorTests {
@Override
@SuppressWarnings("removal")
protected org.springframework.core.task.AsyncListenableTaskExecutor buildExecutor() {
protected AsyncTaskExecutor buildExecutor() {
executor.setThreadNamePrefix(this.threadNamePrefix);
executor.setMaxPoolSize(1);
executor.afterPropertiesSet();

View File

@ -28,6 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.util.ErrorHandler;
@ -49,8 +50,7 @@ class ThreadPoolTaskSchedulerTests extends AbstractSchedulingTaskExecutorTests {
@Override
@SuppressWarnings("removal")
protected org.springframework.core.task.AsyncListenableTaskExecutor buildExecutor() {
protected AsyncTaskExecutor buildExecutor() {
scheduler.setTaskDecorator(runnable -> () -> {
taskRun.set(true);
runnable.run();

View File

@ -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);

View File

@ -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);
}

View File

@ -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.

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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. "&#42;/&#42;").
*/

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}
});
}
}

View File

@ -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 {
}

View File

@ -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}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}
}

View File

@ -211,69 +211,11 @@ public class ExpressionState {
initScopeRootObjects().push(getActiveContextObject());
}
/**
* Enter a new scope with a new {@linkplain #getActiveContextObject() root
* context object} and a new local variable scope containing the supplied
* name/value pair.
* @param name the name of the local variable
* @param value the value of the local variable
* @deprecated as of 6.2 with no replacement; to be removed in 7.0
*/
@Deprecated(since = "6.2", forRemoval = true)
public void enterScope(String name, Object value) {
initVariableScopes().push(new VariableScope(name, value));
initScopeRootObjects().push(getActiveContextObject());
}
/**
* Enter a new scope with a new {@linkplain #getActiveContextObject() root
* context object} and a new local variable scope containing the supplied
* name/value pairs.
* @param variables a map containing name/value pairs for local variables
* @deprecated as of 6.2 with no replacement; to be removed in 7.0
*/
@Deprecated(since = "6.2", forRemoval = true)
public void enterScope(@Nullable Map<String, Object> variables) {
initVariableScopes().push(new VariableScope(variables));
initScopeRootObjects().push(getActiveContextObject());
}
public void exitScope() {
initVariableScopes().pop();
initScopeRootObjects().pop();
}
/**
* Set a local variable with the given name to the supplied value within the
* current scope.
* <p>If a local variable with the given name already exists, it will be
* overwritten.
* @param name the name of the local variable
* @param value the value of the local variable
* @deprecated as of 6.2 with no replacement; to be removed in 7.0
*/
@Deprecated(since = "6.2", forRemoval = true)
public void setLocalVariable(String name, Object value) {
initVariableScopes().element().setVariable(name, value);
}
/**
* Look up the value of the local variable with the given name.
* @param name the name of the local variable
* @return the value of the local variable, or {@code null} if the variable
* does not exist in the current scope
* @deprecated as of 6.2 with no replacement; to be removed in 7.0
*/
@Deprecated(since = "6.2", forRemoval = true)
@Nullable
public Object lookupLocalVariable(String name) {
for (VariableScope scope : initVariableScopes()) {
if (scope.definesVariable(name)) {
return scope.lookupVariable(name);
}
}
return null;
}
private Deque<TypedValue> initContextObjects() {
if (this.contextObjects == null) {

View File

@ -123,17 +123,6 @@ public class Indexer extends SpelNodeImpl {
private volatile CachedIndexState cachedIndexWriteState;
/**
* Create an {@code Indexer} with the given start position, end position, and
* index expression.
* @see #Indexer(boolean, int, int, SpelNodeImpl)
* @deprecated as of 6.2, in favor of {@link #Indexer(boolean, int, int, SpelNodeImpl)}
*/
@Deprecated(since = "6.2", forRemoval = true)
public Indexer(int startPos, int endPos, SpelNodeImpl indexExpression) {
this(false, startPos, endPos, indexExpression);
}
/**
* Create an {@code Indexer} with the given null-safe flag, start position,
* end position, and index expression.

View File

@ -16,8 +16,6 @@
package org.springframework.expression.spel;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.springframework.core.convert.TypeDescriptor;
@ -55,21 +53,6 @@ class ExpressionStateTests extends AbstractExpressionTests {
assertThat(state.getEvaluationContext()).isEqualTo(context);
}
@Test
@SuppressWarnings("removal")
void localVariables() {
Object value = state.lookupLocalVariable("foo");
assertThat(value).isNull();
state.setLocalVariable("foo",34);
value = state.lookupLocalVariable("foo");
assertThat(value).isEqualTo(34);
state.setLocalVariable("foo", null);
value = state.lookupLocalVariable("foo");
assertThat(value).isNull();
}
@Test
void globalVariables() {
TypedValue typedValue = state.lookupVariable("foo");
@ -86,41 +69,6 @@ class ExpressionStateTests extends AbstractExpressionTests {
assertThat(typedValue.getTypeDescriptor().getType()).isEqualTo(String.class);
}
@Test
@SuppressWarnings("removal")
void noVariableInterference() {
TypedValue typedValue = state.lookupVariable("foo");
assertThat(typedValue).isEqualTo(TypedValue.NULL);
state.setLocalVariable("foo",34);
typedValue = state.lookupVariable("foo");
assertThat(typedValue).isEqualTo(TypedValue.NULL);
state.setVariable("goo", "hello");
assertThat(state.lookupLocalVariable("goo")).isNull();
}
@Test
@SuppressWarnings("removal")
void localVariableNestedScopes() {
assertThat(state.lookupLocalVariable("foo")).isNull();
state.setLocalVariable("foo",12);
assertThat(state.lookupLocalVariable("foo")).isEqualTo(12);
state.enterScope(null);
// found in upper scope
assertThat(state.lookupLocalVariable("foo")).isEqualTo(12);
state.setLocalVariable("foo","abc");
// found in nested scope
assertThat(state.lookupLocalVariable("foo")).isEqualTo("abc");
state.exitScope();
// found in nested scope
assertThat(state.lookupLocalVariable("foo")).isEqualTo(12);
}
@Test
void rootContextObject() {
assertThat(state.getRootContextObject().getValue().getClass()).isEqualTo(Inventor.class);
@ -159,25 +107,6 @@ class ExpressionStateTests extends AbstractExpressionTests {
assertThat(state.getActiveContextObject()).isEqualTo(TypedValue.NULL);
}
@Test
@SuppressWarnings("removal")
void populatedNestedScopes() {
assertThat(state.lookupLocalVariable("foo")).isNull();
state.enterScope("foo",34);
assertThat(state.lookupLocalVariable("foo")).isEqualTo(34);
state.enterScope(null);
state.setLocalVariable("foo", 12);
assertThat(state.lookupLocalVariable("foo")).isEqualTo(12);
state.exitScope();
assertThat(state.lookupLocalVariable("foo")).isEqualTo(34);
state.exitScope();
assertThat(state.lookupLocalVariable("goo")).isNull();
}
@Test
void rootObjectConstructor() {
EvaluationContext ctx = TestScenarioCreator.getTestEvaluationContext();
@ -189,27 +118,6 @@ class ExpressionStateTests extends AbstractExpressionTests {
assertThat(stateRoot.getValue()).isEqualTo("i am a string");
}
@Test
@SuppressWarnings("removal")
void populatedNestedScopesMap() {
assertThat(state.lookupLocalVariable("foo")).isNull();
assertThat(state.lookupLocalVariable("goo")).isNull();
state.enterScope(Map.of("foo", 34, "goo", "abc"));
assertThat(state.lookupLocalVariable("foo")).isEqualTo(34);
assertThat(state.lookupLocalVariable("goo")).isEqualTo("abc");
state.enterScope(null);
state.setLocalVariable("foo",12);
assertThat(state.lookupLocalVariable("foo")).isEqualTo(12);
assertThat(state.lookupLocalVariable("goo")).isEqualTo("abc");
state.exitScope();
state.exitScope();
assertThat(state.lookupLocalVariable("foo")).isNull();
assertThat(state.lookupLocalVariable("goo")).isNull();
}
@Test
void operators() {
assertThatExceptionOfType(SpelEvaluationException.class)

View File

@ -50,35 +50,6 @@ public interface AsyncHandlerMethodReturnValueHandler extends HandlerMethodRetur
*/
boolean isAsyncReturnValue(Object returnValue, MethodParameter returnType);
/**
* Adapt the asynchronous return value to a
* {@link org.springframework.util.concurrent.ListenableFuture ListenableFuture}.
* <p>Implementations should consider returning an instance of
* {@link org.springframework.util.concurrent.SettableListenableFuture
* SettableListenableFuture}. Return value handling will then continue when
* the ListenableFuture is completed with either success or error.
* <p><strong>Note:</strong> this method will only be invoked after
* {@link #supportsReturnType(org.springframework.core.MethodParameter)}
* is called and it returns {@code true}.
* @param returnValue the value returned from the handler method
* @param returnType the type of the return value
* @return the resulting ListenableFuture, or {@code null} in which case
* no further handling will be performed
* @deprecated as of 6.0, in favor of
* {@link #toCompletableFuture(Object, MethodParameter)}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
@Nullable
default org.springframework.util.concurrent.ListenableFuture<?> toListenableFuture(
Object returnValue, MethodParameter returnType) {
CompletableFuture<?> result = toCompletableFuture(returnValue, returnType);
return (result != null ?
new org.springframework.util.concurrent.CompletableToListenableFutureAdapter<>(result) :
null);
}
/**
* Adapt the asynchronous return value to a {@link CompletableFuture}.
* <p>Return value handling will then continue when

View File

@ -1,49 +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.messaging.handler.invocation;
import java.util.concurrent.CompletableFuture;
import org.springframework.core.MethodParameter;
/**
* Support for {@link org.springframework.util.concurrent.ListenableFuture} as a return value type.
*
* @author Sebastien Deleuze
* @since 4.2
* @deprecated as of 6.0, in favor of {@link CompletableFutureReturnValueHandler}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
public class ListenableFutureReturnValueHandler extends AbstractAsyncReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return org.springframework.util.concurrent.ListenableFuture.class.isAssignableFrom(returnType.getParameterType());
}
@Override
public org.springframework.util.concurrent.ListenableFuture<?> toListenableFuture(Object returnValue, MethodParameter returnType) {
return (org.springframework.util.concurrent.ListenableFuture<?>) returnValue;
}
@Override
public CompletableFuture<?> toCompletableFuture(Object returnValue, MethodParameter returnType) {
return ((org.springframework.util.concurrent.ListenableFuture<?>) returnValue).completable();
}
}

View File

@ -344,13 +344,11 @@ public class SimpAnnotationMethodMessageHandler extends AbstractMethodMessageHan
}
@Override
@SuppressWarnings("removal")
protected List<? extends HandlerMethodReturnValueHandler> initReturnValueHandlers() {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>();
// Single-purpose return value types
handlers.add(new org.springframework.messaging.handler.invocation.ListenableFutureReturnValueHandler());
handlers.add(new CompletableFutureReturnValueHandler());
if (reactorPresent) {
handlers.add(new ReactiveReturnValueHandler());

View File

@ -31,17 +31,6 @@ import java.util.concurrent.CompletableFuture;
*/
public interface ConnectionHandlingStompSession extends StompSession, StompTcpConnectionHandler<byte[]> {
/**
* Return a future that will complete when the session is ready for use.
* @deprecated as of 6.0, in favor of {@link #getSession()}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
default org.springframework.util.concurrent.ListenableFuture<StompSession> getSessionFuture() {
return new org.springframework.util.concurrent.CompletableToListenableFutureAdapter<>(
getSession());
}
/**
* Return a future that will complete when the session is ready for use.
* @since 6.0

View File

@ -89,22 +89,6 @@ public class ReactorNettyTcpStompClient extends StompClientSupport {
}
/**
* Connect and notify the given {@link StompSessionHandler} when connected
* on the STOMP level.
* @param handler the handler for the STOMP session
* @return a ListenableFuture for access to the session when ready for use
* @deprecated as of 6.0, in favor of {@link #connectAsync(StompSessionHandler)}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
public org.springframework.util.concurrent.ListenableFuture<StompSession> connect(
StompSessionHandler handler) {
return new org.springframework.util.concurrent.CompletableToListenableFutureAdapter<>(
connectAsync(handler));
}
/**
* Connect and notify the given {@link StompSessionHandler} when connected
* on the STOMP level.
@ -116,24 +100,6 @@ public class ReactorNettyTcpStompClient extends StompClientSupport {
return connectAsync(null, handler);
}
/**
* An overloaded version of {@link #connect(StompSessionHandler)} that
* accepts headers to use for the STOMP CONNECT frame.
* @param connectHeaders headers to add to the CONNECT frame
* @param handler the handler for the STOMP session
* @return a ListenableFuture for access to the session when ready for use
* @deprecated as of 6.0, in favor of {@link #connectAsync(StompHeaders, StompSessionHandler)}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
public org.springframework.util.concurrent.ListenableFuture<StompSession> connect(
@Nullable StompHeaders connectHeaders, StompSessionHandler handler) {
ConnectionHandlingStompSession session = createSession(connectHeaders, handler);
this.tcpClient.connectAsync(session);
return session.getSessionFuture();
}
/**
* An overloaded version of {@link #connectAsync(StompSessionHandler)} that
* accepts headers to use for the STOMP CONNECT frame.

View File

@ -30,20 +30,6 @@ import org.springframework.messaging.Message;
*/
public interface TcpConnection<P> extends Closeable {
/**
* Send the given message.
* @param message the message
* @return a ListenableFuture that can be used to determine when and if the
* message was successfully sent
* @deprecated as of 6.0, in favor of {@link #sendAsync(Message)}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
default org.springframework.util.concurrent.ListenableFuture<Void> send(Message<P> message) {
return new org.springframework.util.concurrent.CompletableToListenableFutureAdapter<>(
sendAsync(message));
}
/**
* Send the given message.
* @param message the message

View File

@ -27,22 +27,6 @@ import java.util.concurrent.CompletableFuture;
*/
public interface TcpOperations<P> {
/**
* Open a new connection.
* @param connectionHandler a handler to manage the connection
* @return a ListenableFuture that can be used to determine when and if the
* connection is successfully established
* @deprecated as of 6.0, in favor of {@link #connectAsync(TcpConnectionHandler)}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
default org.springframework.util.concurrent.ListenableFuture<Void> connect(
TcpConnectionHandler<P> connectionHandler) {
return new org.springframework.util.concurrent.CompletableToListenableFutureAdapter<>(
connectAsync(connectionHandler));
}
/**
* Open a new connection.
* @param connectionHandler a handler to manage the connection
@ -52,23 +36,6 @@ public interface TcpOperations<P> {
*/
CompletableFuture<Void> connectAsync(TcpConnectionHandler<P> connectionHandler);
/**
* Open a new connection and a strategy for reconnecting if the connection fails.
* @param connectionHandler a handler to manage the connection
* @param reconnectStrategy a strategy for reconnecting
* @return a ListenableFuture that can be used to determine when and if the
* initial connection is successfully established
* @deprecated as of 6.0, in favor of {@link #connectAsync(TcpConnectionHandler, ReconnectStrategy)}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
default org.springframework.util.concurrent.ListenableFuture<Void> connect(
TcpConnectionHandler<P> connectionHandler, ReconnectStrategy reconnectStrategy) {
return new org.springframework.util.concurrent.CompletableToListenableFutureAdapter<>(
connectAsync(connectionHandler, reconnectStrategy));
}
/**
* Open a new connection and a strategy for reconnecting if the connection fails.
* @param connectionHandler a handler to manage the connection
@ -79,18 +46,6 @@ public interface TcpOperations<P> {
*/
CompletableFuture<Void> connectAsync(TcpConnectionHandler<P> connectionHandler, ReconnectStrategy reconnectStrategy);
/**
* Shut down and close any open connections.
* @return a ListenableFuture that can be used to determine when and if the
* connection is successfully closed
* @deprecated as of 6.0, in favor of {@link #shutdownAsync()}
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
default org.springframework.util.concurrent.ListenableFuture<Void> shutdown() {
return new org.springframework.util.concurrent.CompletableToListenableFutureAdapter<>(shutdownAsync());
}
/**
* Shut down and close any open connections.
* @return a CompletableFuture that can be used to determine when and if the

View File

@ -273,39 +273,6 @@ public class SimpAnnotationMethodMessageHandlerTests {
assertThat(controller.method).isEqualTo("handleFoo");
}
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void listenableFutureSuccess() {
Message emptyMessage = MessageBuilder.withPayload(new byte[0]).build();
given(this.channel.send(any(Message.class))).willReturn(true);
given(this.converter.toMessage(any(), any(MessageHeaders.class))).willReturn(emptyMessage);
ListenableFutureController controller = new ListenableFutureController();
this.messageHandler.registerHandler(controller);
this.messageHandler.setDestinationPrefixes(Arrays.asList("/app1", "/app2/"));
Message<?> message = createMessage("/app1/listenable-future/success");
this.messageHandler.handleMessage(message);
assertThat(controller.future).isNotNull();
controller.future.run();
verify(this.converter).toMessage(this.payloadCaptor.capture(), any(MessageHeaders.class));
assertThat(this.payloadCaptor.getValue()).isEqualTo("foo");
}
@Test
void listenableFutureFailure() {
ListenableFutureController controller = new ListenableFutureController();
this.messageHandler.registerHandler(controller);
this.messageHandler.setDestinationPrefixes(Arrays.asList("/app1", "/app2/"));
Message<?> message = createMessage("/app1/listenable-future/failure");
this.messageHandler.handleMessage(message);
controller.future.run();
assertThat(controller.exceptionCaught).isTrue();
}
@Test
@SuppressWarnings({ "unchecked", "rawtypes" })
public void completableFutureSuccess() {
@ -569,36 +536,6 @@ public class SimpAnnotationMethodMessageHandlerTests {
}
@Controller
@MessageMapping("listenable-future")
@SuppressWarnings({"deprecation", "removal"})
private static class ListenableFutureController {
org.springframework.util.concurrent.ListenableFutureTask<String> future;
boolean exceptionCaught = false;
@MessageMapping("success")
public org.springframework.util.concurrent.ListenableFutureTask<String> handleListenableFuture() {
this.future = new org.springframework.util.concurrent.ListenableFutureTask<>(() -> "foo");
return this.future;
}
@MessageMapping("failure")
public org.springframework.util.concurrent.ListenableFutureTask<String> handleListenableFutureException() {
this.future = new org.springframework.util.concurrent.ListenableFutureTask<>(() -> {
throw new IllegalStateException();
});
return this.future;
}
@MessageExceptionHandler(IllegalStateException.class)
public void handleValidationException() {
this.exceptionCaught = true;
}
}
@Controller
private static class CompletableFutureController {

View File

@ -82,18 +82,6 @@ public class JsonPathExpectationsHelper {
this.configuration = (configuration != null) ? configuration : Configuration.defaultConfiguration();
}
/**
* Construct a new {@code JsonPathExpectationsHelper}.
* @param expression the {@link JsonPath} expression; never {@code null} or empty
* @param args arguments to parameterize the {@code JsonPath} expression with,
* using formatting specifiers defined in {@link String#format(String, Object...)}
* @deprecated in favor of calling {@link String#formatted(Object...)} upfront
*/
@Deprecated(since = "6.2", forRemoval = true)
public JsonPathExpectationsHelper(String expression, Object... args) {
this(expression.formatted(args), (Configuration) null);
}
/**
* Evaluate the JSON path expression against the supplied {@code content}

View File

@ -711,13 +711,6 @@ class DefaultWebTestClient implements WebTestClient {
JsonPathConfigurationProvider.getConfiguration(this.jsonEncoderDecoder));
}
@Override
@SuppressWarnings("removal")
public JsonPathAssertions jsonPath(String expression, Object... args) {
Assert.hasText(expression, "expression must not be null or empty");
return jsonPath(expression.formatted(args));
}
@Override
public XpathAssertions xpath(String expression, @Nullable Map<String, String> namespaces, Object... args) {
return new XpathAssertions(this, expression, namespaces, args);

View File

@ -176,16 +176,6 @@ public class ExchangeResult {
return this.response.getStatusCode();
}
/**
* Return the HTTP status code as an integer.
* @since 5.1.10
* @deprecated in favor of {@link #getStatus()}, for removal in 7.0
*/
@Deprecated(since = "6.0", forRemoval = true)
public int getRawStatusCode() {
return getStatus().value();
}
/**
* Return the response headers received from the server.
*/

View File

@ -161,17 +161,6 @@ public class JsonPathAssertions {
return this.bodySpec;
}
/**
* Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, Class)}.
* @since 5.1
* @deprecated in favor of {@link #value(Class, Matcher)}
*/
@Deprecated(since = "6.2", forRemoval = true)
public <T> WebTestClient.BodyContentSpec value(Matcher<? super T> matcher, Class<T> targetType) {
this.pathHelper.assertValue(this.content, matcher, targetType);
return this.bodySpec;
}
/**
* Delegates to {@link JsonPathExpectationsHelper#assertValue(String, Matcher, ParameterizedTypeReference)}.
* @since 6.2
@ -202,16 +191,6 @@ public class JsonPathAssertions {
return this.bodySpec;
}
/**
* Consume the result of the JSONPath evaluation and provide a target class.
* @since 5.1
* @deprecated in favor of {@link #value(Class, Consumer)}
*/
@Deprecated(since = "6.2", forRemoval = true)
public <T> WebTestClient.BodyContentSpec value(Consumer<T> consumer, Class<T> targetType) {
return value(targetType, consumer);
}
/**
* Consume the result of the JSONPath evaluation and provide a parameterized type.
* @since 6.2

View File

@ -1075,19 +1075,6 @@ public interface WebTestClient {
*/
JsonPathAssertions jsonPath(String expression);
/**
* Access to response body assertions using a
* <a href="https://github.com/jayway/JsonPath">JsonPath</a> expression
* to inspect a specific subset of the body.
* <p>The JSON path expression can be a parameterized string using
* formatting specifiers as defined in {@link String#format}.
* @param expression the JsonPath expression
* @param args arguments to parameterize the expression
* @deprecated in favor of calling {@link String#formatted(Object...)} upfront
*/
@Deprecated(since = "6.2", forRemoval = true)
JsonPathAssertions jsonPath(String expression, Object... args);
/**
* Access to response body assertions using an XPath expression to
* inspect a specific subset of the body.

View File

@ -117,16 +117,6 @@ class AsyncTests {
.expectBody(String.class).isEqualTo("Delayed Error");
}
@Test
void listenableFuture() {
this.testClient.get()
.uri("/1?listenableFuture=true")
.exchange()
.expectStatus().isOk()
.expectHeader().contentType(MediaType.APPLICATION_JSON)
.expectBody().json("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
}
@Test
void completableFutureWithImmediateValue() {
this.testClient.get()
@ -193,15 +183,6 @@ class AsyncTests {
return result;
}
@GetMapping(params = "listenableFuture")
@SuppressWarnings({ "deprecation", "removal" })
org.springframework.util.concurrent.ListenableFuture<Person> getListenableFuture() {
org.springframework.util.concurrent.ListenableFutureTask<Person> futureTask =
new org.springframework.util.concurrent.ListenableFutureTask<>(() -> new Person("Joe"));
delay(100, futureTask);
return futureTask;
}
@GetMapping(params = "completableFutureWithImmediateValue")
CompletableFuture<Person> getCompletableFutureWithImmediateValue() {
CompletableFuture<Person> future = new CompletableFuture<>();

View File

@ -144,18 +144,6 @@ class AsyncTests {
.andExpect(content().string("Delayed Error"));
}
@Test
void listenableFuture() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("listenableFuture", "true"))
.andExpect(request().asyncStarted())
.andReturn();
this.mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(content().string("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}"));
}
@Test // SPR-12597
void completableFutureWithImmediateValue() throws Exception {
MvcResult mvcResult = this.mockMvc.perform(get("/1").param("completableFutureWithImmediateValue", "true"))
@ -245,13 +233,6 @@ class AsyncTests {
.hasStatus5xxServerError().hasBodyTextEqualTo("Delayed Error");
}
@Test
void listenableFuture() {
assertThat(this.mockMvc.get().uri("/1").param("listenableFuture", "true"))
.hasStatusOk().hasContentTypeCompatibleWith(MediaType.APPLICATION_JSON)
.hasBodyTextEqualTo("{\"name\":\"Joe\",\"someDouble\":0.0,\"someBoolean\":false}");
}
@Test // SPR-12597
void completableFutureWithImmediateValue() {
assertThat(this.mockMvc.get().uri("/1").param("completableFutureWithImmediateValue", "true"))
@ -333,15 +314,6 @@ class AsyncTests {
return result;
}
@RequestMapping(params = "listenableFuture")
@SuppressWarnings({"deprecation", "removal"})
org.springframework.util.concurrent.ListenableFuture<Person> getListenableFuture() {
org.springframework.util.concurrent.ListenableFutureTask<Person> futureTask =
new org.springframework.util.concurrent.ListenableFutureTask<>(() -> new Person("Joe"));
delay(100, futureTask);
return futureTask;
}
@RequestMapping(params = "completableFutureWithImmediateValue")
CompletableFuture<Person> getCompletableFutureWithImmediateValue() {
CompletableFuture<Person> future = new CompletableFuture<>();

View File

@ -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.
@ -96,13 +96,6 @@ public class GenericReactiveTransaction implements ReactiveTransaction {
this.suspendedResources = suspendedResources;
}
@Deprecated(since = "6.1", forRemoval = true)
public GenericReactiveTransaction(@Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean readOnly, boolean debug, @Nullable Object suspendedResources) {
this(null, transaction, newTransaction, newSynchronization, false, readOnly, debug, suspendedResources);
}
@Override
public String getTransactionName() {

View File

@ -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.
@ -102,13 +102,6 @@ public class DefaultTransactionStatus extends AbstractTransactionStatus {
this.suspendedResources = suspendedResources;
}
@Deprecated(since = "6.1", forRemoval = true)
public DefaultTransactionStatus(@Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean readOnly, boolean debug, @Nullable Object suspendedResources) {
this(null, transaction, newTransaction, newSynchronization, false, readOnly, debug, suspendedResources);
}
@Override
public String getTransactionName() {

View File

@ -20,7 +20,6 @@ dependencies {
optional("com.google.code.gson:gson")
optional("com.google.protobuf:protobuf-java-util")
optional("com.rometools:rome")
optional("com.squareup.okhttp3:okhttp")
optional("io.micrometer:context-propagation")
optional("io.netty:netty-buffer")
optional("io.netty:netty-handler")

View File

@ -1961,21 +1961,6 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
return (headers instanceof ReadOnlyHttpHeaders ? headers : new ReadOnlyHttpHeaders(headers.headers));
}
/**
* Remove any read-only wrapper that may have been previously applied around
* the given headers via {@link #readOnlyHttpHeaders(HttpHeaders)}.
* <p>Once the writable instance is mutated, the read-only instance is likely
* to be out of sync and should be discarded.
* @param headers the headers to expose
* @return a writable variant of the headers, or the original headers as-is
* @since 5.1.1
* @deprecated as of 6.2 in favor of {@link #HttpHeaders(MultiValueMap)}.
*/
@Deprecated(since = "6.2", forRemoval = true)
public static HttpHeaders writableHttpHeaders(HttpHeaders headers) {
return new HttpHeaders(headers);
}
/**
* Helps to format HTTP header values, as HTTP header values themselves can
* contain comma-separated values, can become confusing with regular

View File

@ -22,7 +22,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -100,23 +99,6 @@ public class MediaType extends MimeType implements Serializable {
*/
public static final String APPLICATION_FORM_URLENCODED_VALUE = "application/x-www-form-urlencoded";
/**
* Public constant media type for {@code application/graphql+json}.
* @since 5.3.19
* @see <a href="https://github.com/graphql/graphql-over-http/pull/215">GraphQL over HTTP spec change</a>
* @deprecated as of 6.0.3, in favor of {@link MediaType#APPLICATION_GRAPHQL_RESPONSE}
*/
@Deprecated(since = "6.0.3", forRemoval = true)
public static final MediaType APPLICATION_GRAPHQL;
/**
* A String equivalent of {@link MediaType#APPLICATION_GRAPHQL}.
* @since 5.3.19
* @deprecated as of 6.0.3, in favor of {@link MediaType#APPLICATION_GRAPHQL_RESPONSE_VALUE}
*/
@Deprecated(since = "6.0.3", forRemoval = true)
public static final String APPLICATION_GRAPHQL_VALUE = "application/graphql+json";
/**
* Public constant media type for {@code application/graphql-response+json}.
* @since 6.0.3
@ -456,7 +438,6 @@ public class MediaType extends MimeType implements Serializable {
APPLICATION_ATOM_XML = new MediaType("application", "atom+xml");
APPLICATION_CBOR = new MediaType("application", "cbor");
APPLICATION_FORM_URLENCODED = new MediaType("application", "x-www-form-urlencoded");
APPLICATION_GRAPHQL = new MediaType("application", "graphql+json");
APPLICATION_GRAPHQL_RESPONSE = new MediaType("application", "graphql-response+json");
APPLICATION_JSON = new MediaType("application", "json");
APPLICATION_JSON_UTF8 = new MediaType("application", "json", StandardCharsets.UTF_8);
@ -847,141 +828,4 @@ public class MediaType extends MimeType implements Serializable {
return MimeTypeUtils.toString(mediaTypes);
}
/**
* Sorts the given list of {@code MediaType} objects by specificity.
* <p>Given two media types:
* <ol>
* <li>if either media type has a {@linkplain #isWildcardType() wildcard type}, then the media type without the
* wildcard is ordered before the other.</li>
* <li>if the two media types have different {@linkplain #getType() types}, then they are considered equal and
* remain their current order.</li>
* <li>if either media type has a {@linkplain #isWildcardSubtype() wildcard subtype}, then the media type without
* the wildcard is sorted before the other.</li>
* <li>if the two media types have different {@linkplain #getSubtype() subtypes}, then they are considered equal
* and remain their current order.</li>
* <li>if the two media types have different {@linkplain #getQualityValue() quality value}, then the media type
* with the highest quality value is ordered before the other.</li>
* <li>if the two media types have a different amount of {@linkplain #getParameter(String) parameters}, then the
* media type with the most parameters is ordered before the other.</li>
* </ol>
* <p>For example:
* <blockquote>audio/basic &lt; audio/* &lt; *&#047;*</blockquote>
* <blockquote>audio/* &lt; audio/*;q=0.7; audio/*;q=0.3</blockquote>
* <blockquote>audio/basic;level=1 &lt; audio/basic</blockquote>
* <blockquote>audio/basic == text/html</blockquote>
* <blockquote>audio/basic == audio/wave</blockquote>
* @param mediaTypes the list of media types to be sorted
* @deprecated As of 6.0, in favor of {@link MimeTypeUtils#sortBySpecificity(List)}
*/
@Deprecated(since = "6.0", forRemoval = true)
public static void sortBySpecificity(List<MediaType> mediaTypes) {
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
if (mediaTypes.size() > 1) {
mediaTypes.sort(SPECIFICITY_COMPARATOR);
}
}
/**
* Sorts the given list of {@code MediaType} objects by quality value.
* <p>Given two media types:
* <ol>
* <li>if the two media types have different {@linkplain #getQualityValue() quality value}, then the media type
* with the highest quality value is ordered before the other.</li>
* <li>if either media type has a {@linkplain #isWildcardType() wildcard type}, then the media type without the
* wildcard is ordered before the other.</li>
* <li>if the two media types have different {@linkplain #getType() types}, then they are considered equal and
* remain their current order.</li>
* <li>if either media type has a {@linkplain #isWildcardSubtype() wildcard subtype}, then the media type without
* the wildcard is sorted before the other.</li>
* <li>if the two media types have different {@linkplain #getSubtype() subtypes}, then they are considered equal
* and remain their current order.</li>
* <li>if the two media types have a different amount of {@linkplain #getParameter(String) parameters}, then the
* media type with the most parameters is ordered before the other.</li>
* </ol>
* @param mediaTypes the list of media types to be sorted
* @see #getQualityValue()
* @deprecated As of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0", forRemoval = true)
public static void sortByQualityValue(List<MediaType> mediaTypes) {
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
if (mediaTypes.size() > 1) {
mediaTypes.sort(QUALITY_VALUE_COMPARATOR);
}
}
/**
* Sorts the given list of {@code MediaType} objects by specificity as the
* primary criteria and quality value the secondary.
* @deprecated As of 6.0, in favor of {@link MimeTypeUtils#sortBySpecificity(List)}
*/
@Deprecated(since = "6.0")
public static void sortBySpecificityAndQuality(List<MediaType> mediaTypes) {
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
if (mediaTypes.size() > 1) {
mediaTypes.sort(MediaType.SPECIFICITY_COMPARATOR.thenComparing(MediaType.QUALITY_VALUE_COMPARATOR));
}
}
/**
* Comparator used by {@link #sortByQualityValue(List)}.
* @deprecated As of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0", forRemoval = true)
public static final Comparator<MediaType> QUALITY_VALUE_COMPARATOR = (mediaType1, mediaType2) -> {
double quality1 = mediaType1.getQualityValue();
double quality2 = mediaType2.getQualityValue();
int qualityComparison = Double.compare(quality2, quality1);
if (qualityComparison != 0) {
return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3
}
else if (mediaType1.isWildcardType() && !mediaType2.isWildcardType()) { // */* < audio/*
return 1;
}
else if (mediaType2.isWildcardType() && !mediaType1.isWildcardType()) { // audio/* > */*
return -1;
}
else if (!mediaType1.getType().equals(mediaType2.getType())) { // audio/basic == text/html
return 0;
}
else { // mediaType1.getType().equals(mediaType2.getType())
if (mediaType1.isWildcardSubtype() && !mediaType2.isWildcardSubtype()) { // audio/* < audio/basic
return 1;
}
else if (mediaType2.isWildcardSubtype() && !mediaType1.isWildcardSubtype()) { // audio/basic > audio/*
return -1;
}
else if (!mediaType1.getSubtype().equals(mediaType2.getSubtype())) { // audio/basic == audio/wave
return 0;
}
else {
int paramsSize1 = mediaType1.getParameters().size();
int paramsSize2 = mediaType2.getParameters().size();
return Integer.compare(paramsSize2, paramsSize1); // audio/basic;level=1 < audio/basic
}
}
};
/**
* Comparator used by {@link #sortBySpecificity(List)}.
* @deprecated As of 6.0, with no direct replacement
*/
@Deprecated(since = "6.0", forRemoval = true)
@SuppressWarnings("removal")
public static final Comparator<MediaType> SPECIFICITY_COMPARATOR = new SpecificityComparator<>() {
@Override
protected int compareParameters(MediaType mediaType1, MediaType mediaType2) {
double quality1 = mediaType1.getQualityValue();
double quality2 = mediaType2.getQualityValue();
int qualityComparison = Double.compare(quality2, quality1);
if (qualityComparison != 0) {
return qualityComparison; // audio/*;q=0.7 < audio/*;q=0.3
}
return super.compareParameters(mediaType1, mediaType2);
}
};
}

View File

@ -42,19 +42,6 @@ public interface ClientHttpResponse extends HttpInputMessage, Closeable {
*/
HttpStatusCode getStatusCode() throws IOException;
/**
* Get the HTTP status code as an integer.
* @return the HTTP status as an integer value
* @throws IOException in case of I/O errors
* @since 3.1.1
* @see #getStatusCode()
* @deprecated in favor of {@link #getStatusCode()}, for removal in 7.0
*/
@Deprecated(since = "6.0", forRemoval = true)
default int getRawStatusCode() throws IOException {
return getStatusCode().value();
}
/**
* Get the HTTP status text of the response.
* @return the HTTP status text

View File

@ -209,18 +209,6 @@ public class HttpComponentsClientHttpRequestFactory implements ClientHttpRequest
this.readTimeout = readTimeout.toMillis();
}
/**
* Indicates whether this request factory should buffer the request body internally.
* <p>Default is {@code true}. When sending large amounts of data via POST or PUT, it is
* recommended to change this property to {@code false}, so as not to run out of memory.
* @since 4.0
* @deprecated since 6.1 requests are never buffered, as if this property is {@code false}
*/
@Deprecated(since = "6.1", forRemoval = true)
public void setBufferRequestBody(boolean bufferRequestBody) {
// no-op
}
/**
* Configure a factory to pre-create the {@link HttpContext} for each request.
* <p>This may be useful for example in mutual TLS authentication where a

View File

@ -1,142 +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.http.client;
import java.io.IOException;
import java.net.URI;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okio.BufferedSink;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
* {@link ClientHttpRequest} implementation based on OkHttp 3.x.
*
* <p>Created via the {@link OkHttp3ClientHttpRequestFactory}.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 4.3
* @deprecated since 6.1, in favor of other HTTP client libraries;
* scheduled for removal in 7.0
*/
@Deprecated(since = "6.1", forRemoval = true)
class OkHttp3ClientHttpRequest extends AbstractStreamingClientHttpRequest {
private final OkHttpClient client;
private final URI uri;
private final HttpMethod method;
public OkHttp3ClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method) {
this.client = client;
this.uri = uri;
this.method = method;
}
@Override
public HttpMethod getMethod() {
return this.method;
}
@Override
public URI getURI() {
return this.uri;
}
@Override
@SuppressWarnings("removal")
protected ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException {
RequestBody requestBody;
if (body != null) {
requestBody = new BodyRequestBody(headers, body);
}
else if (okhttp3.internal.http.HttpMethod.requiresRequestBody(getMethod().name())) {
String header = headers.getFirst(HttpHeaders.CONTENT_TYPE);
MediaType contentType = (header != null) ? MediaType.parse(header) : null;
requestBody = RequestBody.create(contentType, new byte[0]);
}
else {
requestBody = null;
}
Request.Builder builder = new Request.Builder()
.url(this.uri.toURL());
builder.method(this.method.name(), requestBody);
headers.forEach((headerName, headerValues) -> {
for (String headerValue : headerValues) {
builder.addHeader(headerName, headerValue);
}
});
Request request = builder.build();
return new OkHttp3ClientHttpResponse(this.client.newCall(request).execute());
}
private static class BodyRequestBody extends RequestBody {
private final HttpHeaders headers;
private final Body body;
public BodyRequestBody(HttpHeaders headers, Body body) {
this.headers = headers;
this.body = body;
}
@Override
public long contentLength() {
return this.headers.getContentLength();
}
@Nullable
@Override
public MediaType contentType() {
String contentType = this.headers.getFirst(HttpHeaders.CONTENT_TYPE);
if (StringUtils.hasText(contentType)) {
return MediaType.parse(contentType);
}
else {
return null;
}
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
this.body.writeTo(sink.outputStream());
}
@Override
public boolean isOneShot() {
return !this.body.repeatable();
}
}
}

View File

@ -1,153 +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.http.client;
import java.io.IOException;
import java.net.URI;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.http.HttpMethod;
import org.springframework.util.Assert;
/**
* {@link ClientHttpRequestFactory} implementation that uses
* <a href="https://square.github.io/okhttp/">OkHttp</a> 3.x to create requests.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 4.3
* @deprecated since 6.1, in favor of other {@link ClientHttpRequestFactory} implementations;
* scheduled for removal in 7.0
*/
@Deprecated(since = "6.1", forRemoval = true)
public class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {
private OkHttpClient client;
private final boolean defaultClient;
/**
* Create a factory with a default {@link OkHttpClient} instance.
*/
public OkHttp3ClientHttpRequestFactory() {
this.client = new OkHttpClient();
this.defaultClient = true;
}
/**
* Create a factory with the given {@link OkHttpClient} instance.
* @param client the client to use
*/
public OkHttp3ClientHttpRequestFactory(OkHttpClient client) {
Assert.notNull(client, "OkHttpClient must not be null");
this.client = client;
this.defaultClient = false;
}
/**
* Set the underlying read timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
*/
public void setReadTimeout(int readTimeout) {
this.client = this.client.newBuilder()
.readTimeout(readTimeout, TimeUnit.MILLISECONDS)
.build();
}
/**
* Set the underlying read timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
* @since 6.1
*/
public void setReadTimeout(Duration readTimeout) {
this.client = this.client.newBuilder()
.readTimeout(readTimeout)
.build();
}
/**
* Set the underlying write timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
*/
public void setWriteTimeout(int writeTimeout) {
this.client = this.client.newBuilder()
.writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
.build();
}
/**
* Set the underlying write timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
* @since 6.1
*/
public void setWriteTimeout(Duration writeTimeout) {
this.client = this.client.newBuilder()
.writeTimeout(writeTimeout)
.build();
}
/**
* Set the underlying connect timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
*/
public void setConnectTimeout(int connectTimeout) {
this.client = this.client.newBuilder()
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.build();
}
/**
* Set the underlying connect timeout in milliseconds.
* A value of 0 specifies an infinite timeout.
* @since 6.1
*/
public void setConnectTimeout(Duration connectTimeout) {
this.client = this.client.newBuilder()
.connectTimeout(connectTimeout)
.build();
}
@Override
@SuppressWarnings("removal")
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
return new OkHttp3ClientHttpRequest(this.client, uri, httpMethod);
}
@Override
public void destroy() throws IOException {
if (this.defaultClient) {
// Clean up the client if we created it in the constructor
Cache cache = this.client.cache();
if (cache != null) {
cache.close();
}
this.client.dispatcher().executorService().shutdown();
this.client.connectionPool().evictAll();
}
}
}

View File

@ -1,94 +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.http.client;
import java.io.IOException;
import java.io.InputStream;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatusCode;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
* {@link ClientHttpResponse} implementation based on OkHttp 3.x.
*
* @author Luciano Leggieri
* @author Arjen Poutsma
* @author Roy Clarkson
* @since 4.3
* @deprecated since 6.1, in favor of other HTTP client libraries;
* scheduled for removal in 7.0
*/
@Deprecated(since = "6.1", forRemoval = true)
class OkHttp3ClientHttpResponse implements ClientHttpResponse {
private final Response response;
@Nullable
private volatile HttpHeaders headers;
public OkHttp3ClientHttpResponse(Response response) {
Assert.notNull(response, "Response must not be null");
this.response = response;
}
@Override
public HttpStatusCode getStatusCode() throws IOException {
return HttpStatusCode.valueOf(this.response.code());
}
@Override
public String getStatusText() {
return this.response.message();
}
@Override
public InputStream getBody() throws IOException {
ResponseBody body = this.response.body();
return (body != null ? body.byteStream() : InputStream.nullInputStream());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = this.headers;
if (headers == null) {
headers = new HttpHeaders();
for (String headerName : this.response.headers().names()) {
for (String headerValue : this.response.headers(headerName)) {
headers.add(headerName, headerValue);
}
}
this.headers = headers;
}
return headers;
}
@Override
public void close() {
ResponseBody body = this.response.body();
if (body != null) {
body.close();
}
}
}

View File

@ -81,24 +81,6 @@ final class ReactorClientHttpRequest extends AbstractStreamingClientHttpRequest
this.exchangeTimeout = exchangeTimeout;
}
/**
* Original constructor with timeout values.
* @deprecated without a replacement; readTimeout is now applied to the
* underlying client via {@link HttpClient#responseTimeout(Duration)}, and the
* value passed here is not used; exchangeTimeout is deprecated and superseded
* by Reactor Netty timeout configuration, but applied if set.
*/
@Deprecated(since = "6.2", forRemoval = true)
public ReactorClientHttpRequest(
HttpClient httpClient, URI uri, HttpMethod method,
@Nullable Duration exchangeTimeout, @Nullable Duration readTimeout) {
this.httpClient = httpClient;
this.method = method;
this.uri = uri;
this.exchangeTimeout = exchangeTimeout;
}
@Override
public HttpMethod getMethod() {

View File

@ -180,36 +180,6 @@ public class ReactorClientHttpRequestFactory implements ClientHttpRequestFactory
setReadTimeout(Duration.ofMillis(readTimeout));
}
/**
* Set the timeout for the HTTP exchange in milliseconds.
* <p>By default, as of 6.2 this is no longer set.
* @see #setConnectTimeout(int)
* @see #setReadTimeout(Duration)
* @see <a href="https://projectreactor.io/docs/netty/release/reference/index.html#timeout-configuration">Timeout Configuration</a>
* @deprecated as of 6.2 and no longer set by default (previously 5 seconds)
* in favor of using Reactor Netty HttpClient timeout configuration.
*/
@Deprecated(since = "6.2", forRemoval = true)
public void setExchangeTimeout(long exchangeTimeout) {
Assert.isTrue(exchangeTimeout > 0, "Timeout must be a positive value");
this.exchangeTimeout = Duration.ofMillis(exchangeTimeout);
}
/**
* Variant of {@link #setExchangeTimeout(long)} with a Duration value.
* <p>By default, as of 6.2 this is no longer set.
* @see #setConnectTimeout(int)
* @see #setReadTimeout(Duration)
* @see <a href="https://projectreactor.io/docs/netty/release/reference/index.html#timeout-configuration">Timeout Configuration</a>
* @deprecated as of 6.2 and no longer set by default (previously 5 seconds)
* in favor of using Reactor Netty HttpClient timeout configuration.
*/
@Deprecated(since = "6.2", forRemoval = true)
public void setExchangeTimeout(Duration exchangeTimeout) {
Assert.notNull(exchangeTimeout, "ExchangeTimeout must not be null");
setExchangeTimeout((int) exchangeTimeout.toMillis());
}
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {

View File

@ -18,12 +18,10 @@ package org.springframework.http.client;
import java.io.IOException;
import java.io.InputStream;
import java.time.Duration;
import io.netty.buffer.ByteBuf;
import org.reactivestreams.FlowAdapters;
import reactor.netty.Connection;
import reactor.netty.http.client.HttpClient;
import reactor.netty.http.client.HttpClientResponse;
import org.springframework.http.HttpHeaders;
@ -64,21 +62,6 @@ final class ReactorClientHttpResponse implements ClientHttpResponse {
new Netty4HeadersAdapter(response.responseHeaders()));
}
/**
* Original constructor.
* @deprecated without a replacement; readTimeout is now applied to the
* underlying client via {@link HttpClient#responseTimeout(Duration)}, and the
* value passed here is not used.
*/
@Deprecated(since = "6.2", forRemoval = true)
public ReactorClientHttpResponse(
HttpClientResponse response, Connection connection, @Nullable Duration readTimeout) {
this.response = response;
this.connection = connection;
this.headers = HttpHeaders.readOnlyHttpHeaders(new Netty4HeadersAdapter(response.responseHeaders()));
}
@Override
public HttpStatusCode getStatusCode() {

View File

@ -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.http.client;
import java.util.function.Function;
import reactor.netty.http.client.HttpClient;
/**
* Reactor-Netty implementation of {@link ClientHttpRequestFactory}.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 6.1
* @deprecated in favor of the renamed {@link ReactorClientHttpRequestFactory}
*/
@Deprecated(since = "6.2", forRemoval = true)
public class ReactorNettyClientRequestFactory extends ReactorClientHttpRequestFactory {
/**
* Superseded by {@link ReactorClientHttpRequestFactory}.
* @see ReactorClientHttpRequestFactory#ReactorClientHttpRequestFactory()
*/
public ReactorNettyClientRequestFactory() {
super();
}
/**
* Superseded by {@link ReactorClientHttpRequestFactory}.
* @see ReactorClientHttpRequestFactory#ReactorClientHttpRequestFactory(HttpClient)
*/
public ReactorNettyClientRequestFactory(HttpClient httpClient) {
super(httpClient);
}
/**
* Superseded by {@link ReactorClientHttpRequestFactory}.
* @see ReactorClientHttpRequestFactory#ReactorClientHttpRequestFactory(ReactorResourceFactory, Function)
*/
public ReactorNettyClientRequestFactory(ReactorResourceFactory resourceFactory, Function<HttpClient, HttpClient> mapper) {
super(resourceFactory, mapper);
}
}

View File

@ -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.
@ -59,24 +59,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
this.proxy = proxy;
}
/**
* Indicate whether this request factory should buffer the
* {@linkplain ClientHttpRequest#getBody() request body} internally.
* <p>Default is {@code true}. When sending large amounts of data via POST or PUT,
* it is recommended to change this property to {@code false}, so as not to run
* out of memory. This will result in a {@link ClientHttpRequest} that either
* streams directly to the underlying {@link HttpURLConnection} (if the
* {@link org.springframework.http.HttpHeaders#getContentLength() Content-Length}
* is known in advance), or that will use "Chunked transfer encoding"
* (if the {@code Content-Length} is not known in advance).
* @see #setChunkSize(int)
* @see HttpURLConnection#setFixedLengthStreamingMode(int)
* @deprecated since 6.1 requests are never buffered, as if this property is {@code false}
*/
@Deprecated(since = "6.1", forRemoval = true)
public void setBufferRequestBody(boolean bufferRequestBody) {
}
/**
* Set the number of bytes to write in each chunk when not buffering request
* bodies locally.
@ -134,20 +116,6 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
this.readTimeout = (int) readTimeout.toMillis();
}
/**
* Set if the underlying URLConnection can be set to 'output streaming' mode.
* Default is {@code true}.
* <p>When output streaming is enabled, authentication and redirection cannot be handled automatically.
* If output streaming is disabled, the {@link HttpURLConnection#setFixedLengthStreamingMode} and
* {@link HttpURLConnection#setChunkedStreamingMode} methods of the underlying connection will never
* be called.
* @param outputStreaming if output streaming is enabled
* @deprecated as of 6.1 requests are always streamed, as if this property is {@code true}
*/
@Deprecated(since = "6.1", forRemoval = true)
public void setOutputStreaming(boolean outputStreaming) {
}
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {

View File

@ -46,18 +46,6 @@ public interface ClientHttpResponse extends ReactiveHttpInputMessage {
*/
HttpStatusCode getStatusCode();
/**
* Return the HTTP status code as an integer.
* @return the HTTP status as an integer value
* @since 5.0.6
* @see #getStatusCode()
* @deprecated in favor of {@link #getStatusCode()}, for removal in 7.0
*/
@Deprecated(since = "6.0", forRemoval = true)
default int getRawStatusCode() {
return getStatusCode().value();
}
/**
* Return a read-only map of response cookies received from the server.
*/

View File

@ -76,14 +76,6 @@ class ReactorNetty2ServerHttpResponse extends AbstractServerHttpResponse impleme
return (status != null ? status : HttpStatusCode.valueOf(this.response.status().code()));
}
@Override
@Deprecated
@SuppressWarnings("removal")
public Integer getRawStatusCode() {
Integer status = super.getRawStatusCode();
return (status != null ? status : this.response.status().code());
}
@Override
protected void applyStatusCode() {
HttpStatusCode status = super.getStatusCode();

View File

@ -75,14 +75,6 @@ class ReactorServerHttpResponse extends AbstractServerHttpResponse implements Ze
return (status != null ? status : HttpStatusCode.valueOf(this.response.status().code()));
}
@Override
@Deprecated
@SuppressWarnings("removal")
public Integer getRawStatusCode() {
Integer status = super.getRawStatusCode();
return (status != null ? status : this.response.status().code());
}
@Override
protected void applyStatusCode() {
HttpStatusCode status = super.getStatusCode();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@ -60,20 +60,6 @@ public interface ServerHttpResponse extends ReactiveHttpOutputMessage {
return setStatusCode(value != null ? HttpStatusCode.valueOf(value) : null);
}
/**
* Return the status code that has been set, or otherwise fall back on the
* status of the response from the underlying server. The return value may
* be {@code null} if there is no default value from the underlying server.
* @since 5.2.4
* @deprecated in favor of {@link #getStatusCode()}, for removal in 7.0
*/
@Deprecated(since = "6.0", forRemoval = true)
@Nullable
default Integer getRawStatusCode() {
HttpStatusCode httpStatus = getStatusCode();
return (httpStatus != null ? httpStatus.value() : null);
}
/**
* Return a mutable map with the cookies to send to the server.
*/

View File

@ -71,14 +71,6 @@ public class ServerHttpResponseDecorator implements ServerHttpResponse {
return getDelegate().setRawStatusCode(value);
}
@Override
@Nullable
@Deprecated
@SuppressWarnings("removal")
public Integer getRawStatusCode() {
return getDelegate().getRawStatusCode();
}
@Override
public HttpHeaders getHeaders() {
return getDelegate().getHeaders();

View File

@ -104,14 +104,6 @@ class ServletServerHttpResponse extends AbstractListenerServerHttpResponse {
return (status != null ? status : HttpStatusCode.valueOf(this.response.getStatus()));
}
@Override
@Deprecated
@SuppressWarnings("removal")
public Integer getRawStatusCode() {
Integer status = super.getRawStatusCode();
return (status != null ? status : this.response.getStatus());
}
@Override
protected void applyStatusCode() {
HttpStatusCode status = super.getStatusCode();

View File

@ -87,14 +87,6 @@ class UndertowServerHttpResponse extends AbstractListenerServerHttpResponse impl
return (status != null ? status : HttpStatusCode.valueOf(this.exchange.getStatusCode()));
}
@Override
@Deprecated
@SuppressWarnings("removal")
public Integer getRawStatusCode() {
Integer status = super.getRawStatusCode();
return (status != null ? status : this.exchange.getStatusCode());
}
@Override
protected void applyStatusCode() {
HttpStatusCode status = super.getStatusCode();

View File

@ -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.
@ -66,25 +66,6 @@ public class MissingServletRequestParameterException extends MissingRequestValue
getBody().setDetail(initBodyDetail(this.parameterName));
}
/**
* Constructor for use when a value was present but converted to {@code null}.
* @param parameterName the name of the missing parameter
* @param parameterType the expected type of the missing parameter
* @param missingAfterConversion whether the value became null after conversion
* @since 5.3.6
* @deprecated in favor of {@link #MissingServletRequestParameterException(String, MethodParameter, boolean)}
*/
@Deprecated(since = "6.1", forRemoval = true)
public MissingServletRequestParameterException(
String parameterName, String parameterType, boolean missingAfterConversion) {
super("", missingAfterConversion, null, new Object[] {parameterName});
this.parameterName = parameterName;
this.parameterType = parameterType;
this.parameter = null;
getBody().setDetail(initBodyDetail(this.parameterName));
}
private static String initBodyDetail(String name) {
return "Required parameter '" + name + "' is not present.";
}

View File

@ -136,31 +136,9 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
*/
@Override
public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
// For backwards compatibility try handle(response) first
HandleErrorResponseDecorator decorator = new HandleErrorResponseDecorator(response);
handleError(decorator);
if (decorator.isHandled()) {
return;
}
handleError(response, response.getStatusCode(), url, method);
}
@SuppressWarnings("removal")
@Override
public void handleError(ClientHttpResponse response) throws IOException {
// Called via handleError(url, method, response)
if (response instanceof HandleErrorResponseDecorator decorator) {
decorator.setNotHandled();
return;
}
// Called directly, so do handle
handleError(response, response.getStatusCode(), null, null);
}
/**
* Handle the error based on the resolved status code.
* <p>The default implementation delegates to
@ -288,22 +266,4 @@ public class DefaultResponseErrorHandler implements ResponseErrorHandler {
};
}
private static class HandleErrorResponseDecorator extends ClientHttpResponseDecorator {
private boolean handled = true;
public HandleErrorResponseDecorator(ClientHttpResponse delegate) {
super(delegate);
}
public void setNotHandled() {
this.handled = false;
}
public boolean isHandled() {
return this.handled;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 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.
@ -52,19 +52,6 @@ public interface ResponseErrorHandler {
* @since 5.0
*/
default void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
handleError(response);
}
/**
* Handle the error in the given response.
* <p>This method is only called when {@link #hasError(ClientHttpResponse)}
* has returned {@code true}.
* @param response the response with the error
* @throws IOException in case of I/O errors
* @deprecated in favor of {@link #handleError(URI, HttpMethod, ClientHttpResponse)}
*/
@Deprecated(since = "6.2.1", forRemoval = true)
default void handleError(ClientHttpResponse response) throws IOException {
}
}

View File

@ -1,176 +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.web.filter.reactive;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
import reactor.core.observability.DefaultSignalListener;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.observation.DefaultServerRequestObservationConvention;
import org.springframework.http.server.reactive.observation.ServerHttpObservationDocumentation;
import org.springframework.http.server.reactive.observation.ServerRequestObservationContext;
import org.springframework.http.server.reactive.observation.ServerRequestObservationConvention;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
/**
* {@link org.springframework.web.server.WebFilter} that creates {@link Observation observations}
* for HTTP exchanges. This collects information about the execution time and
* information gathered from the {@link ServerRequestObservationContext}.
* <p>Web Frameworks can fetch the current {@link ServerRequestObservationContext context}
* as a {@link #CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE request attribute} and contribute
* additional information to it.
* The configured {@link ServerRequestObservationConvention} will use this context to collect
* {@link io.micrometer.common.KeyValue metadata} and attach it to the observation.
*
* @author Brian Clozel
* @since 6.0
* @deprecated since 6.1 in favor of {@link WebHttpHandlerBuilder}.
*/
@Deprecated(since = "6.1", forRemoval = true)
public class ServerHttpObservationFilter implements WebFilter {
/**
* Name of the request attribute holding the {@link ServerRequestObservationContext context} for the current observation.
*/
public static final String CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE = ServerHttpObservationFilter.class.getName() + ".context";
private static final ServerRequestObservationConvention DEFAULT_OBSERVATION_CONVENTION = new DefaultServerRequestObservationConvention();
private final ObservationRegistry observationRegistry;
private final ServerRequestObservationConvention observationConvention;
/**
* Create an {@code HttpRequestsObservationWebFilter} that records observations
* against the given {@link ObservationRegistry}. The default
* {@link DefaultServerRequestObservationConvention convention} will be used.
* @param observationRegistry the registry to use for recording observations
*/
public ServerHttpObservationFilter(ObservationRegistry observationRegistry) {
this(observationRegistry, DEFAULT_OBSERVATION_CONVENTION);
}
/**
* Create an {@code HttpRequestsObservationWebFilter} that records observations
* against the given {@link ObservationRegistry} with a custom convention.
* @param observationRegistry the registry to use for recording observations
* @param observationConvention the convention to use for all recorded observations
*/
public ServerHttpObservationFilter(ObservationRegistry observationRegistry, ServerRequestObservationConvention observationConvention) {
this.observationRegistry = observationRegistry;
this.observationConvention = observationConvention;
}
/**
* Get the current {@link ServerRequestObservationContext observation context} from the given request, if available.
* @param exchange the current exchange
* @return the current observation context
*/
public static Optional<ServerRequestObservationContext> findObservationContext(ServerWebExchange exchange) {
return Optional.ofNullable(exchange.getAttribute(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE));
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerRequestObservationContext observationContext = new ServerRequestObservationContext(exchange.getRequest(),
exchange.getResponse(), exchange.getAttributes());
exchange.getAttributes().put(CURRENT_OBSERVATION_CONTEXT_ATTRIBUTE, observationContext);
return chain.filter(exchange).tap(() -> new ObservationSignalListener(observationContext));
}
private final class ObservationSignalListener extends DefaultSignalListener<Void> {
private static final Set<String> DISCONNECTED_CLIENT_EXCEPTIONS = Set.of("AbortedException",
"ClientAbortException", "EOFException", "EofException");
private final ServerRequestObservationContext observationContext;
private final Observation observation;
private final AtomicBoolean observationRecorded = new AtomicBoolean();
ObservationSignalListener(ServerRequestObservationContext observationContext) {
this.observationContext = observationContext;
this.observation = ServerHttpObservationDocumentation.HTTP_REACTIVE_SERVER_REQUESTS.observation(observationConvention,
DEFAULT_OBSERVATION_CONVENTION, () -> observationContext, observationRegistry);
}
@Override
public Context addToContext(Context originalContext) {
return originalContext.put(ObservationThreadLocalAccessor.KEY, this.observation);
}
@Override
public void doFirst() throws Throwable {
this.observation.start();
}
@Override
public void doOnCancel() throws Throwable {
if (this.observationRecorded.compareAndSet(false, true)) {
this.observationContext.setConnectionAborted(true);
this.observation.stop();
}
}
@Override
public void doOnComplete() throws Throwable {
if (this.observationRecorded.compareAndSet(false, true)) {
doOnTerminate(this.observationContext);
}
}
@Override
public void doOnError(Throwable error) throws Throwable {
if (this.observationRecorded.compareAndSet(false, true)) {
if (DISCONNECTED_CLIENT_EXCEPTIONS.contains(error.getClass().getSimpleName())) {
this.observationContext.setConnectionAborted(true);
}
this.observationContext.setError(error);
doOnTerminate(this.observationContext);
}
}
private void doOnTerminate(ServerRequestObservationContext context) {
ServerHttpResponse response = context.getResponse();
if (response != null) {
if (response.isCommitted()) {
this.observation.stop();
}
else {
response.beforeCommit(() -> {
this.observation.stop();
return Mono.empty();
});
}
}
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 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.
@ -88,11 +88,10 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
return "Resolved [" + className + ": " + message + "] for HTTP " + request.getMethod() + " " + path;
}
@SuppressWarnings("deprecation")
private boolean updateResponse(ServerHttpResponse response, Throwable ex) {
boolean result = false;
HttpStatusCode statusCode = determineStatus(ex);
int code = (statusCode != null ? statusCode.value() : determineRawStatusCode(ex));
int code = (statusCode != null ? statusCode.value() : -1);
if (code != -1) {
if (response.setStatusCode(statusCode)) {
if (ex instanceof ResponseStatusException responseStatusException) {
@ -127,19 +126,4 @@ public class ResponseStatusExceptionHandler implements WebExceptionHandler {
}
}
/**
* Determine the raw status code for the given exception.
* @param ex the exception to check
* @return the associated HTTP status code, or -1 if it can't be derived.
* @since 5.3
* @deprecated in favor of {@link #determineStatus(Throwable)}, for removal in 7.0
*/
@Deprecated(since = "6.0", forRemoval = true)
protected int determineRawStatusCode(Throwable ex) {
if (ex instanceof ResponseStatusException responseStatusException) {
return responseStatusException.getStatusCode().value();
}
return -1;
}
}

View File

@ -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.
@ -18,9 +18,6 @@ package org.springframework.web.service.invoker;
import java.time.Duration;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpHeaders;
@ -35,9 +32,7 @@ import org.springframework.util.Assert;
* @author Rossen Stoyanchev
* @since 6.1
*/
@SuppressWarnings("removal")
public abstract class AbstractReactorHttpExchangeAdapter
implements ReactorHttpExchangeAdapter, org.springframework.web.service.invoker.HttpClientAdapter {
public abstract class AbstractReactorHttpExchangeAdapter implements ReactorHttpExchangeAdapter {
private ReactiveAdapterRegistry reactiveAdapterRegistry = ReactiveAdapterRegistry.getSharedInstance();
@ -126,46 +121,4 @@ public abstract class AbstractReactorHttpExchangeAdapter
return entity;
}
// HttpClientAdapter implementation
@Override
public Mono<Void> requestToVoid(HttpRequestValues requestValues) {
return exchangeForMono(requestValues);
}
@Override
public Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues) {
return exchangeForHeadersMono(requestValues);
}
@Override
public <T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
return exchangeForBodyMono(requestValues, bodyType);
}
@Override
public <T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
return exchangeForBodyFlux(requestValues, bodyType);
}
@Override
public Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues) {
return exchangeForBodilessEntityMono(requestValues);
}
@Override
public <T> Mono<ResponseEntity<T>> requestToEntity(
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
return exchangeForEntityMono(requestValues, bodyType);
}
@Override
public <T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
return exchangeForEntityFlux(requestValues, bodyType);
}
}

View File

@ -1,147 +0,0 @@
/*
* Copyright 2002-2023 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.web.service.invoker;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
/**
* Contract to abstract the underlying HTTP client and decouple it from the
* {@linkplain HttpServiceProxyFactory#createClient(Class) HTTP service proxy}.
*
* @author Rossen Stoyanchev
* @author Olga Maciaszek-Sharma
* @since 6.0
* @deprecated in favor of {@link ReactorHttpExchangeAdapter}
*/
@Deprecated(since = "6.1", forRemoval = true)
public interface HttpClientAdapter {
/**
* Perform the given request, and release the response content, if any.
* @param requestValues the request to perform
* @return {@code Mono} that completes when the request is fully executed
* and the response content is released.
*/
Mono<Void> requestToVoid(HttpRequestValues requestValues);
/**
* Perform the given request, release the response content, and return the
* response headers.
* @param requestValues the request to perform
* @return {@code Mono} that returns the response headers the request is
* fully executed and the response content released.
*/
Mono<HttpHeaders> requestToHeaders(HttpRequestValues requestValues);
/**
* Perform the given request and decode the response content to the given type.
* @param requestValues the request to perform
* @param bodyType the target type to decode to
* @return {@code Mono} that returns the decoded response.
* @param <T> the type the response is decoded to
*/
<T> Mono<T> requestToBody(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
/**
* Perform the given request and decode the response content to a stream with
* elements of the given type.
* @param requestValues the request to perform
* @param bodyType the target stream element type to decode to
* @return {@code Flux} with decoded stream elements.
* @param <T> the type the response is decoded to
*/
<T> Flux<T> requestToBodyFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
/**
* Variant of {@link #requestToVoid(HttpRequestValues)} with additional
* access to the response status and headers.
*/
Mono<ResponseEntity<Void>> requestToBodilessEntity(HttpRequestValues requestValues);
/**
* Variant of {@link #requestToBody(HttpRequestValues, ParameterizedTypeReference)}
* with additional access to the response status and headers.
*/
<T> Mono<ResponseEntity<T>> requestToEntity(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
/**
* Variant of {@link #requestToBodyFlux(HttpRequestValues, ParameterizedTypeReference)}
* with additional access to the response status and headers.
*/
<T> Mono<ResponseEntity<Flux<T>>> requestToEntityFlux(HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType);
/**
* Adapt this instance to {@link ReactorHttpExchangeAdapter}.
* @since 6.1
*/
default ReactorHttpExchangeAdapter asReactorExchangeAdapter() {
return new AbstractReactorHttpExchangeAdapter() {
@Override
public boolean supportsRequestAttributes() {
return true;
}
@Override
public Mono<Void> exchangeForMono(HttpRequestValues values) {
return HttpClientAdapter.this.requestToVoid(values);
}
@Override
public Mono<HttpHeaders> exchangeForHeadersMono(HttpRequestValues values) {
return HttpClientAdapter.this.requestToHeaders(values);
}
@Override
public <T> Mono<T> exchangeForBodyMono(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
return HttpClientAdapter.this.requestToBody(values, bodyType);
}
@Override
public <T> Flux<T> exchangeForBodyFlux(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
return HttpClientAdapter.this.requestToBodyFlux(values, bodyType);
}
@Override
public Mono<ResponseEntity<Void>> exchangeForBodilessEntityMono(HttpRequestValues values) {
return HttpClientAdapter.this.requestToBodilessEntity(values);
}
@Override
public <T> Mono<ResponseEntity<T>> exchangeForEntityMono(
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
return HttpClientAdapter.this.requestToEntity(requestValues, bodyType);
}
@Override
public <T> Mono<ResponseEntity<Flux<T>>> exchangeForEntityFlux(
HttpRequestValues requestValues, ParameterizedTypeReference<T> bodyType) {
return HttpClientAdapter.this.requestToEntityFlux(requestValues, bodyType);
}
};
}
}

View File

@ -86,21 +86,6 @@ public class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
this.contentCacheLimit = (cacheLimit > 0 ? cacheLimit : null);
}
/**
* Create a new ContentCachingRequestWrapper for the given servlet request.
* @param request the original servlet request
* @deprecated in favor of {@link #ContentCachingRequestWrapper(HttpServletRequest, int)}
* in order to explicitly choose the cache limit
*/
@Deprecated(since = "6.2.1", forRemoval = true)
public ContentCachingRequestWrapper(HttpServletRequest request) {
super(request);
int contentLength = request.getContentLength();
this.cachedContent = (contentLength > 0 ?
new FastByteArrayOutputStream(contentLength) : new FastByteArrayOutputStream());
this.contentCacheLimit = null;
}
@Override
public ServletInputStream getInputStream() throws IOException {

View File

@ -30,7 +30,6 @@ import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.http.HttpRequest;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
@ -243,34 +242,6 @@ public class UriComponentsBuilder implements UriBuilder, Cloneable {
return fromUriString(httpUrl);
}
/**
* Create a new {@code UriComponents} object from the URI associated with
* the given HttpRequest while also overlaying with values from the headers
* "Forwarded" (<a href="https://tools.ietf.org/html/rfc7239">RFC 7239</a>),
* or "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" if
* "Forwarded" is not found.
* @param request the source request
* @return the URI components of the URI
* @since 4.1.5
* @deprecated in favor of {@link ForwardedHeaderUtils#adaptFromForwardedHeaders};
* to be removed in 7.0
*/
@Deprecated(since = "6.1", forRemoval = true)
public static UriComponentsBuilder fromHttpRequest(HttpRequest request) {
return ForwardedHeaderUtils.adaptFromForwardedHeaders(request.getURI(), request.getHeaders());
}
/**
* Create an instance by parsing the "Origin" header of an HTTP request.
* @see <a href="https://tools.ietf.org/html/rfc6454">RFC 6454</a>
* @deprecated in favor of {@link UriComponentsBuilder#fromUriString(String)};
* to be removed in 7.0
*/
@Deprecated(since = "6.2", forRemoval = true)
public static UriComponentsBuilder fromOriginHeader(String origin) {
return fromUriString(origin);
}
// Encode methods

View File

@ -19,7 +19,6 @@ package org.springframework.http;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
@ -279,221 +278,6 @@ class MediaTypeTests {
assertThat(audioBasic.isLessSpecific(MediaType.TEXT_HTML)).isFalse();
}
@Test
void specificityComparator() {
MediaType audioBasic = new MediaType("audio", "basic");
MediaType audioWave = new MediaType("audio", "wave");
MediaType audio = new MediaType("audio");
MediaType audio03 = new MediaType("audio", "*", 0.3);
MediaType audio07 = new MediaType("audio", "*", 0.7);
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
MediaType textHtml = new MediaType("text", "html");
MediaType allXml = new MediaType("application", "*+xml");
MediaType all = MediaType.ALL;
@SuppressWarnings("removal")
Comparator<MediaType> comp = MediaType.SPECIFICITY_COMPARATOR;
// equal
assertThat(comp.compare(audioBasic, audioBasic)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audio, audio)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audio07, audio07)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audio03, audio03)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audioBasicLevel, audioBasicLevel)).as("Invalid comparison result").isEqualTo(0);
// specific to unspecific
assertThat(comp.compare(audioBasic, audio)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audioBasic, all)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audio, all)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(MediaType.APPLICATION_XHTML_XML, allXml)).as("Invalid comparison result").isLessThan(0);
// unspecific to specific
assertThat(comp.compare(audio, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(allXml, MediaType.APPLICATION_XHTML_XML)).as("Invalid comparison result")
.isGreaterThan(0);
assertThat(comp.compare(all, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(all, audio)).as("Invalid comparison result").isGreaterThan(0);
// qualifiers
assertThat(comp.compare(audio, audio07)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audio07, audio)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(audio07, audio03)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audio03, audio07)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(audio03, all)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(all, audio03)).as("Invalid comparison result").isGreaterThan(0);
// other parameters
assertThat(comp.compare(audioBasic, audioBasicLevel)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(audioBasicLevel, audioBasic)).as("Invalid comparison result").isLessThan(0);
// different types
assertThat(comp.compare(audioBasic, textHtml)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(textHtml, audioBasic)).as("Invalid comparison result").isEqualTo(0);
// different subtypes
assertThat(comp.compare(audioBasic, audioWave)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audioWave, audioBasic)).as("Invalid comparison result").isEqualTo(0);
}
@Test
@SuppressWarnings("removal")
public void sortBySpecificityRelated() {
MediaType audioBasic = new MediaType("audio", "basic");
MediaType audio = new MediaType("audio");
MediaType audio03 = new MediaType("audio", "*", 0.3);
MediaType audio07 = new MediaType("audio", "*", 0.7);
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
MediaType all = MediaType.ALL;
List<MediaType> expected = new ArrayList<>();
expected.add(audioBasicLevel);
expected.add(audioBasic);
expected.add(audio);
expected.add(audio07);
expected.add(audio03);
expected.add(all);
List<MediaType> result = new ArrayList<>(expected);
Random rnd = new Random();
// shuffle & sort 10 times
for (int i = 0; i < 10; i++) {
Collections.shuffle(result, rnd);
MediaType.sortBySpecificity(result);
for (int j = 0; j < result.size(); j++) {
assertThat(result.get(j)).as("Invalid media type at " + j).isSameAs(expected.get(j));
}
}
}
@Test
@SuppressWarnings("removal")
public void sortBySpecificityUnrelated() {
MediaType audioBasic = new MediaType("audio", "basic");
MediaType audioWave = new MediaType("audio", "wave");
MediaType textHtml = new MediaType("text", "html");
List<MediaType> expected = new ArrayList<>();
expected.add(textHtml);
expected.add(audioBasic);
expected.add(audioWave);
List<MediaType> result = new ArrayList<>(expected);
MediaType.sortBySpecificity(result);
for (int i = 0; i < result.size(); i++) {
assertThat(result.get(i)).as("Invalid media type at " + i).isSameAs(expected.get(i));
}
}
@Test
void qualityComparator() {
MediaType audioBasic = new MediaType("audio", "basic");
MediaType audioWave = new MediaType("audio", "wave");
MediaType audio = new MediaType("audio");
MediaType audio03 = new MediaType("audio", "*", 0.3);
MediaType audio07 = new MediaType("audio", "*", 0.7);
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
MediaType textHtml = new MediaType("text", "html");
MediaType allXml = new MediaType("application", "*+xml");
MediaType all = MediaType.ALL;
@SuppressWarnings("removal")
Comparator<MediaType> comp = MediaType.QUALITY_VALUE_COMPARATOR;
// equal
assertThat(comp.compare(audioBasic, audioBasic)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audio, audio)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audio07, audio07)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audio03, audio03)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audioBasicLevel, audioBasicLevel)).as("Invalid comparison result").isEqualTo(0);
// specific to unspecific
assertThat(comp.compare(audioBasic, audio)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audioBasic, all)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audio, all)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(MediaType.APPLICATION_XHTML_XML, allXml)).as("Invalid comparison result").isLessThan(0);
// unspecific to specific
assertThat(comp.compare(audio, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(all, audioBasic)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(all, audio)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(allXml, MediaType.APPLICATION_XHTML_XML)).as("Invalid comparison result")
.isGreaterThan(0);
// qualifiers
assertThat(comp.compare(audio, audio07)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audio07, audio)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(audio07, audio03)).as("Invalid comparison result").isLessThan(0);
assertThat(comp.compare(audio03, audio07)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(audio03, all)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(all, audio03)).as("Invalid comparison result").isLessThan(0);
// other parameters
assertThat(comp.compare(audioBasic, audioBasicLevel)).as("Invalid comparison result").isGreaterThan(0);
assertThat(comp.compare(audioBasicLevel, audioBasic)).as("Invalid comparison result").isLessThan(0);
// different types
assertThat(comp.compare(audioBasic, textHtml)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(textHtml, audioBasic)).as("Invalid comparison result").isEqualTo(0);
// different subtypes
assertThat(comp.compare(audioBasic, audioWave)).as("Invalid comparison result").isEqualTo(0);
assertThat(comp.compare(audioWave, audioBasic)).as("Invalid comparison result").isEqualTo(0);
}
@Test
@SuppressWarnings("removal")
public void sortByQualityRelated() {
MediaType audioBasic = new MediaType("audio", "basic");
MediaType audio = new MediaType("audio");
MediaType audio03 = new MediaType("audio", "*", 0.3);
MediaType audio07 = new MediaType("audio", "*", 0.7);
MediaType audioBasicLevel = new MediaType("audio", "basic", Collections.singletonMap("level", "1"));
MediaType all = MediaType.ALL;
List<MediaType> expected = new ArrayList<>();
expected.add(audioBasicLevel);
expected.add(audioBasic);
expected.add(audio);
expected.add(all);
expected.add(audio07);
expected.add(audio03);
List<MediaType> result = new ArrayList<>(expected);
Random rnd = new Random();
// shuffle & sort 10 times
for (int i = 0; i < 10; i++) {
Collections.shuffle(result, rnd);
MediaType.sortByQualityValue(result);
for (int j = 0; j < result.size(); j++) {
assertThat(result.get(j)).as("Invalid media type at " + j).isSameAs(expected.get(j));
}
}
}
@Test
@SuppressWarnings("removal")
public void sortByQualityUnrelated() {
MediaType audioBasic = new MediaType("audio", "basic");
MediaType audioWave = new MediaType("audio", "wave");
MediaType textHtml = new MediaType("text", "html");
List<MediaType> expected = new ArrayList<>();
expected.add(textHtml);
expected.add(audioBasic);
expected.add(audioWave);
List<MediaType> result = new ArrayList<>(expected);
MediaType.sortBySpecificity(result);
for (int i = 0; i < result.size(); i++) {
assertThat(result.get(i)).as("Invalid media type at " + i).isSameAs(expected.get(i));
}
}
@Test
void testWithConversionService() {
ConversionService conversionService = new DefaultConversionService();

Some files were not shown because too many files have changed in this diff Show More