DATAREST-1540 - Improvements in HandlerMapping implementation for Spring 5.3.

We now use Spring's path prefix capabilities to apply Spring Data REST's base path to its mappings. This was previously implemented by tweaking the matching conditions.

We now also pick up Spring 5.3's PathPatternParser and apply that to the custom HandlerMapping implementations we register.

Moved DelegatingHandlerMapping into the configuration package to be able to keep it around in package scope.

Deprecated RepositoryRestConfiguration.getBaseUri() as we have only supported paths for quite a while now. Moved all client code to ….getBasePath() instead.
This commit is contained in:
Oliver Drotbohm
2020-07-01 18:26:28 +02:00
parent 8992e21175
commit d7f36b1180
11 changed files with 110 additions and 499 deletions

View File

@@ -51,7 +51,7 @@ import org.springframework.web.servlet.config.annotation.CorsRegistration;
@SuppressWarnings("deprecation")
public class RepositoryRestConfiguration {
private static final URI NO_URI = URI.create("");
static final URI NO_URI = URI.create("");
private URI baseUri = NO_URI;
private URI basePath = NO_URI;
@@ -109,7 +109,9 @@ public class RepositoryRestConfiguration {
* The base URI against which the exporter should calculate its links.
*
* @return The base URI.
* @deprecated use {@link #getBasePath()} instead.
*/
@Deprecated
public URI getBaseUri() {
return basePath != NO_URI ? basePath : baseUri;
}

View File

@@ -21,11 +21,11 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.tests.AbstractControllerIntegrationTests;
import org.springframework.data.rest.tests.mongodb.MongoDbRepositoryConfig;
import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
/**
* Integration tests for {@link BasePathAwareHandlerMapping}.
@@ -36,7 +36,7 @@ import org.springframework.web.servlet.HandlerExecutionChain;
@ContextConfiguration(classes = MongoDbRepositoryConfig.class)
public class RepositoryRestHandlerMappingIntegrationTests extends AbstractControllerIntegrationTests {
@Autowired DelegatingHandlerMapping mapping;
@Autowired HandlerMapping mapping;
@Test // DATAREST-617
public void usesMethodsWithoutProducesClauseForGeneralJsonRequests() throws Exception {

View File

@@ -15,35 +15,17 @@
*/
package org.springframework.data.rest.webmvc;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URI;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.Part;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.util.ProxyUtils;
@@ -52,11 +34,9 @@ import org.springframework.http.MediaType;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
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.UrlPathHelper;
/**
* A {@link RequestMappingHandlerMapping} that augments the request mappings
@@ -65,12 +45,8 @@ import org.springframework.web.util.UrlPathHelper;
*/
public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
private static final UrlPathHelper URL_PATH_HELPER = new UrlPathHelper();
private final RepositoryRestConfiguration configuration;
private String prefix;
/**
* Creates a new {@link BasePathAwareHandlerMapping} using the given {@link RepositoryRestConfiguration}.
*
@@ -79,7 +55,18 @@ public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
public BasePathAwareHandlerMapping(RepositoryRestConfiguration configuration) {
Assert.notNull(configuration, "RepositoryRestConfiguration must not be null!");
this.configuration = configuration;
String baseUri = configuration.getBasePath().toString();
if (StringUtils.hasText(baseUri)) {
Map<String, Predicate<Class<?>>> prefixes = new HashMap<>();
prefixes.put(baseUri, it -> true);
this.setPathPrefixes(prefixes);
}
}
/*
@@ -134,34 +121,12 @@ public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
return null;
}
PatternsRequestCondition patternsCondition = customize(info.getPatternsCondition(), prefix);
ProducesRequestCondition producesCondition = customize(info.getProducesCondition());
return new RequestMappingInfo(patternsCondition, info.getMethodsCondition(), info.getParamsCondition(),
return new RequestMappingInfo(info.getPatternsCondition(), info.getMethodsCondition(), info.getParamsCondition(),
info.getHeadersCondition(), info.getConsumesCondition(), producesCondition, info.getCustomCondition());
}
/**
* Customize the given {@link PatternsRequestCondition} and prefix.
*
* @param condition will never be {@literal null}.
* @param prefix will never be {@literal null}.
* @return
*/
protected PatternsRequestCondition customize(PatternsRequestCondition condition, String prefix) {
Set<String> patterns = condition.getPatterns();
String[] augmentedPatterns = new String[patterns.size()];
int count = 0;
for (String pattern : patterns) {
augmentedPatterns[count++] = prefix.concat(pattern);
}
return new PatternsRequestCondition(augmentedPatterns, getUrlPathHelper(), getPathMatcher(),
useSuffixPatternMatch(), useTrailingSlashMatch(), getFileExtensions());
}
/**
* Customize the given {@link ProducesRequestCondition}. Default implementation returns the condition as is.
*
@@ -184,391 +149,6 @@ public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
return type.isAnnotationPresent(BasePathAwareController.class);
}
/*
* (non-Javadoc)
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
URI baseUri = configuration.getBaseUri();
if (baseUri.isAbsolute()) {
HttpServletRequest request = new UriAwareHttpServletRequest(getServletContext(), baseUri);
this.prefix = URL_PATH_HELPER.getPathWithinApplication(request);
} else {
this.prefix = baseUri.toString();
}
super.afterPropertiesSet();
}
private static class UriAwareHttpServletRequest implements HttpServletRequest {
private final ServletContext context;
private final String path;
/**
* @param context
* @param uri
*/
public UriAwareHttpServletRequest(ServletContext context, URI uri) {
this.context = context;
this.path = uri.getPath();
}
/*
* (non-Javadoc)
* @see javax.servlet.ServletRequest#getAttribute(java.lang.String)
*/
@Override
public Object getAttribute(String name) {
return null;
}
@Override
public Enumeration<String> getAttributeNames() {
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
* @see javax.servlet.ServletRequest#getCharacterEncoding()
*/
@Override
public String getCharacterEncoding() {
return null;
}
@Override
public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
throw new UnsupportedOperationException();
}
@Override
public int getContentLength() {
throw new UnsupportedOperationException();
}
@Override
public String getContentType() {
throw new UnsupportedOperationException();
}
@Override
public ServletInputStream getInputStream() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getParameter(String name) {
throw new UnsupportedOperationException();
}
@Override
public Enumeration<String> getParameterNames() {
throw new UnsupportedOperationException();
}
@Override
public String[] getParameterValues(String name) {
throw new UnsupportedOperationException();
}
@Override
public Map<String, String[]> getParameterMap() {
throw new UnsupportedOperationException();
}
@Override
public String getProtocol() {
throw new UnsupportedOperationException();
}
@Override
public String getScheme() {
throw new UnsupportedOperationException();
}
@Override
public String getServerName() {
throw new UnsupportedOperationException();
}
@Override
public int getServerPort() {
throw new UnsupportedOperationException();
}
@Override
public BufferedReader getReader() throws IOException {
throw new UnsupportedOperationException();
}
@Override
public String getRemoteAddr() {
throw new UnsupportedOperationException();
}
@Override
public String getRemoteHost() {
throw new UnsupportedOperationException();
}
@Override
public void setAttribute(String name, Object o) {
throw new UnsupportedOperationException();
}
@Override
public void removeAttribute(String name) {
throw new UnsupportedOperationException();
}
@Override
public Locale getLocale() {
throw new UnsupportedOperationException();
}
@Override
public Enumeration<Locale> getLocales() {
throw new UnsupportedOperationException();
}
@Override
public boolean isSecure() {
throw new UnsupportedOperationException();
}
@Override
public RequestDispatcher getRequestDispatcher(String path) {
throw new UnsupportedOperationException();
}
@Override
public String getRealPath(String path) {
throw new UnsupportedOperationException();
}
@Override
public int getRemotePort() {
throw new UnsupportedOperationException();
}
@Override
public String getLocalName() {
throw new UnsupportedOperationException();
}
@Override
public String getLocalAddr() {
throw new UnsupportedOperationException();
}
@Override
public int getLocalPort() {
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
* @see javax.servlet.ServletRequest#getServletContext()
*/
@Override
public ServletContext getServletContext() {
return context;
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
throw new UnsupportedOperationException();
}
@Override
public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
throws IllegalStateException {
throw new UnsupportedOperationException();
}
@Override
public boolean isAsyncStarted() {
throw new UnsupportedOperationException();
}
@Override
public boolean isAsyncSupported() {
throw new UnsupportedOperationException();
}
@Override
public AsyncContext getAsyncContext() {
throw new UnsupportedOperationException();
}
@Override
public DispatcherType getDispatcherType() {
throw new UnsupportedOperationException();
}
@Override
public String getAuthType() {
throw new UnsupportedOperationException();
}
@Override
public Cookie[] getCookies() {
throw new UnsupportedOperationException();
}
@Override
public long getDateHeader(String name) {
throw new UnsupportedOperationException();
}
@Override
public String getHeader(String name) {
throw new UnsupportedOperationException();
}
@Override
public Enumeration<String> getHeaders(String name) {
throw new UnsupportedOperationException();
}
@Override
public Enumeration<String> getHeaderNames() {
throw new UnsupportedOperationException();
}
@Override
public int getIntHeader(String name) {
throw new UnsupportedOperationException();
}
@Override
public String getMethod() {
throw new UnsupportedOperationException();
}
@Override
public String getPathInfo() {
throw new UnsupportedOperationException();
}
@Override
public String getPathTranslated() {
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getContextPath()
*/
@Override
public String getContextPath() {
return context.getContextPath();
}
@Override
public String getQueryString() {
throw new UnsupportedOperationException();
}
@Override
public String getRemoteUser() {
throw new UnsupportedOperationException();
}
@Override
public boolean isUserInRole(String role) {
throw new UnsupportedOperationException();
}
@Override
public Principal getUserPrincipal() {
throw new UnsupportedOperationException();
}
@Override
public String getRequestedSessionId() {
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequest#getRequestURI()
*/
@Override
public String getRequestURI() {
return path;
}
@Override
public StringBuffer getRequestURL() {
throw new UnsupportedOperationException();
}
@Override
public String getServletPath() {
throw new UnsupportedOperationException();
}
@Override
public HttpSession getSession(boolean create) {
throw new UnsupportedOperationException();
}
@Override
public HttpSession getSession() {
throw new UnsupportedOperationException();
}
@Override
public boolean isRequestedSessionIdValid() {
throw new UnsupportedOperationException();
}
@Override
public boolean isRequestedSessionIdFromCookie() {
throw new UnsupportedOperationException();
}
@Override
public boolean isRequestedSessionIdFromURL() {
throw new UnsupportedOperationException();
}
@Override
public boolean isRequestedSessionIdFromUrl() {
throw new UnsupportedOperationException();
}
@Override
public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
throw new UnsupportedOperationException();
}
@Override
public void login(String username, String password) throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public void logout() throws ServletException {
throw new UnsupportedOperationException();
}
@Override
public Collection<Part> getParts() throws IOException, ServletException {
throw new UnsupportedOperationException();
}
@Override
public Part getPart(String name) throws IOException, ServletException {
throw new UnsupportedOperationException();
}
}
/**
* {@link HttpServletRequest} that exposes the given media types for the {@code Accept} header.
*
@@ -610,11 +190,9 @@ public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
@Override
public String getHeader(String name) {
if (HttpHeaders.ACCEPT.equalsIgnoreCase(name) && acceptMediaTypes != null) {
return StringUtils.collectionToCommaDelimitedString(acceptMediaTypes);
}
return super.getHeader(name);
return HttpHeaders.ACCEPT.equalsIgnoreCase(name) && acceptMediaTypes != null //
? StringUtils.collectionToCommaDelimitedString(acceptMediaTypes) //
: super.getHeader(name);
}
/*
@@ -624,11 +202,9 @@ public class BasePathAwareHandlerMapping extends RequestMappingHandlerMapping {
@Override
public Enumeration<String> getHeaders(String name) {
if (HttpHeaders.ACCEPT.equalsIgnoreCase(name) && acceptMediaTypes != null) {
return Collections.enumeration(acceptMediaTypeStrings);
}
return super.getHeaders(name);
return HttpHeaders.ACCEPT.equalsIgnoreCase(name) && acceptMediaTypes != null //
? Collections.enumeration(acceptMediaTypeStrings) //
: super.getHeaders(name);
}
}
}

View File

@@ -118,7 +118,7 @@ public class ProfileController {
*/
public static String getRootPath(RepositoryRestConfiguration configuration) {
BaseUri baseUri = new BaseUri(configuration.getBaseUri());
BaseUri baseUri = new BaseUri(configuration.getBasePath());
return baseUri.getUriComponentsBuilder().path(ProfileController.PROFILE_ROOT_MAPPING).build().toString();
}

View File

@@ -19,7 +19,6 @@ import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Optional;
@@ -147,7 +146,7 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
return null;
}
String repositoryLookupPath = new BaseUri(configuration.getBaseUri()).getRepositoryLookupPath(lookupPath);
String repositoryLookupPath = new BaseUri(configuration.getBasePath()).getRepositoryLookupPath(lookupPath);
// Repository root resource
if (!StringUtils.hasText(repositoryLookupPath)) {
@@ -210,7 +209,7 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
return condition;
}
HashSet<String> mediaTypes = new LinkedHashSet<String>();
Set<String> mediaTypes = new LinkedHashSet<String>();
mediaTypes.add(configuration.getDefaultMediaType().toString());
mediaTypes.add(MediaType.APPLICATION_JSON_VALUE);
@@ -224,7 +223,7 @@ public class RepositoryRestHandlerMapping extends BasePathAwareHandlerMapping {
protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
String repositoryLookupPath = new BaseUri(configuration.getBaseUri()).getRepositoryLookupPath(lookupPath);
String repositoryLookupPath = new BaseUri(configuration.getBasePath()).getRepositoryLookupPath(lookupPath);
CorsConfiguration corsConfiguration = super.getCorsConfiguration(handler, request);
return repositories.filter(it -> StringUtils.hasText(repositoryLookupPath))//

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.rest.webmvc.support;
package org.springframework.data.rest.webmvc.config;
import lombok.Getter;
import lombok.NonNull;
@@ -31,6 +31,7 @@ import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.UnsatisfiedServletRequestParameterException;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.handler.MatchableHandlerMapping;
import org.springframework.web.servlet.handler.RequestMatchResult;
import org.springframework.web.util.pattern.PathPatternParser;
@@ -42,7 +43,7 @@ import org.springframework.web.util.pattern.PathPatternParser;
* @author Oliver Gierke
* @soundtrack Benny Greb - Stabila (Moving Parts)
*/
public class DelegatingHandlerMapping implements HandlerMapping, Ordered, MatchableHandlerMapping {
class DelegatingHandlerMapping extends AbstractHandlerMapping implements MatchableHandlerMapping {
private final @Getter List<HandlerMapping> delegates;
@@ -58,6 +59,17 @@ public class DelegatingHandlerMapping implements HandlerMapping, Ordered, Matcha
this.delegates = delegates;
}
@Override
public void setPatternParser(PathPatternParser parser) {
super.setPatternParser(parser);
delegates.stream() //
.filter(AbstractHandlerMapping.class::isInstance) //
.map(AbstractHandlerMapping.class::cast) //
.forEach(it -> it.setPatternParser(parser));
}
/*
* (non-Javadoc)
* @see org.springframework.core.Ordered#getOrder()
@@ -69,10 +81,10 @@ public class DelegatingHandlerMapping implements HandlerMapping, Ordered, Matcha
/*
* (non-Javadoc)
* @see org.springframework.web.servlet.HandlerMapping#getHandler(javax.servlet.http.HttpServletRequest)
* @see org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandlerInternal(javax.servlet.http.HttpServletRequest)
*/
@Override
public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
return HandlerSelectionResult.from(request, delegates).resultOrException();
}
@@ -90,14 +102,6 @@ public class DelegatingHandlerMapping implements HandlerMapping, Ordered, Matcha
}
}
/*
* (non-Javadoc)
* @see org.springframework.web.servlet.handler.MatchableHandlerMapping#getPatternParser()
*/
public PathPatternParser getPatternParser() {
return null;
}
@Value
private static class HandlerSelectionResult {

View File

@@ -80,7 +80,15 @@ import org.springframework.data.rest.webmvc.mapping.Associations;
import org.springframework.data.rest.webmvc.mapping.LinkCollector;
import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
import org.springframework.data.rest.webmvc.spi.BackendIdConverter.DefaultIdConverter;
import org.springframework.data.rest.webmvc.support.*;
import org.springframework.data.rest.webmvc.support.BackendIdHandlerMethodArgumentResolver;
import org.springframework.data.rest.webmvc.support.DefaultExcerptProjector;
import org.springframework.data.rest.webmvc.support.DomainClassResolver;
import org.springframework.data.rest.webmvc.support.ETagArgumentResolver;
import org.springframework.data.rest.webmvc.support.ExcerptProjector;
import org.springframework.data.rest.webmvc.support.HttpMethodHandlerMethodArgumentResolver;
import org.springframework.data.rest.webmvc.support.JpaHelper;
import org.springframework.data.rest.webmvc.support.PagingAndSortingTemplateVariables;
import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks;
import org.springframework.data.util.AnnotatedTypeScanner;
import org.springframework.data.util.Lazy;
import org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver;
@@ -114,7 +122,9 @@ import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.handler.AbstractHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@@ -297,7 +307,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
@Bean
public BaseUri baseUri() {
return new BaseUri(repositoryRestConfiguration().getBaseUri());
return new BaseUri(repositoryRestConfiguration().getBasePath());
}
/**
@@ -530,7 +540,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
* @return
*/
@Bean
public DelegatingHandlerMapping restHandlerMapping() {
public AbstractHandlerMapping restHandlerMapping() {
Map<String, CorsConfiguration> corsConfigurations = repositoryRestConfiguration().getCorsRegistry()
.getCorsConfigurations();
@@ -554,6 +564,15 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
return new DelegatingHandlerMapping(mappings);
}
/*
* (non-Javadoc)
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurer#configurePathMatch(org.springframework.web.servlet.config.annotation.PathMatchConfigurer)
*/
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
restHandlerMapping().setPatternParser(configurer.getPatternParser());
}
@Bean
public RepositoryResourceMappings resourceMappings() {
return new RepositoryResourceMappings(repositories(), persistentEntities(), repositoryRestConfiguration());

View File

@@ -86,7 +86,7 @@ public class RepositoryEntityLinks extends AbstractEntityLinks {
public LinkBuilder linkFor(Class<?> type) {
ResourceMetadata metadata = mappings.getMetadataFor(type);
return new RepositoryLinkBuilder(metadata, new BaseUri(config.getBaseUri()));
return new RepositoryLinkBuilder(metadata, new BaseUri(config.getBasePath()));
}
/*

View File

@@ -18,6 +18,9 @@ package org.springframework.data.rest.webmvc;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.net.URI;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.support.AopUtils;
@@ -30,8 +33,16 @@ import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
*/
public class BasePathAwareHandlerMappingUnitTests {
RepositoryRestConfiguration configuration = mock(RepositoryRestConfiguration.class);
HandlerMappingStub mapping = new HandlerMappingStub(configuration);
HandlerMappingStub mapping;
@Before
public void setUp() {
RepositoryRestConfiguration configuration = mock(RepositoryRestConfiguration.class);
doReturn(URI.create("")).when(configuration).getBasePath();
mapping = new HandlerMappingStub(configuration);
}
@Test // DATAREST-1132
public void detectsAnnotationsOnProxies() {

View File

@@ -19,7 +19,9 @@ import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collections;
import java.util.function.Supplier;
import javax.servlet.http.HttpServletRequest;
@@ -71,7 +73,7 @@ public class RepositoryRestHandlerMappingUnitTests {
@Mock Repositories repositories;
RepositoryRestConfiguration configuration;
HandlerMappingStub handlerMapping;
Supplier<HandlerMappingStub> handlerMapping;
MockHttpServletRequest mockRequest;
Method listEntitiesMethod, rootHandlerMethod;
@@ -81,8 +83,14 @@ public class RepositoryRestHandlerMappingUnitTests {
configuration = new RepositoryRestConfiguration(new ProjectionDefinitionConfiguration(),
new MetadataConfiguration(), mock(EnumTranslationConfiguration.class));
handlerMapping = new HandlerMappingStub(mappings, configuration, repositories);
handlerMapping.setApplicationContext(CONTEXT);
handlerMapping = () -> {
HandlerMappingStub mapping = new HandlerMappingStub(mappings, configuration, repositories);
mapping.setApplicationContext(CONTEXT);
mapping.afterPropertiesSet();
return mapping;
};
mockRequest = new MockHttpServletRequest();
@@ -103,9 +111,7 @@ public class RepositoryRestHandlerMappingUnitTests {
@Test // DATAREST-111
public void returnsNullForUriNotMapped() throws Exception {
handlerMapping.afterPropertiesSet();
assertThat(handlerMapping.getHandler(mockRequest)).isNull();
assertThat(handlerMapping.get().getHandler(mockRequest)).isNull();
}
@Test // DATAREST-111
@@ -114,8 +120,7 @@ public class RepositoryRestHandlerMappingUnitTests {
when(mappings.exportsTopLevelResourceFor("/people")).thenReturn(true);
mockRequest = new MockHttpServletRequest("GET", "/people");
handlerMapping.afterPropertiesSet();
HandlerMethod method = handlerMapping.getHandlerInternal(mockRequest);
HandlerMethod method = handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(method).isNotNull();
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
@@ -128,9 +133,8 @@ public class RepositoryRestHandlerMappingUnitTests {
mockRequest = new MockHttpServletRequest("GET", "/base/people");
configuration.setBasePath("/base");
handlerMapping.afterPropertiesSet();
HandlerMethod method = handlerMapping.getHandlerInternal(mockRequest);
HandlerMethod method = handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(method).isNotNull();
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
@@ -142,9 +146,8 @@ public class RepositoryRestHandlerMappingUnitTests {
mockRequest = new MockHttpServletRequest("GET", "/base");
configuration.setBasePath("/base");
handlerMapping.afterPropertiesSet();
HandlerMethod method = handlerMapping.getHandlerInternal(mockRequest);
HandlerMethod method = handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(method).isNotNull();
assertThat(method.getMethod()).isEqualTo(rootHandlerMethod);
@@ -157,9 +160,8 @@ public class RepositoryRestHandlerMappingUnitTests {
mockRequest = new MockHttpServletRequest("GET", "/base/people/");
configuration.setBasePath("/base");
handlerMapping.afterPropertiesSet();
HandlerMethod method = handlerMapping.getHandlerInternal(mockRequest);
HandlerMethod method = handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(method).isNotNull();
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
@@ -173,9 +175,8 @@ public class RepositoryRestHandlerMappingUnitTests {
mockRequest.setServletPath("/base/people");
configuration.setBasePath("/base");
handlerMapping.afterPropertiesSet();
HandlerMethod method = handlerMapping.getHandlerInternal(mockRequest);
HandlerMethod method = handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(method).isNotNull();
assertThat(method.getMethod()).isEqualTo(listEntitiesMethod);
@@ -189,7 +190,7 @@ public class RepositoryRestHandlerMappingUnitTests {
configuration.setBasePath("/base");
HandlerMethod method = handlerMapping.getHandlerInternal(mockRequest);
HandlerMethod method = handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(method).isNull();
}
@@ -206,7 +207,7 @@ public class RepositoryRestHandlerMappingUnitTests {
configuration.setBasePath(baseUri);
HandlerMethod method = handlerMapping.getHandlerInternal(mockRequest);
HandlerMethod method = handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(method).isNull();
}
@@ -218,7 +219,7 @@ public class RepositoryRestHandlerMappingUnitTests {
mockRequest = new MockHttpServletRequest("GET", "/people{?projection}");
assertThat(handlerMapping.getHandler(mockRequest)).isNull();
assertThat(handlerMapping.get().getHandler(mockRequest)).isNull();
}
@Test // DATAREST-1019
@@ -233,7 +234,7 @@ public class RepositoryRestHandlerMappingUnitTests {
mockRequest = new MockHttpServletRequest("GET", uri);
mockRequest.setServletPath(uri);
handlerMapping.getCorsConfiguration(uri, mockRequest);
handlerMapping.get().getCorsConfiguration(uri, mockRequest);
verify(mappings).exportsTopLevelResourceFor("/people");
}
@@ -253,7 +254,7 @@ public class RepositoryRestHandlerMappingUnitTests {
mockRequest = new MockHttpServletRequest("GET", uri);
mockRequest.setServletPath(uri);
handlerMapping.getCorsConfiguration(uri, mockRequest);
handlerMapping.get().getCorsConfiguration(uri, mockRequest);
verify(mappings).exportsTopLevelResourceFor("/people");
}
@@ -268,8 +269,10 @@ public class RepositoryRestHandlerMappingUnitTests {
Class<?> type = createProxy(new SomeController());
HandlerMappingStub mapping = new HandlerMappingStub(mock(ResourceMappings.class),
mock(RepositoryRestConfiguration.class));
RepositoryRestConfiguration configuration = mock(RepositoryRestConfiguration.class);
doReturn(URI.create("")).when(configuration).getBasePath();
HandlerMappingStub mapping = new HandlerMappingStub(mock(ResourceMappings.class), configuration);
assertThat(mapping.isHandler(type)).isTrue();
}
@@ -281,8 +284,7 @@ public class RepositoryRestHandlerMappingUnitTests {
MockHttpServletRequest mockRequest = new MockHttpServletRequest("GET", "/people/search/findByLastnameLike");
handlerMapping.afterPropertiesSet();
handlerMapping.getHandlerInternal(mockRequest);
handlerMapping.get().getHandlerInternal(mockRequest);
assertThat(mockRequest.getAttribute(RepositoryRestHandlerMapping.EFFECTIVE_LOOKUP_PATH_ATTRIBUTE)) //
.isInstanceOfSatisfying(PathPattern.class, it -> {
@@ -299,9 +301,7 @@ public class RepositoryRestHandlerMappingUnitTests {
request.addHeader(HttpHeaders.ORIGIN, "test case");
request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET");
handlerMapping.afterPropertiesSet();
assertThatCode(() -> handlerMapping.getHandlerInternal(request)).doesNotThrowAnyException();
assertThatCode(() -> handlerMapping.get().getHandlerInternal(request)).doesNotThrowAnyException();
}
private static Class<?> createProxy(Object source) {

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.rest.webmvc.support;
package org.springframework.data.rest.webmvc.config;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;