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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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))//
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user