diff --git a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java index 62fa75e8e..58c6873a7 100644 --- a/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java +++ b/spring-data-rest-webmvc/src/main/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMapping.java @@ -50,6 +50,7 @@ import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.condition.ProducesRequestCondition; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.util.pattern.PathPatternParser; /** * {@link RequestMappingHandlerMapping} implementation that will only find a handler method if a @@ -63,6 +64,9 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl */ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping { + private static final PathPatternParser PARSER = new PathPatternParser(); + static final String EFFECTIVE_LOOKUP_PATH_KEY = "EFFECTIVE_REPOSITORY_LOOKUP_PATH"; + private final ResourceMappings mappings; private final RepositoryRestConfiguration configuration; private final Optional repositories; @@ -151,7 +155,15 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping { return handlerMethod; } - return mappings.exportsTopLevelResourceFor(getRepositoryBasePath(repositoryLookupPath)) ? handlerMethod : null; + String repositoryBasePath = getRepositoryBasePath(repositoryLookupPath); + + if (!mappings.exportsTopLevelResourceFor(repositoryBasePath)) { + return null; + } + + exposeEffectiveLookupPathKey(handlerMethod, request, repositoryBasePath); + + return handlerMethod; } /* @@ -235,6 +247,26 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping { return secondSlashIndex == -1 ? repositoryLookupPath : repositoryLookupPath.substring(0, secondSlashIndex); } + /** + * Exposes the effective repository resource lookup path as request attribute via {@link #EFFECTIVE_LOOKUP_PATH_KEY}, + * i.e. {@code /people/search/\{search\}} instead of {@code /\{repository\}/search/\{search\}}. + * + * @param method must not be {@literal null}. + * @param request must not be {@literal null}. + * @param repositoryBasePath must not be {@literal null}. + */ + private void exposeEffectiveLookupPathKey(HandlerMethod method, HttpServletRequest request, + String repositoryBasePath) { + + RequestMappingInfo mappingInfo = getMappingForMethod(method.getMethod(), method.getBeanType()); + String pattern = mappingInfo.getPatternsCondition() // + .getMatchingCondition(request)// + .getPatterns() // + .iterator().next(); + + request.setAttribute(EFFECTIVE_LOOKUP_PATH_KEY, PARSER.parse(pattern.replace("/{repository}", repositoryBasePath))); + } + /** * No-op {@link StringValueResolver} that returns the given {@link String} value as is. * diff --git a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java index e6defd7fd..2dfbfc616 100755 --- a/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java +++ b/spring-data-rest-webmvc/src/test/java/org/springframework/data/rest/webmvc/RepositoryRestHandlerMappingUnitTests.java @@ -43,6 +43,7 @@ import org.springframework.mock.web.MockServletContext; import org.springframework.util.ClassUtils; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.method.HandlerMethod; +import org.springframework.web.util.pattern.PathPattern; /** * Unit tests for {@link RepositoryRestHandlerMapping}. @@ -270,6 +271,22 @@ public class RepositoryRestHandlerMappingUnitTests { assertThat(mapping.isHandler(type)).isTrue(); } + @Test // DATAREST-1294 + public void exposesEffectiveRepositoryLookupPathAsRequestAttribute() throws Exception { + + when(mappings.exportsTopLevelResourceFor("/people")).thenReturn(true); + + MockHttpServletRequest mockRequest = new MockHttpServletRequest("GET", "/people/search/findByLastnameLike"); + + handlerMapping.afterPropertiesSet(); + handlerMapping.lookupHandlerMethod("/people/search/findByLastnameLike", mockRequest); + + assertThat(mockRequest.getAttribute(RepositoryRestHandlerMapping.EFFECTIVE_LOOKUP_PATH_KEY)) // + .isInstanceOfSatisfying(PathPattern.class, it -> { + assertThat(it.getPatternString()).isEqualTo("/people/search/{search}"); + }); + } + private static Class createProxy(Object source) { ProxyFactory factory = new ProxyFactory(source);