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