aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-webserver-webapi-v2
diff options
context:
space:
mode:
authorAlain Kermis <alain.kermis@sonarsource.com>2023-12-06 16:46:21 +0100
committersonartech <sonartech@sonarsource.com>2023-12-19 20:02:55 +0000
commita7a5ec9cecb3e5146094b50af61f02ab067b455c (patch)
treeecd9e598a2b47b3030ae7470c5fb1301504c0739 /server/sonar-webserver-webapi-v2
parent6a2f77f0e34e09ddd7202e92e685948229570f3f (diff)
downloadsonarqube-a7a5ec9cecb3e5146094b50af61f02ab067b455c.tar.gz
sonarqube-a7a5ec9cecb3e5146094b50af61f02ab067b455c.zip
SONAR-21228 Log deprecated API usage for API V2
Diffstat (limited to 'server/sonar-webserver-webapi-v2')
-rw-r--r--server/sonar-webserver-webapi-v2/build.gradle4
-rw-r--r--server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/DeprecatedHandler.java137
-rw-r--r--server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java8
-rw-r--r--server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/DeprecatedHandlerTest.java206
-rw-r--r--server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/config/CommonWebConfigTest.java1
-rw-r--r--server/sonar-webserver-webapi-v2/src/testFixtures/java/org/sonar/server/v2/api/ControllerTester.java14
6 files changed, 369 insertions, 1 deletions
diff --git a/server/sonar-webserver-webapi-v2/build.gradle b/server/sonar-webserver-webapi-v2/build.gradle
index 93b98d477a2..14af058a25a 100644
--- a/server/sonar-webserver-webapi-v2/build.gradle
+++ b/server/sonar-webserver-webapi-v2/build.gradle
@@ -18,11 +18,15 @@ dependencies {
testImplementation 'javax.servlet:javax.servlet-api'
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.skyscreamer:jsonassert:1.5.1'
+ testImplementation 'org.sonarsource.api.plugin:sonar-plugin-api-test-fixtures'
+ testImplementation 'com.tngtech.java:junit-dataprovider'
testImplementation project(':sonar-testing-harness')
testImplementation testFixtures(project(':server:sonar-server-common'))
testImplementation testFixtures(project(':server:sonar-webserver-auth'))
testFixturesApi 'org.springframework:spring-test'
+
+ testRuntimeOnly 'org.apache.logging.log4j:log4j-core'
}
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/DeprecatedHandler.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/DeprecatedHandler.java
new file mode 100644
index 00000000000..94701a2a101
--- /dev/null
+++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/common/DeprecatedHandler.java
@@ -0,0 +1,137 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.v2.common;
+
+import java.lang.reflect.Field;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.event.Level;
+import org.sonar.server.user.ThreadLocalUserSession;
+import org.sonar.server.user.UserSession;
+import org.springdoc.api.annotations.ParameterObject;
+import org.springframework.core.MethodParameter;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import static org.sonar.process.logging.LogbackHelper.DEPRECATION_LOGGER_NAME;
+
+/**
+ * Interceptor that logs deprecation warnings for deprecated web services and parameters that are used. The only thing this handler will not
+ * log is used deprecated fields of {@link org.springframework.web.bind.annotation.RequestBody()}. This needs to be covered at some point.
+ * </p>
+ */
+@Component
+public class DeprecatedHandler implements HandlerInterceptor {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DEPRECATION_LOGGER_NAME);
+
+ private final UserSession userSession;
+
+ public DeprecatedHandler(UserSession userSession) {
+ this.userSession = userSession;
+ }
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
+ if (handler instanceof HandlerMethod handlerMethod) {
+ preHandle(handlerMethod, request);
+ } else {
+ LOGGER.debug("Handler is not a HandlerMethod, skipping deprecated check.");
+ }
+
+ return true;
+ }
+
+ private void preHandle(HandlerMethod handlerMethod, HttpServletRequest request) {
+ Level logLevel = getLogLevel();
+ Deprecated deprecatedEndpoint = handlerMethod.getMethodAnnotation(Deprecated.class);
+ if (deprecatedEndpoint != null) {
+ logDeprecatedWebServiceMessage(logLevel, deprecatedEndpoint.since());
+ }
+
+ handleParams(handlerMethod, logLevel, request);
+ }
+
+ private static void handleParams(HandlerMethod handlerMethod, Level logLevel, HttpServletRequest request) {
+ for (MethodParameter param : handlerMethod.getMethodParameters()) {
+ if (isV2ParameterObject(param)) {
+ checkDeprecatedFields(param.getParameterType(), logLevel, request);
+ } else if (isUsedDeprecatedRequestParam(request, param)) {
+ String paramName = param.getParameterAnnotation(RequestParam.class).name();
+ String deprecatedSince = param.getParameterAnnotation(Deprecated.class).since();
+ logDeprecatedParamMessage(logLevel, paramName, deprecatedSince);
+ }
+ }
+ }
+
+ private static void checkDeprecatedFields(Class<?> clazz, Level logLevel, HttpServletRequest request) {
+ for (Field field : clazz.getDeclaredFields()) {
+ if (isUsedDeprecatedField(request, field)) {
+ String deprecatedSince = field.getAnnotation(Deprecated.class).since();
+ logDeprecatedParamMessage(logLevel, field.getName(), deprecatedSince);
+ }
+
+ if (isApiV2Param(field.getType())) {
+ checkDeprecatedFields(field.getType(), logLevel, request);
+ }
+ }
+ }
+
+ private Level getLogLevel() {
+ return isAuthenticatedBrowserSessionOrUnauthenticatedUser() ? Level.DEBUG : Level.WARN;
+ }
+
+ private boolean isAuthenticatedBrowserSessionOrUnauthenticatedUser() {
+ return userSession instanceof ThreadLocalUserSession threadLocalUserSession
+ && (threadLocalUserSession.hasSession()
+ && (!userSession.isLoggedIn() || userSession.isAuthenticatedBrowserSession()));
+ }
+
+ private static void logDeprecatedWebServiceMessage(Level logLevel, String deprecatedSince) {
+ LOGGER.atLevel(logLevel).log("Web service is deprecated since {} and will be removed in a future version.", deprecatedSince);
+ }
+
+ private static void logDeprecatedParamMessage(Level logLevel, String field, String deprecatedSince) {
+ LOGGER.atLevel(logLevel).log("Parameter '{}' is deprecated since {} and will be removed in a future version.", field, deprecatedSince);
+ }
+
+ private static boolean isUsedDeprecatedRequestParam(HttpServletRequest request, MethodParameter param) {
+ return param.hasParameterAnnotation(Deprecated.class) &&
+ param.hasParameterAnnotation(RequestParam.class) &&
+ request.getParameter(param.getParameterAnnotation(RequestParam.class).name()) != null;
+ }
+
+ private static boolean isUsedDeprecatedField(HttpServletRequest request, Field field) {
+ return field.getAnnotation(Deprecated.class) != null && request.getParameter(field.getName()) != null;
+ }
+
+ private static boolean isV2ParameterObject(MethodParameter param) {
+ return param.hasParameterAnnotation(ParameterObject.class) && isApiV2Param(param.getParameterType());
+ }
+
+ private static boolean isApiV2Param(Class<?> clazz) {
+ return clazz.getTypeName().startsWith("org.sonar.server.v2");
+ }
+
+}
diff --git a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java
index 0cb87b69044..3df7ae8ebe1 100644
--- a/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java
+++ b/server/sonar-webserver-webapi-v2/src/main/java/org/sonar/server/v2/config/PlatformLevel4WebConfig.java
@@ -52,9 +52,11 @@ import org.sonar.server.v2.api.system.controller.LivenessController;
import org.sonar.server.v2.api.user.controller.DefaultUserController;
import org.sonar.server.v2.api.user.controller.UserController;
import org.sonar.server.v2.api.user.converter.UsersSearchRestResponseGenerator;
+import org.sonar.server.v2.common.DeprecatedHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@Configuration
@Import(CommonWebConfig.class)
@@ -112,5 +114,11 @@ public class PlatformLevel4WebConfig {
return new DefaultRuleController(userSession, ruleService, ruleRestResponseGenerator);
}
+ @Bean
+ public RequestMappingHandlerMapping requestMappingHandlerMapping(UserSession userSession) {
+ RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
+ handlerMapping.setInterceptors(new DeprecatedHandler(userSession));
+ return handlerMapping;
+ }
}
diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/DeprecatedHandlerTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/DeprecatedHandlerTest.java
new file mode 100644
index 00000000000..f8b24ed8b0e
--- /dev/null
+++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/common/DeprecatedHandlerTest.java
@@ -0,0 +1,206 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.v2.common;
+
+import com.tngtech.java.junit.dataprovider.DataProvider;
+import com.tngtech.java.junit.dataprovider.DataProviderRunner;
+import com.tngtech.java.junit.dataprovider.UseDataProvider;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.event.Level;
+import org.sonar.api.testfixtures.log.LogTester;
+import org.sonar.server.user.ThreadLocalUserSession;
+import org.sonar.server.v2.api.ControllerTester;
+import org.springdoc.api.annotations.ParameterObject;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseStatus;
+import org.springframework.web.bind.annotation.RestController;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.springframework.http.HttpMethod.GET;
+import static org.springframework.http.HttpMethod.POST;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.request;
+
+@RunWith(DataProviderRunner.class)
+public class DeprecatedHandlerTest {
+
+ private static final String DEPRECATED_VERSION = "10.0";
+ private static final String DEPRECATED_WEB_SERVICE = "Web service is deprecated since %s and will be removed in a future version.";
+ private static final String DEPRECATED_PARAM = "Parameter '%s' is deprecated since %s and will be removed in a future version.";
+
+ private final ThreadLocalUserSession userSession = mock(ThreadLocalUserSession.class);
+ private final MockMvc mockMvc = ControllerTester.getMockMvcWithHandlerInterceptors(List.of(new DeprecatedHandler(userSession)), new TestController());
+
+ @Rule
+ public LogTester logTester = new LogTester().setLevel(Level.DEBUG);
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsDeprecatedGetMethod_shouldShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(GET, sessionData, "/test/get-deprecated-endpoint");
+
+ assertThat(logTester.logs(expectedLogLevel)).contains(DEPRECATED_WEB_SERVICE.formatted(DEPRECATED_VERSION));
+ }
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsNotDeprecatedGetMethod_shouldNotShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(GET, sessionData, "/test/get-not-deprecated-endpoint");
+
+ assertThat(logTester.logs(expectedLogLevel)).doesNotContain(DEPRECATED_WEB_SERVICE.formatted(DEPRECATED_VERSION));
+ }
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsGetMethodWithUsedDeprecatedParamObjectField_shouldShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(GET, sessionData, "/test/get-deprecated-param-obj?deprecatedField=foo&notDeprecatedField=bar");
+
+ assertThat(logTester.logs(expectedLogLevel)).contains(DEPRECATED_PARAM.formatted("deprecatedField", DEPRECATED_VERSION));
+ }
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsGetMethodWithUnusedDeprecatedParam_shouldNotShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(GET, sessionData, "/test/get-deprecated-param-obj?notDeprecatedParam=bar");
+
+ assertThat(logTester.logs(expectedLogLevel)).doesNotContain(DEPRECATED_PARAM.formatted("notDeprecatedParam", DEPRECATED_VERSION));
+ }
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsGetMethodWithUsedDeprecatedSimpleParam_shouldShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(GET, sessionData, "/test/get-deprecated-param?deprecatedParam=foo");
+
+ assertThat(logTester.logs(expectedLogLevel)).contains(DEPRECATED_PARAM.formatted("deprecatedParam", DEPRECATED_VERSION));
+ }
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsGetMethodWithUnusedDeprecatedSimpleParam_shouldNotShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(GET, sessionData, "/test/get-deprecated-param?notDeprecatedField=bar");
+
+ assertThat(logTester.logs(expectedLogLevel)).doesNotContain(DEPRECATED_PARAM.formatted("notDeprecatedField", DEPRECATED_VERSION));
+ }
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsDeprecatedPostMethod_shouldShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(POST, sessionData, "/test/post-deprecated-endpoint");
+
+ assertThat(logTester.logs(expectedLogLevel)).contains(DEPRECATED_WEB_SERVICE.formatted(DEPRECATED_VERSION));
+ }
+
+ @Test
+ @UseDataProvider("userSessions")
+ public void preHandle_whenHandlerContainsNotDeprecatedPostMethod_shouldNotShowDeprecatedLogs(UserSessionData sessionData, Level expectedLogLevel) throws Exception {
+ performRequest(POST, sessionData, "/test/post-not-deprecated-endpoint");
+
+ assertThat(logTester.logs(expectedLogLevel)).doesNotContain(DEPRECATED_WEB_SERVICE.formatted(DEPRECATED_VERSION));
+ }
+
+ @Test
+ public void preHandle_whenNotHandlerMethod_shouldLogDebugMessage() {
+ DeprecatedHandler handler = new DeprecatedHandler(userSession);
+
+ boolean result = handler.preHandle(mock(HttpServletRequest.class), mock(HttpServletResponse.class), "Not handler");
+
+ assertThat(result).isTrue();
+ assertThat(logTester.logs(Level.DEBUG)).contains("Handler is not a HandlerMethod, skipping deprecated check.");
+ }
+
+ private void performRequest(HttpMethod method, UserSessionData sessionData, String endpoint) throws Exception {
+ when(userSession.hasSession()).thenReturn(true);
+ when(userSession.isLoggedIn()).thenReturn(sessionData.isLoggedIn());
+ when(userSession.isAuthenticatedBrowserSession()).thenReturn(sessionData.isAuthenticatedBrowserSession());
+
+ mockMvc.perform(request(method, endpoint));
+ }
+
+ @DataProvider
+ public static Object[][] userSessions() {
+ return new Object[][] {
+ {new UserSessionData(false, false), Level.DEBUG },
+ {new UserSessionData(false, true), Level.DEBUG},
+ {new UserSessionData(true, false), Level.WARN},
+ {new UserSessionData(true, true), Level.DEBUG}
+ };
+ }
+
+ @RequestMapping("test")
+ @RestController
+ private static class TestController {
+ @Deprecated(since = DEPRECATED_VERSION)
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ @GetMapping("/get-deprecated-endpoint")
+ void deprecatedGet() {
+ }
+
+ @GetMapping("/get-not-deprecated-endpoint")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ void notDeprecatedGet() {
+ }
+
+ @GetMapping("/get-deprecated-param")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ void deprecatedGetParam(@Deprecated(since = DEPRECATED_VERSION) @RequestParam(name = "deprecatedParam") String deprecatedParam,
+ @RequestParam(name = "notDeprecatedParam") String notDeprecatedParam) {
+ }
+
+ @GetMapping("/get-deprecated-param-obj")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ void deprecatedGetParam(@ParameterObject GetRequest request) {
+ }
+
+ @Deprecated(since = DEPRECATED_VERSION)
+ @PostMapping("/post-deprecated-endpoint")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ void deprecatedPost(@RequestBody Object request) {
+ }
+
+ @PostMapping("/post-not-deprecated-endpoint")
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ void notDeprecatedPost(@RequestBody Object request) {
+ }
+ }
+
+ private static class GetRequest {
+ @Deprecated(since = DEPRECATED_VERSION)
+ private String deprecatedField;
+ private String notDeprecatedField;
+ }
+
+ private record UserSessionData(boolean isLoggedIn, boolean isAuthenticatedBrowserSession) {
+ }
+
+}
+
diff --git a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/config/CommonWebConfigTest.java b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/config/CommonWebConfigTest.java
index b295b12d3b2..2f5bd83f1ce 100644
--- a/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/config/CommonWebConfigTest.java
+++ b/server/sonar-webserver-webapi-v2/src/test/java/org/sonar/server/v2/config/CommonWebConfigTest.java
@@ -27,7 +27,6 @@ import org.springframework.web.util.UrlPathHelper;
import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
@RunWith(MockitoJUnitRunner.class)
public class CommonWebConfigTest {
diff --git a/server/sonar-webserver-webapi-v2/src/testFixtures/java/org/sonar/server/v2/api/ControllerTester.java b/server/sonar-webserver-webapi-v2/src/testFixtures/java/org/sonar/server/v2/api/ControllerTester.java
index 3b209c36ffe..ff21dc74460 100644
--- a/server/sonar-webserver-webapi-v2/src/testFixtures/java/org/sonar/server/v2/api/ControllerTester.java
+++ b/server/sonar-webserver-webapi-v2/src/testFixtures/java/org/sonar/server/v2/api/ControllerTester.java
@@ -19,15 +19,29 @@
*/
package org.sonar.server.v2.api;
+import java.util.List;
import org.sonar.server.v2.common.RestResponseEntityExceptionHandler;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
public class ControllerTester {
public static MockMvc getMockMvc(Object... controllers) {
+ return getMockMvcWithHandlerInterceptors(null, controllers);
+ }
+
+ public static MockMvc getMockMvcWithHandlerInterceptors(List<HandlerInterceptor> handlerInterceptors, Object... controllers) {
return MockMvcBuilders
.standaloneSetup(controllers)
+ .setCustomHandlerMapping(() -> resolveRequestMappingHandlerMapping(handlerInterceptors))
.setControllerAdvice(new RestResponseEntityExceptionHandler())
.build();
}
+
+ private static RequestMappingHandlerMapping resolveRequestMappingHandlerMapping(List<HandlerInterceptor> handlerInterceptors) {
+ RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
+ handlerMapping.setInterceptors(handlerInterceptors != null ? handlerInterceptors.toArray() : new Object[0]);
+ return handlerMapping;
+ }
}