DATACMNS-353 - Make Spring HATEOAS purely optional.

Extracted the implementation of UriComponentsContributor from PageableHandlerMethoArgumentResolver and SortHandlerMethodArgumentResolver into dedicated subclasses so that we can really make Spring HATEOAS an optional dependency.

The integration tests are now guarded with an assumption to run on Spring 3.2 as Spring 3.1 has issues with JavaConfig and configuration method overrides. We've upgraded to Spring Data Build 1.2 snapshots so that the tests can be run with -Pspring32. This effectively means that the Spring Data Web support can only be used with a current Spring 3.2. Added a note on that in the reference docs and JavaDoc of @EnableSpringDataWebSupport.

Original pull request: #39.
This commit is contained in:
Nick Williams
2013-08-18 20:10:55 -05:00
committed by Oliver Gierke
parent 9843447a58
commit eb4b801dc9
20 changed files with 502 additions and 185 deletions

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.web;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.mvc.UriComponentsContributor;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Unit tests for {@link HateoasPageableHandlerMethodArgumentResolver}.
*
* @author Oliver Gierke
*/
public class HateoasPageableHandlerMethodArgumentResolverUnitTests extends
PageableHandlerMethodArgumentResolverUnitTests {
@Test
public void buildsUpRequestParameters() {
String basicString = String.format("page=%d&size=%d", PAGE_NUMBER, PAGE_SIZE);
assertUriStringFor(REFERENCE_WITHOUT_SORT, basicString);
assertUriStringFor(REFERENCE_WITH_SORT, basicString + "&sort=firstname,lastname,desc");
assertUriStringFor(REFERENCE_WITH_SORT_FIELDS, basicString + "&sort=firstname,lastname,asc");
}
/**
* @see DATACMNS-343
*/
@Test
public void replacesExistingPaginationInformation() throws Exception {
MethodParameter parameter = new MethodParameter(Sample.class.getMethod("supportedMethod", Pageable.class), 0);
UriComponentsContributor resolver = new HateoasPageableHandlerMethodArgumentResolver();
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080?page=0&size=10");
resolver.enhance(builder, parameter, new PageRequest(1, 20));
MultiValueMap<String, String> params = builder.build().getQueryParams();
List<String> page = params.get("page");
assertThat(page.size(), is(1));
assertThat(page.get(0), is("1"));
List<String> size = params.get("size");
assertThat(size.size(), is(1));
assertThat(size.get(0), is("20"));
}
/**
* @see DATACMNS-335
*/
@Test
public void preventsPageSizeFromExceedingMayValueIfConfiguredOnWrite() throws Exception {
assertUriStringFor(new PageRequest(0, 200), "page=0&size=100");
}
@Override
protected HateoasPageableHandlerMethodArgumentResolver getResolver() {
HateoasPageableHandlerMethodArgumentResolver resolver = new HateoasPageableHandlerMethodArgumentResolver();
resolver.setMaxPageSize(100);
return resolver;
}
protected void assertUriStringFor(Pageable pageable, String expected) {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/");
MethodParameter parameter = getParameterOfMethod("supportedMethod");
getResolver().enhance(builder, parameter, pageable);
assertThat(builder.build().toUriString(), endsWith(expected));
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.web;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.domain.Sort.Direction.*;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Sort;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Unit tests for {@link HateoasSortHandlerMethodArgumentResolver}
*
* @author Oliver Gierke
*/
public class HateoasSortHandlerMethodArgumentResolverUnitTests extends SortHandlerMethodArgumentResolverUnitTests {
@Test
public void buildsUpRequestParameters() {
assertUriStringFor(SORT, "sort=firstname,lastname,desc");
assertUriStringFor(new Sort(ASC, "foo").and(new Sort(DESC, "bar").and(new Sort(ASC, "foobar"))),
"sort=foo,asc&sort=bar,desc&sort=foobar,asc");
assertUriStringFor(new Sort(ASC, "foo").and(new Sort(ASC, "bar").and(new Sort(DESC, "foobar"))),
"sort=foo,bar,asc&sort=foobar,desc");
}
private void assertUriStringFor(Sort sort, String expected) {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/");
MethodParameter parameter = getParameterOfMethod("supportedMethod");
new HateoasSortHandlerMethodArgumentResolver().enhance(builder, parameter, sort);
assertThat(builder.build().toUriString(), endsWith(expected));
}
}

View File

@@ -32,6 +32,7 @@ import org.springframework.data.web.SortDefault.SortDefaults;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Unit tests for {@link PageableHandlerMethodArgumentResolver} in it's legacy mode. Essentially a copy of
@@ -39,9 +40,10 @@ import org.springframework.web.context.request.ServletWebRequest;
*
* @since 1.6
* @author Oliver Gierke
* @author Nick Williams
*/
@SuppressWarnings("deprecation")
public class LegacyPageableHandlerArgumentResolverUnitTests extends PageableDefaultUnitTests {
public class LegacyPageableHandlerMethodArgumentResolverUnitTests extends PageableDefaultUnitTests {
Method correctMethod, noQualifiers, invalidQualifiers, defaultsMethod, defaultsMethodWithSort,
defaultsMethodWithSortAndDirection, otherMethod;
@@ -210,8 +212,18 @@ public class LegacyPageableHandlerArgumentResolverUnitTests extends PageableDefa
}
@Override
protected PageableHandlerMethodArgumentResolver getResolver() {
return PageableHandlerMethodArgumentResolver.LEGACY;
protected HateoasPageableHandlerMethodArgumentResolver getResolver() {
return HateoasPageableHandlerMethodArgumentResolver.LEGACY;
}
protected void assertUriStringFor(Pageable pageable, String expected) {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/");
MethodParameter parameter = getParameterOfMethod("supportedMethod");
getResolver().enhance(builder, parameter, pageable);
assertThat(builder.build().toUriString(), endsWith(expected));
}
static interface SampleController {
@@ -224,8 +236,8 @@ public class LegacyPageableHandlerArgumentResolverUnitTests extends PageableDefa
void simpleDefaultWithSortAndDirection(@PageableDefaults(value = PAGE_SIZE, pageNumber = PAGE_NUMBER, sort = {
"firstname", "lastname" }, sortDir = Direction.DESC) Pageable pageable);
void simpleDefaultWithExternalSort(
@PageableDefaults(value = PAGE_SIZE, pageNumber = PAGE_NUMBER) @SortDefault(sort = { "firstname", "lastname" }, direction = Direction.DESC) Pageable pageable);
void simpleDefaultWithExternalSort(@PageableDefaults(value = PAGE_SIZE, pageNumber = PAGE_NUMBER) @SortDefault(
sort = { "firstname", "lastname" }, direction = Direction.DESC) Pageable pageable);
void simpleDefaultWithContaineredExternalSort(
@PageableDefaults(value = PAGE_SIZE, pageNumber = PAGE_NUMBER) @SortDefaults(@SortDefault(sort = { "firstname",

View File

@@ -32,7 +32,6 @@ import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Base test class to test supporting of a {@link HandlerMethodArgumentResolver} implementation defaulting
@@ -42,6 +41,7 @@ import org.springframework.web.util.UriComponentsBuilder;
*
* @since 1.6
* @author Oliver Gierke
* @author Nick Williams
*/
public abstract class PageableDefaultUnitTests {
@@ -144,16 +144,6 @@ public abstract class PageableDefaultUnitTests {
assertThat(resolver.resolveArgument(parameter, null, request, null), is((Object) pageable));
}
protected void assertUriStringFor(Pageable pageable, String expected) {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/");
MethodParameter parameter = getParameterOfMethod("supportedMethod");
getResolver().enhance(builder, parameter, pageable);
assertThat(builder.build().toUriString(), endsWith(expected));
}
protected abstract PageableHandlerMethodArgumentResolver getResolver();
protected abstract Class<?> getControllerClass();

View File

@@ -15,11 +15,6 @@
*/
package org.springframework.data.web;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.MethodParameter;
@@ -27,38 +22,23 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.SortDefault.SortDefaults;
import org.springframework.hateoas.mvc.UriComponentsContributor;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Unit tests for {@link PageableHandlerMethodArgumentResolver}. Pulls in defaulting tests from
* {@link PageableDefaultUnitTests}.
*
* @author Oliver Gierke
* @author Nick Williams
*/
public class PageableHandlerMethodArgumentResolverUnitTests extends PageableDefaultUnitTests {
@Test
public void buildsUpRequestParameters() {
String basicString = String.format("page=%d&size=%d", PAGE_NUMBER, PAGE_SIZE);
assertUriStringFor(REFERENCE_WITHOUT_SORT, basicString);
assertUriStringFor(REFERENCE_WITH_SORT, basicString + "&sort=firstname,lastname,desc");
assertUriStringFor(REFERENCE_WITH_SORT_FIELDS, basicString + "&sort=firstname,lastname,asc");
}
/**
* @see DATACMNS-335
*/
@Test
public void preventsPageSizeFromExceedingMayValueIfConfigured() throws Exception {
// Write side
assertUriStringFor(new PageRequest(0, 200), "page=0&size=100");
// Read side
MockHttpServletRequest request = new MockHttpServletRequest();
request.addParameter("page", "0");
@@ -69,28 +49,6 @@ public class PageableHandlerMethodArgumentResolverUnitTests extends PageableDefa
assertSupportedAndResult(parameter, new PageRequest(0, 100), request);
}
/**
* @see DATACMNS-343
*/
@Test
public void replacesExistingPaginationInformation() throws Exception {
MethodParameter parameter = new MethodParameter(Sample.class.getMethod("supportedMethod", Pageable.class), 0);
UriComponentsContributor resolver = new PageableHandlerMethodArgumentResolver();
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://localhost:8080?page=0&size=10");
resolver.enhance(builder, parameter, new PageRequest(1, 20));
MultiValueMap<String, String> params = builder.build().getQueryParams();
List<String> page = params.get("page");
assertThat(page.size(), is(1));
assertThat(page.get(0), is("1"));
List<String> size = params.get("size");
assertThat(size.size(), is(1));
assertThat(size.get(0), is("20"));
}
@Test(expected = IllegalArgumentException.class)
public void rejectsEmptyPageParameterName() {
new PageableHandlerMethodArgumentResolver().setPageParameterName("");

View File

@@ -35,10 +35,11 @@ import org.springframework.web.util.UriComponentsBuilder;
* Unit tests for {@link PagedResourcesAssembler}.
*
* @author Oliver Gierke
* @author Nick Williams
*/
public class PagedResourcesAssemblerUnitTests {
PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver();
HateoasPageableHandlerMethodArgumentResolver resolver = new HateoasPageableHandlerMethodArgumentResolver();
@Before
public void setUp() {

View File

@@ -17,7 +17,6 @@ package org.springframework.data.web;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.data.domain.Sort.Direction.*;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Qualifier;
@@ -30,7 +29,6 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.util.UriComponentsBuilder;
/**
* Unit tests for {@link SortHandlerMethodArgumentResolver}.
@@ -38,8 +36,9 @@ import org.springframework.web.util.UriComponentsBuilder;
* @since 1.6
* @author Oliver Gierke
* @author Thomas Darimont
* @author Nick Williams
*/
public class SortHandlerArgumentResolverUnitTests extends SortDefaultUnitTests {
public class SortHandlerMethodArgumentResolverUnitTests extends SortDefaultUnitTests {
static final String SORT_0 = "username";
static final String SORT_1 = "username,asc";
@@ -115,25 +114,6 @@ public class SortHandlerArgumentResolverUnitTests extends SortDefaultUnitTests {
assertThat(result, is(nullValue()));
}
@Test
public void buildsUpRequestParameters() {
assertUriStringFor(SORT, "sort=firstname,lastname,desc");
assertUriStringFor(new Sort(ASC, "foo").and(new Sort(DESC, "bar").and(new Sort(ASC, "foobar"))),
"sort=foo,asc&sort=bar,desc&sort=foobar,asc");
assertUriStringFor(new Sort(ASC, "foo").and(new Sort(ASC, "bar").and(new Sort(DESC, "foobar"))),
"sort=foo,bar,asc&sort=foobar,desc");
}
private void assertUriStringFor(Sort sort, String expected) {
UriComponentsBuilder builder = UriComponentsBuilder.fromPath("/");
MethodParameter parameter = getParameterOfMethod("supportedMethod");
new SortHandlerMethodArgumentResolver().enhance(builder, parameter, sort);
assertThat(builder.build().toUriString(), endsWith(expected));
}
private static void assertSupportedAndResolvedTo(NativeWebRequest request, MethodParameter parameter, Sort sort) {
SortHandlerMethodArgumentResolver resolver = new SortHandlerMethodArgumentResolver();
@@ -147,7 +127,6 @@ public class SortHandlerArgumentResolverUnitTests extends SortDefaultUnitTests {
}
private static NativeWebRequest getRequestWithSort(Sort sort) {
return getRequestWithSort(sort, null);
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.web.config;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
@@ -25,9 +26,11 @@ import java.util.List;
import org.hamcrest.Matcher;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.SpringVersion;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.data.web.PagedResourcesAssemblerArgumentResolver;
import org.springframework.data.web.SortHandlerMethodArgumentResolver;
@@ -53,6 +56,11 @@ public class EnableSpringDataWebSupportIntegrationTests {
}
@Before
public void setUp() {
assumeThat(SpringVersion.getVersion(), startsWith("3.2"));
}
@After
public void tearDown() {
reEnableHateoas();
@@ -88,6 +96,7 @@ public class EnableSpringDataWebSupportIntegrationTests {
ApplicationContext context = WebTestUtils.createApplicationContext(SampleConfig.class);
List<String> names = Arrays.asList(context.getBeanDefinitionNames());
assertThat(names, hasItems("pageableResolver", "sortResolver"));
assertThat(names, not(hasItems("pagedResourcesAssembler", "pagedResourcesAssemblerArgumentResolver")));
}

View File

@@ -17,6 +17,7 @@ package org.springframework.data.web.config;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import java.util.Arrays;
@@ -25,6 +26,7 @@ import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.SpringVersion;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
@@ -63,6 +65,8 @@ public class PageableResourcesAssemblerIntegrationTests {
@Test
public void injectsPagedResourcesAssembler() {
assumeThat(SpringVersion.getVersion(), startsWith("3.2"));
WebApplicationContext context = WebTestUtils.createApplicationContext(Config.class);
SampleController controller = context.getBean(SampleController.class);
@@ -77,8 +81,7 @@ public class PageableResourcesAssemblerIntegrationTests {
@Controller
static class SampleController {
@Autowired
PagedResourcesAssembler<Person> assembler;
@Autowired PagedResourcesAssembler<Person> assembler;
@RequestMapping("/persons")
PagedResources<Resource<Person>> sample(Pageable pageable) {