From 7ac66eff4d8c0b5e6d507f78eb3d65718c9b444a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 24 Jan 2024 11:43:36 +0100 Subject: [PATCH] Consistent nullability for concurrent result (cherry picked from commit b92877990da57c36eee035095c9ae72f5c0a7537) --- .../web/context/request/async/WebAsyncManager.java | 10 ++++++++-- .../annotation/RequestMappingHandlerAdapter.java | 9 ++++++--- .../annotation/ServletInvocableHandlerMethod.java | 8 ++++---- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java index 14b17ebe09..33d2484e38 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/async/WebAsyncManager.java @@ -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. @@ -53,6 +53,7 @@ import org.springframework.web.context.request.async.DeferredResult.DeferredResu * * @author Rossen Stoyanchev * @author Juergen Hoeller + * @author Sam Brannen * @since 3.2 * @see org.springframework.web.context.request.AsyncWebRequestInterceptor * @see org.springframework.web.servlet.AsyncHandlerInterceptor @@ -77,12 +78,15 @@ public final class WebAsyncManager { private static Boolean taskExecutorWarning = true; + @Nullable private AsyncWebRequest asyncWebRequest; private AsyncTaskExecutor taskExecutor = DEFAULT_TASK_EXECUTOR; + @Nullable private volatile Object concurrentResult = RESULT_NONE; + @Nullable private volatile Object[] concurrentResultContext; /* @@ -156,6 +160,7 @@ public final class WebAsyncManager { * concurrent handling raised one. * @see #clearConcurrentResult() */ + @Nullable public Object getConcurrentResult() { return this.concurrentResult; } @@ -165,6 +170,7 @@ public final class WebAsyncManager { * concurrent handling. * @see #clearConcurrentResult() */ + @Nullable public Object[] getConcurrentResultContext() { return this.concurrentResultContext; } @@ -378,7 +384,7 @@ public final class WebAsyncManager { return request != null ? request.getRequestURI() : "servlet container"; } - private void setConcurrentResultAndDispatch(Object result) { + private void setConcurrentResultAndDispatch(@Nullable Object result) { synchronized (WebAsyncManager.this) { if (this.concurrentResult != RESULT_NONE) { return; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java index 6005b22e24..c68bd3ef29 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 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. @@ -50,6 +50,7 @@ import org.springframework.http.converter.support.AllEncompassingFormHttpMessage import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.lang.Nullable; import org.springframework.ui.ModelMap; +import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils.MethodFilter; import org.springframework.web.accept.ContentNegotiationManager; @@ -465,7 +466,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter } /** - * By default the content of the "default" model is used both during + * By default, the content of the "default" model is used both during * rendering and redirect scenarios. Alternatively a controller method * can declare a {@link RedirectAttributes} argument and use it to provide * attributes for a redirect. @@ -883,7 +884,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); - mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; + Object[] resultContext = asyncManager.getConcurrentResultContext(); + Assert.state(resultContext != null && resultContext.length > 0, "Missing result context"); + mavContainer = (ModelAndViewContainer) resultContext[0]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(result, !traceOn); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java index ae3473873d..23f19a3292 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 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. @@ -199,7 +199,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { * actually invoking the controller method. This is useful when processing * async return values (e.g. Callable, DeferredResult, ListenableFuture). */ - ServletInvocableHandlerMethod wrapConcurrentResult(Object result) { + ServletInvocableHandlerMethod wrapConcurrentResult(@Nullable Object result) { return new ConcurrentResultHandlerMethod(result, new ConcurrentResultMethodParameter(result)); } @@ -214,7 +214,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { private final MethodParameter returnType; - public ConcurrentResultHandlerMethod(final Object result, ConcurrentResultMethodParameter returnType) { + public ConcurrentResultHandlerMethod(@Nullable Object result, ConcurrentResultMethodParameter returnType) { super((Callable) () -> { if (result instanceof Exception) { throw (Exception) result; @@ -278,7 +278,7 @@ public class ServletInvocableHandlerMethod extends InvocableHandlerMethod { private final ResolvableType returnType; - public ConcurrentResultMethodParameter(Object returnValue) { + public ConcurrentResultMethodParameter(@Nullable Object returnValue) { super(-1); this.returnValue = returnValue; this.returnType = (returnValue instanceof ReactiveTypeHandler.CollectedValuesList ?