DATAREST-292 - Fixed application of configured base URI.

Major overhaul of mapping detection in RepositoryRestHandlerMapping. We now correctly map URIs if a base URI is configured via RepositoryRestConfiguration.

Additional tweaks needed for the back-port.
This commit is contained in:
Oliver Gierke
2014-04-23 17:56:28 +02:00
parent 0c3748c3c4
commit 29c16a0e74
8 changed files with 90 additions and 26 deletions

View File

@@ -31,7 +31,7 @@ import org.springframework.util.Assert;
@SuppressWarnings("deprecation")
public class RepositoryRestConfiguration {
private URI baseUri = null;
private URI baseUri = URI.create("");
private int defaultPageSize = 20;
private int maxPageSize = 1000;
private String pageParamName = "page";

View File

@@ -31,8 +31,11 @@ import org.springframework.data.rest.webmvc.support.JpaHelper;
import org.springframework.http.MediaType;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
/**
* {@link RequestMappingHandlerMapping} implementation that will only find a handler method if a
@@ -111,24 +114,28 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
HttpServletRequest request = new DefaultAcceptTypeHttpServletRequest(origRequest, acceptType);
String requestUri = lookupPath;
if (requestUri.startsWith("/")) {
requestUri = requestUri.substring(1);
}
if (!hasText(requestUri)) {
if (!hasText(lookupPath)) {
return super.lookupHandlerMethod(lookupPath, request);
}
String[] parts = requestUri.split("/");
// Strip base URI
UriComponents components = UriComponentsBuilder.fromPath(lookupPath).build();
List<String> segments = components.getPathSegments();
String baseUri = config.getBaseUri().toString();
int repositoryIndex = !segments.isEmpty() && segments.get(0).equals(baseUri) ? 1 : 0;
segments = segments.subList(repositoryIndex, segments.size());
if (parts.length == 0) {
// Root request
return super.lookupHandlerMethod(lookupPath, request);
String uri = "/".concat(StringUtils.collectionToDelimitedString(segments, "/"));
request = new DefaultAcceptTypeHttpServletRequest(origRequest, acceptType, uri);
// Root request
if (uri.equals("/")) {
return super.lookupHandlerMethod(uri, request);
}
if (mappings.exportsTopLevelResourceFor(parts[0])) {
return super.lookupHandlerMethod(lookupPath, request);
if (mappings.exportsTopLevelResourceFor(segments.get(0))) {
return super.lookupHandlerMethod(uri, request);
}
return null;
@@ -159,10 +166,16 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
private static class DefaultAcceptTypeHttpServletRequest extends HttpServletRequestWrapper {
private final String defaultAcceptType;
private final String requestUri;
private DefaultAcceptTypeHttpServletRequest(HttpServletRequest request, String defaultAcceptType) {
this(request, defaultAcceptType, null);
}
private DefaultAcceptTypeHttpServletRequest(HttpServletRequest request, String defaultAcceptType, String requestUri) {
super(request);
this.defaultAcceptType = defaultAcceptType;
this.requestUri = requestUri;
}
@Override
@@ -174,5 +187,14 @@ public class RepositoryRestHandlerMapping extends RequestMappingHandlerMapping {
return super.getHeader(name);
}
}
/*
* (non-Javadoc)
* @see javax.servlet.http.HttpServletRequestWrapper#getRequestURI()
*/
@Override
public String getRequestURI() {
return requestUri != null ? requestUri : super.getRequestURI();
}
}
}

View File

@@ -289,7 +289,7 @@ public class RepositoryRestMvcConfiguration extends HateoasAwareSpringDataWebCon
*/
@Bean
public PersistentEntityToJsonSchemaConverter jsonSchemaConverter() {
return new PersistentEntityToJsonSchemaConverter(repositories(), resourceMappings(),
return new PersistentEntityToJsonSchemaConverter(repositories(), resourceMappings(), config(),
resourceDescriptionMessageSourceAccessor());
}

View File

@@ -32,6 +32,7 @@ import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.SimpleAssociationHandler;
import org.springframework.data.mapping.SimplePropertyHandler;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.ResourceDescription;
import org.springframework.data.rest.core.mapping.ResourceMapping;
import org.springframework.data.rest.core.mapping.ResourceMappings;
@@ -55,6 +56,7 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
private final ResourceMappings mappings;
private final Repositories repositories;
private final MessageSourceAccessor accessor;
private final RepositoryRestConfiguration config;
/**
* Creates a new {@link PersistentEntityToJsonSchemaConverter} for the given {@link Repositories} and
@@ -65,13 +67,16 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
* @param accessor
*/
public PersistentEntityToJsonSchemaConverter(Repositories repositories, ResourceMappings mappings,
MessageSourceAccessor accessor) {
RepositoryRestConfiguration config, MessageSourceAccessor accessor) {
Assert.notNull(repositories, "Repositories must not be null!");
Assert.notNull(mappings, "ResourceMappings must not be null!");
Assert.notNull(config, "RepositoryRestConfiguration must not be null!");
this.repositories = repositories;
this.mappings = mappings;
this.config = config;
this.accessor = accessor;
for (Class<?> domainType : repositories) {
@@ -155,7 +160,7 @@ public class PersistentEntityToJsonSchemaConverter implements ConditionalGeneric
return;
}
RepositoryLinkBuilder builder = new RepositoryLinkBuilder(metadata, null).slash("{id}");
RepositoryLinkBuilder builder = new RepositoryLinkBuilder(metadata, config.getBaseUri()).slash("{id}");
maybeAddAssociationLink(builder, mappings, persistentProperty, links);
}
});

View File

@@ -19,10 +19,9 @@ import java.net.URI;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.rest.core.mapping.ResourceMetadata;
import org.springframework.data.rest.webmvc.RepositoryController;
import org.springframework.hateoas.Link;
import org.springframework.hateoas.core.LinkBuilderSupport;
import org.springframework.hateoas.mvc.ControllerLinkBuilder;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
public class RepositoryLinkBuilder extends LinkBuilderSupport<RepositoryLinkBuilder> {
@@ -41,8 +40,12 @@ public class RepositoryLinkBuilder extends LinkBuilderSupport<RepositoryLinkBuil
private static UriComponentsBuilder prepareBuilder(URI baseUri, ResourceMetadata metadata) {
UriComponentsBuilder builder = baseUri != null ? UriComponentsBuilder.fromUri(baseUri) : ControllerLinkBuilder
.linkTo(RepositoryController.class).toUriComponentsBuilder();
UriComponentsBuilder builder = ServletUriComponentsBuilder.fromCurrentServletMapping();
if (baseUri != null) {
builder = builder.path(baseUri.toString());
}
return builder.path(metadata.getPath().toString());
}

View File

@@ -20,6 +20,7 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.lang.reflect.Method;
import java.net.URI;
import org.junit.Before;
import org.junit.Test;
@@ -51,7 +52,7 @@ public class RepositoryRestHandlerMappingUnitTests {
RepositoryRestConfiguration configuration;
RepositoryRestHandlerMapping handlerMapping;
MockHttpServletRequest mockRequest;
Method listEntitiesMethod;
Method listEntitiesMethod, rootHandlerMethod;
@Before
public void setUp() throws Exception {
@@ -66,6 +67,7 @@ public class RepositoryRestHandlerMappingUnitTests {
listEntitiesMethod = RepositoryEntityController.class.getMethod("listEntities", RootResourceInformation.class,
Pageable.class, Sort.class);
rootHandlerMethod = RepositoryController.class.getMethod("listRepositories");
}
@Test(expected = IllegalArgumentException.class)
@@ -100,4 +102,38 @@ public class RepositoryRestHandlerMappingUnitTests {
assertThat(method, is(notNullValue()));
assertThat(method.getMethod(), is(listEntitiesMethod));
}
/**
* @see DATAREST-292
*/
@Test
public void returnsRepositoryHandlerMethodWithBaseUriConfigured() throws Exception {
when(mappings.exportsTopLevelResourceFor("people")).thenReturn(true);
mockRequest = new MockHttpServletRequest("GET", "/base/people");
configuration.setBaseUri(URI.create("base"));
HandlerMethod method = handlerMapping.lookupHandlerMethod("/base/people", mockRequest);
assertThat(method, is(notNullValue()));
assertThat(method.getMethod(), is(listEntitiesMethod));
}
/**
* @see DATAREST-292
*/
@Test
public void returnsRootHandlerMethodWithBaseUriConfigured() throws Exception {
when(mappings.exportsTopLevelResourceFor("people")).thenReturn(true);
mockRequest = new MockHttpServletRequest("GET", "/base");
configuration.setBaseUri(URI.create("base"));
HandlerMethod method = handlerMapping.lookupHandlerMethod("/base", mockRequest);
assertThat(method, is(notNullValue()));
assertThat(method.getMethod(), is(rootHandlerMethod));
}
}

View File

@@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.repository.support.Repositories;
import org.springframework.data.rest.webmvc.PersistentEntityResource;
import org.springframework.data.rest.webmvc.WebTestUtils;
import org.springframework.data.rest.webmvc.jpa.LineItem;
import org.springframework.data.rest.webmvc.jpa.Order;
import org.springframework.data.rest.webmvc.jpa.OrderRepository;
@@ -74,6 +75,7 @@ public class PersistentEntitySerializationTests {
@Before
public void setUp() {
WebTestUtils.initWebTest();
linkDiscoverer = new HalLinkDiscoverer();
}
@@ -212,7 +214,7 @@ public class PersistentEntitySerializationTests {
assertThat(mapper.writeValueAsString(persistentEntityResource),
is("{\"_embedded\":{\"orders\":[{\"lineItems\":[{\"name\":\"first\"},{\"name\":\"second\"}],\"price\":2.5"
+ ",\"_links\":{\"creator\":{\"href\":\"http://localhost:8080/orders/1/creator\"}}}]},\""
+ ",\"_links\":{\"creator\":{\"href\":\"http://localhost/orders/1/creator\"}}}]},\""
+ "page\":{\"size\":1,\"totalElements\":10,\"totalPages\":10,\"number\":0}}"));
}
}

View File

@@ -15,8 +15,6 @@
*/
package org.springframework.data.rest.webmvc.json;
import java.net.URI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -72,8 +70,6 @@ public class RepositoryTestsConfig {
config.setResourceMappingForRepository(PersonRepository.class).setRel("people").setPath("people")
.addResourceMappingFor("findByFirstName").setRel("firstname").setPath("firstname");
config.setBaseUri(URI.create("http://localhost:8080"));
return config;
}