DATAREST-1294 - Expose effective repository lookup path as request attribute.

We now expose a partially resolved PathPattern to contain the explicit repository base path so that the subpaths can be grouped around the individual repositories exposed.

Related ticket: spring-projects/spring-boot#14872
This commit is contained in:
Oliver Gierke
2018-10-18 12:00:50 +02:00
parent 74be650a0c
commit ffb38a067e
2 changed files with 50 additions and 1 deletions

View File

@@ -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> 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.
*

View File

@@ -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);