From abacc6d29ed2b7cd5ccd8498d3e4db05aa6d7dc4 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 20 Nov 2018 22:31:02 -0500 Subject: [PATCH] BEST_MATCHING_HANDLER_ATTRIBUTE for spring-webmvc Issue: SPR-17518 --- .../springframework/web/servlet/HandlerMapping.java | 9 ++++++++- .../servlet/handler/AbstractHandlerMethodMapping.java | 1 + .../servlet/handler/AbstractUrlHandlerMapping.java | 1 + .../servlet/handler/HandlerMethodMappingTests.java | 9 +++++++-- .../servlet/handler/SimpleUrlHandlerMappingTests.java | 11 +++++++---- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java index 117bff3588..da03f81f91 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/HandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2018 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,13 @@ import javax.servlet.http.HttpServletRequest; */ public interface HandlerMapping { + /** + * Name of the {@link HttpServletRequest} attribute that contains the mapped + * handler for the best matching pattern. + * @since 4.3.21 + */ + String BEST_MATCHING_HANDLER_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingHandler"; + /** * Name of the {@link HttpServletRequest} attribute that contains the path * within the handler mapping, in case of a pattern match, or the full diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java index f471b36aca..3893b2a046 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java @@ -367,6 +367,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap request.getRequestURL() + "': {" + m1 + ", " + m2 + "}"); } } + request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod); handleMatch(bestMatch.mapping, lookupPath, request); return bestMatch.handlerMethod; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java index 16a120cb4f..48571d6b3e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java @@ -407,6 +407,7 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping i @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request); + request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, handler); request.setAttribute(INTROSPECT_TYPE_LEVEL_MAPPING, supportsTypeLevelMappings()); return true; } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java index 5a181069fe..6676f2def3 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java @@ -38,6 +38,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.context.support.StaticWebApplicationContext; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.util.UrlPathHelper; @@ -79,8 +80,10 @@ public class HandlerMethodMappingTests { String key = "foo"; this.mapping.registerMapping(key, this.handler, this.method1); - HandlerMethod result = this.mapping.getHandlerInternal(new MockHttpServletRequest("GET", key)); + MockHttpServletRequest request = new MockHttpServletRequest("GET", key); + HandlerMethod result = this.mapping.getHandlerInternal(request); assertEquals(method1, result.getMethod()); + assertEquals(result, request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE)); } @Test @@ -88,8 +91,10 @@ public class HandlerMethodMappingTests { this.mapping.registerMapping("/fo*", this.handler, this.method1); this.mapping.registerMapping("/f*", this.handler, this.method2); - HandlerMethod result = this.mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo")); + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); + HandlerMethod result = this.mapping.getHandlerInternal(request); assertEquals(method1, result.getMethod()); + assertEquals(result, request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE)); } @Test(expected = IllegalStateException.class) diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java index dd6b09bd2c..2550405d99 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/SimpleUrlHandlerMappingTests.java @@ -41,17 +41,18 @@ import static org.junit.Assert.*; public class SimpleUrlHandlerMappingTests { @Test - public void handlerBeanNotFound() throws Exception { + @SuppressWarnings("resource") + public void handlerBeanNotFound() { MockServletContext sc = new MockServletContext(""); XmlWebApplicationContext root = new XmlWebApplicationContext(); root.setServletContext(sc); - root.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map1.xml"}); + root.setConfigLocations("/org/springframework/web/servlet/handler/map1.xml"); root.refresh(); XmlWebApplicationContext wac = new XmlWebApplicationContext(); wac.setParent(root); wac.setServletContext(sc); wac.setNamespace("map2err"); - wac.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map2err.xml"}); + wac.setConfigLocations("/org/springframework/web/servlet/handler/map2err.xml"); try { wac.refresh(); fail("Should have thrown NoSuchBeanDefinitionException"); @@ -93,7 +94,7 @@ public class SimpleUrlHandlerMappingTests { MockServletContext sc = new MockServletContext(""); XmlWebApplicationContext wac = new XmlWebApplicationContext(); wac.setServletContext(sc); - wac.setConfigLocations(new String[] {"/org/springframework/web/servlet/handler/map2.xml"}); + wac.setConfigLocations("/org/springframework/web/servlet/handler/map2.xml"); wac.refresh(); Object bean = wac.getBean("mainController"); Object otherBean = wac.getBean("otherController"); @@ -104,11 +105,13 @@ public class SimpleUrlHandlerMappingTests { HandlerExecutionChain hec = getHandler(hm, req); assertTrue("Handler is correct bean", hec != null && hec.getHandler() == bean); assertEquals("/welcome.html", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + assertEquals(bean, req.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE)); req = new MockHttpServletRequest("GET", "/welcome.x"); hec = getHandler(hm, req); assertTrue("Handler is correct bean", hec != null && hec.getHandler() == otherBean); assertEquals("welcome.x", req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE)); + assertEquals(otherBean, req.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE)); req = new MockHttpServletRequest("GET", "/welcome/"); hec = getHandler(hm, req);