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 821361f042e2..3747d856fd5b 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 @@ -166,6 +166,7 @@ public boolean hasConcurrentResult() { * concurrent handling raised one. * @see #clearConcurrentResult() */ + @Nullable public Object getConcurrentResult() { return this.concurrentResult; } 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 36c8013c4ca8..4ffe49165007 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-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. @@ -50,6 +50,7 @@ import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; import org.springframework.lang.Nullable; import org.springframework.ui.ModelMap; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils.MethodFilter; @@ -905,7 +906,9 @@ protected ModelAndView invokeHandlerMethod(HttpServletRequest request, 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 d1d166880f6c..5e9b1f74b166 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-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. @@ -200,7 +200,7 @@ private String formatErrorForReturnValue(@Nullable Object returnValue) { * 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)); } @@ -215,7 +215,7 @@ private class ConcurrentResultHandlerMethod extends ServletInvocableHandlerMetho private final MethodParameter returnType; - public ConcurrentResultHandlerMethod(final Object result, ConcurrentResultMethodParameter returnType) { + public ConcurrentResultHandlerMethod(@Nullable Object result, ConcurrentResultMethodParameter returnType) { super((Callable) () -> { if (result instanceof Exception exception) { throw exception; @@ -279,7 +279,7 @@ private class ConcurrentResultMethodParameter extends AnnotatedMethodParameter { private final ResolvableType returnType; - public ConcurrentResultMethodParameter(Object returnValue) { + public ConcurrentResultMethodParameter(@Nullable Object returnValue) { super(-1); this.returnValue = returnValue; this.returnType = (returnValue instanceof CollectedValuesList cvList ?