From eb4b801dc9d810c0df4429ce53387980a3b20756 Mon Sep 17 00:00:00 2001 From: Nick Williams Date: Sun, 18 Aug 2013 20:10:55 -0500 Subject: [PATCH] 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. --- pom.xml | 12 +- src/docbkx/repositories.xml | 6 +- ...PageableHandlerMethodArgumentResolver.java | 108 ++++++++++++++++ ...eoasSortHandlerMethodArgumentResolver.java | 66 ++++++++++ ...PageableHandlerMethodArgumentResolver.java | 117 +++++++++++------- .../data/web/PagedResourcesAssembler.java | 7 +- ...gedResourcesAssemblerArgumentResolver.java | 5 +- .../SortHandlerMethodArgumentResolver.java | 51 ++------ .../config/EnableSpringDataWebSupport.java | 9 +- ...ateoasAwareSpringDataWebConfiguration.java | 23 ++++ .../config/SpringDataWebConfiguration.java | 12 +- ...andlerMethodArgumentResolverUnitTests.java | 96 ++++++++++++++ ...andlerMethodArgumentResolverUnitTests.java | 53 ++++++++ ...ndlerMethodArgumentResolverUnitTests.java} | 22 +++- .../data/web/PageableDefaultUnitTests.java | 12 +- ...andlerMethodArgumentResolverUnitTests.java | 44 +------ .../web/PagedResourcesAssemblerUnitTests.java | 3 +- ...ndlerMethodArgumentResolverUnitTests.java} | 25 +--- ...eSpringDataWebSupportIntegrationTests.java | 9 ++ ...bleResourcesAssemblerIntegrationTests.java | 7 +- 20 files changed, 502 insertions(+), 185 deletions(-) create mode 100644 src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java create mode 100644 src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java create mode 100644 src/test/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolverUnitTests.java create mode 100644 src/test/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolverUnitTests.java rename src/test/java/org/springframework/data/web/{LegacyPageableHandlerArgumentResolverUnitTests.java => LegacyPageableHandlerMethodArgumentResolverUnitTests.java} (90%) rename src/test/java/org/springframework/data/web/{SortHandlerArgumentResolverUnitTests.java => SortHandlerMethodArgumentResolverUnitTests.java} (85%) diff --git a/pom.xml b/pom.xml index 9bad60afa..a23acc8c2 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ org.springframework.data.build spring-data-parent - 1.1.1.RELEASE + 1.2.0.BUILD-SNAPSHOT ../spring-data-build/parent/pom.xml @@ -162,6 +162,12 @@ ${springhateoas} true + + org.springframework + spring-webmvc + ${spring} + true + com.sun.xml.bind @@ -211,8 +217,8 @@ - spring-libs-releases - http://repo.springsource.org/libs-release-local + spring-libs-snapshot + http://repo.springsource.org/libs-snapshot-local diff --git a/src/docbkx/repositories.xml b/src/docbkx/repositories.xml index 7cacd1650..392ed2348 100644 --- a/src/docbkx/repositories.xml +++ b/src/docbkx/repositories.xml @@ -864,6 +864,10 @@ public class MyRepositoryFactoryBean<R extends JpaRepository<T, I>, T, range. As it the newly introduced support changes quite a lot of things we kept the documentation of the former behavior in . + + Also note that the JavaConfig support introduced in Spring Data + Commons 1.6 requires Spring 3.2 due to some issues with JavaConfig and + overridden methods in Spring 3.1. Spring Data modules ships with a variety of web support if the @@ -1128,7 +1132,7 @@ class PersonController { Assume we have 30 Person instances in the database. You can now trigger a request GET http://localhost:8080/persons and you'll see something similar - to this: + to this: { "links" : [ { "rel" : "next", "href" : "http://localhost:8080/persons?page=1&size=20 } diff --git a/src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java new file mode 100644 index 000000000..f3dfc1463 --- /dev/null +++ b/src/main/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolver.java @@ -0,0 +1,108 @@ +/* + * 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 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.web.util.UriComponentsBuilder; + +/** + * Extension of {@link PageableHandlerMethodArgumentResolver} that also supports enhancing URIs using Spring HATEOAS + * support. + * + * @since 1.6 + * @author Oliver Gierke + * @author Nick Williams + */ +@SuppressWarnings("deprecation") +public class HateoasPageableHandlerMethodArgumentResolver extends PageableHandlerMethodArgumentResolver implements + UriComponentsContributor { + + /** + * A {@link HateoasPageableHandlerMethodArgumentResolver} preconfigured to the setup of + * {@link PageableArgumentResolver}. Use that if you need to stick to the former request parameters an 1-indexed + * behavior. This will be removed in the next major version (1.7). So consider migrating to the new way of exposing + * request parameters. + */ + @Deprecated public static final HateoasPageableHandlerMethodArgumentResolver LEGACY; + private static final HateoasSortHandlerMethodArgumentResolver DEFAULT_SORT_RESOLVER = new HateoasSortHandlerMethodArgumentResolver(); + + static { + + HateoasSortHandlerMethodArgumentResolver LEGACY_SORT = new HateoasSortHandlerMethodArgumentResolver(); + LEGACY_SORT.setLegacyMode(true); + LEGACY_SORT.setSortParameter("page.sort"); + + LEGACY = new HateoasPageableHandlerMethodArgumentResolver(LEGACY_SORT); + LEGACY.setPageParameterName("page.page"); + LEGACY.setSizeParameterName("page.size"); + LEGACY.setFallbackPageable(new PageRequest(1, 10)); + LEGACY.setOneIndexedParameters(true); + } + + private final HateoasSortHandlerMethodArgumentResolver sortResolver; + + /** + * Constructs an instance of this resolver with a default {@link HateoasSortHandlerMethodArgumentResolver}. + */ + public HateoasPageableHandlerMethodArgumentResolver() { + this(null); + } + + /** + * Creates a new {@link HateoasPageableHandlerMethodArgumentResolver} using the given + * {@link HateoasSortHandlerMethodArgumentResolver}.. + * + * @param sortResolver + */ + public HateoasPageableHandlerMethodArgumentResolver(HateoasSortHandlerMethodArgumentResolver sortResolver) { + + super(getDefaultedSortResolver(sortResolver)); + this.sortResolver = getDefaultedSortResolver(sortResolver); + } + + private static HateoasSortHandlerMethodArgumentResolver getDefaultedSortResolver( + HateoasSortHandlerMethodArgumentResolver sortResolver) { + return sortResolver == null ? DEFAULT_SORT_RESOLVER : sortResolver; + } + + /* + * (non-Javadoc) + * @see org.springframework.hateoas.mvc.UriComponentsContributor#enhance(org.springframework.web.util.UriComponentsBuilder, org.springframework.core.MethodParameter, java.lang.Object) + */ + @Override + public void enhance(UriComponentsBuilder builder, MethodParameter parameter, Object value) { + + if (!(value instanceof Pageable)) { + return; + } + + Pageable pageable = (Pageable) value; + + String pagePropertyName = getParameterNameToUse(getPageParameterName(), parameter); + String sizePropertyName = getParameterNameToUse(getSizeParameterName(), parameter); + + int pageNumber = pageable.getPageNumber(); + + builder.replaceQueryParam(pagePropertyName, isOneIndexedParameters() ? pageNumber + 1 : pageNumber); + builder.replaceQueryParam(sizePropertyName, pageable.getPageSize() <= getMaxPageSize() ? pageable.getPageSize() + : getMaxPageSize()); + + this.sortResolver.enhance(builder, parameter, pageable.getSort()); + } +} diff --git a/src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java new file mode 100644 index 000000000..cebfe4a12 --- /dev/null +++ b/src/main/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolver.java @@ -0,0 +1,66 @@ +/* + * 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 java.util.List; + +import org.springframework.core.MethodParameter; +import org.springframework.data.domain.Sort; +import org.springframework.hateoas.mvc.UriComponentsContributor; +import org.springframework.util.Assert; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * Extension of {@link SortHandlerMethodArgumentResolver} that also supports enhancing URIs using Spring HATEOAS + * support. + * + * @since 1.6 + * @author Oliver Gierke + * @author Thomas Darimont + * @author Nick Williams + */ +public class HateoasSortHandlerMethodArgumentResolver extends SortHandlerMethodArgumentResolver + implements UriComponentsContributor { + + /* + * (non-Javadoc) + * @see org.springframework.hateoas.mvc.UriComponentsContributor#enhance(org.springframework.web.util.UriComponentsBuilder, org.springframework.core.MethodParameter, java.lang.Object) + */ + @Override + public void enhance(UriComponentsBuilder builder, MethodParameter parameter, Object value) { + + if (!(value instanceof Sort)) { + return; + } + + Sort sort = (Sort) value; + + if (legacyMode) { + + List expressions = legacyFoldExpressions(sort); + Assert.isTrue(expressions.size() == 2, + String.format("Expected 2 sort expressions (fields, direction) but got %d!", expressions.size())); + builder.queryParam(getSortParameter(parameter), expressions.get(0)); + builder.queryParam(getLegacyDirectionParameter(parameter), expressions.get(1)); + + } else { + + for (String expression : foldIntoExpressions(sort)) { + builder.queryParam(getSortParameter(parameter), expression); + } + } + } +} diff --git a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java index 7f6804ec4..571c59aa4 100644 --- a/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/PageableHandlerMethodArgumentResolver.java @@ -22,25 +22,24 @@ import org.springframework.core.MethodParameter; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.hateoas.mvc.UriComponentsContributor; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import org.springframework.web.util.UriComponentsBuilder; /** * Extracts paging information from web requests and thus allows injecting {@link Pageable} instances into controller - * methods. Request properties to be parsed can be configured. Default configuration uses request properties beginning - * with {@link #PAGE_PROPERTY}{@link #DEFAULT_SEPARATOR}. + * methods. Request properties to be parsed can be configured. Default configuration uses request parameters beginning + * with {@link #DEFAULT_PAGE_PARAMETER}{@link #DEFAULT_QUALIFIER_DELIMITER}. * * @since 1.6 * @author Oliver Gierke + * @author Nick Williams */ @SuppressWarnings("deprecation") -public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver, UriComponentsContributor { +public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { /** * A {@link PageableHandlerMethodArgumentResolver} preconfigured to the setup of {@link PageableArgumentResolver}. Use @@ -60,21 +59,37 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum } private static final Pageable DEFAULT_PAGE_REQUEST = new PageRequest(0, 20); - private static final String DEFAULT_PAGE_PROPERTY = "page"; - private static final String DEFAULT_SIZE_PROPERTY = "size"; + private static final String DEFAULT_PAGE_PARAMETER = "page"; + private static final String DEFAULT_SIZE_PARAMETER = "size"; private static final String DEFAULT_PREFIX = ""; private static final String DEFAULT_QUALIFIER_DELIMITER = "_"; private static final int DEFAULT_MAX_PAGE_SIZE = 2000; private Pageable fallbackPageable = DEFAULT_PAGE_REQUEST; - private SortHandlerMethodArgumentResolver sortResolver = new SortHandlerMethodArgumentResolver(); - private String pageParameterName = DEFAULT_PAGE_PROPERTY; - private String sizeParameterName = DEFAULT_SIZE_PROPERTY; + private SortHandlerMethodArgumentResolver sortResolver; + private String pageParameterName = DEFAULT_PAGE_PARAMETER; + private String sizeParameterName = DEFAULT_SIZE_PARAMETER; private String prefix = DEFAULT_PREFIX; private String qualifierDelimiter = DEFAULT_QUALIFIER_DELIMITER; private int maxPageSize = DEFAULT_MAX_PAGE_SIZE; private boolean oneIndexedParameters = false; + /** + * Constructs an instance of this resolved with a default {@link SortHandlerMethodArgumentResolver}. + */ + public PageableHandlerMethodArgumentResolver() { + this(null); + } + + /** + * Constructs an instance of this resolver with the specified {@link SortHandlerMethodArgumentResolver}. + * + * @param sortResolver The sort resolver to use + */ + public PageableHandlerMethodArgumentResolver(SortHandlerMethodArgumentResolver sortResolver) { + this.sortResolver = sortResolver == null ? new SortHandlerMethodArgumentResolver() : sortResolver; + } + /** * Configures the {@link Pageable} to be used as fallback in case no {@link PageableDefault} or * {@link PageableDefaults} (the latter only supported in legacy mode) can be found at the method parameter to be @@ -99,6 +114,16 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum this.maxPageSize = maxPageSize; } + /** + * Retrieves the maximum page size to be accepted. This allows to put an upper boundary of the page size to prevent + * potential attacks trying to issue an {@link OutOfMemoryError}. Defaults to {@link #DEFAULT_MAX_PAGE_SIZE}. + * + * @return the maximum page size allowed. + */ + protected int getMaxPageSize() { + return this.maxPageSize; + } + /** * Configures the parameter name to be used to find the page number in the request. Defaults to {@code page}. * @@ -110,6 +135,15 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum this.pageParameterName = pageParameterName; } + /** + * Retrieves the parameter name to be used to find the page number in the request. Defaults to {@code page}. + * + * @return the parameter name to be used, never {@literal null} or empty. + */ + protected String getPageParameterName() { + return this.pageParameterName; + } + /** * Configures the parameter name to be used to find the page size in the request. Defaults to {@code size}. * @@ -121,6 +155,15 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum this.sizeParameterName = sizeParameterName; } + /** + * Retrieves the parameter name to be used to find the page size in the request. Defaults to {@code size}. + * + * @return the parameter name to be used, never {@literal null} or empty. + */ + protected String getSizeParameterName() { + return this.sizeParameterName; + } + /** * Configures a general prefix to be prepended to the page number and page size parameters. Useful to namespace the * property names used in case they are clashing with ones used by your application. By default, no prefix is used. @@ -141,17 +184,6 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum this.qualifierDelimiter = qualifierDelimiter == null ? DEFAULT_QUALIFIER_DELIMITER : qualifierDelimiter; } - /** - * Configure the {@link SortHandlerMethodArgumentResolver} to be used with the - * {@link PageableHandlerMethodArgumentResolver}. - * - * @param sortResolver the {@link SortHandlerMethodArgumentResolver} to be used ot {@literal null} to reset it to the - * default one. - */ - public void setSortResolver(SortHandlerMethodArgumentResolver sortResolver) { - this.sortResolver = sortResolver == null ? new SortHandlerMethodArgumentResolver() : sortResolver; - } - /** * Configures whether to expose and assume 1-based page number indexes in the request parameters. Defaults to * {@literal false}, meaning a page number of 0 in the request equals the first page. If this is set to @@ -163,42 +195,31 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum this.oneIndexedParameters = oneIndexedParameters; } + /** + * Indicates whether to expose and assume 1-based page number indexes in the request parameters. Defaults to + * {@literal false}, meaning a page number of 0 in the request equals the first page. If this is set to + * {@literal true}, a page number of 1 in the request will be considered the first page. + * + * @return whether to assume 1-based page number indexes in the request parameters. + */ + protected boolean isOneIndexedParameters() { + return this.oneIndexedParameters; + } + /* * (non-Javadoc) * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter) */ + @Override public boolean supportsParameter(MethodParameter parameter) { return Pageable.class.equals(parameter.getParameterType()); } - /* - * (non-Javadoc) - * @see org.springframework.hateoas.mvc.UriComponentsContributor#enhance(org.springframework.web.util.UriComponentsBuilder, org.springframework.core.MethodParameter, java.lang.Object) - */ - public void enhance(UriComponentsBuilder builder, MethodParameter parameter, Object value) { - - if (!(value instanceof Pageable)) { - return; - } - - Pageable pageable = (Pageable) value; - - String pagePropertyName = getParameterNameToUse(pageParameterName, parameter); - String sizePropertyName = getParameterNameToUse(sizeParameterName, parameter); - - int pageNumber = pageable.getPageNumber(); - - builder.replaceQueryParam(pagePropertyName, oneIndexedParameters ? pageNumber + 1 : pageNumber); - builder.replaceQueryParam(sizePropertyName, pageable.getPageSize() <= maxPageSize ? pageable.getPageSize() - : maxPageSize); - - sortResolver.enhance(builder, parameter, pageable.getSort()); - } - - /* + /* * (non-Javadoc) * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory) */ + @Override public Pageable resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { @@ -225,9 +246,9 @@ public class PageableHandlerMethodArgumentResolver implements HandlerMethodArgum * * @param source the basic parameter name. * @param parameter the {@link MethodParameter} potentially qualified. - * @return + * @return the name of the request parameter. */ - private String getParameterNameToUse(String source, MethodParameter parameter) { + protected String getParameterNameToUse(String source, MethodParameter parameter) { StringBuilder builder = new StringBuilder(prefix); diff --git a/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java b/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java index 7afe0dd85..83732cc85 100644 --- a/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java +++ b/src/main/java/org/springframework/data/web/PagedResourcesAssembler.java @@ -38,10 +38,11 @@ import org.springframework.web.util.UriComponentsBuilder; * * @since 1.6 * @author Oliver Gierke + * @author Nick Williams */ public class PagedResourcesAssembler implements ResourceAssembler, PagedResources>> { - private final PageableHandlerMethodArgumentResolver pageableResolver; + private final HateoasPageableHandlerMethodArgumentResolver pageableResolver; private final UriComponents baseUri; /** @@ -52,9 +53,9 @@ public class PagedResourcesAssembler implements ResourceAssembler, Pa * @param resolver * @param baseUri */ - public PagedResourcesAssembler(PageableHandlerMethodArgumentResolver resolver, UriComponents baseUri) { + public PagedResourcesAssembler(HateoasPageableHandlerMethodArgumentResolver resolver, UriComponents baseUri) { - this.pageableResolver = resolver == null ? new PageableHandlerMethodArgumentResolver() : resolver; + this.pageableResolver = resolver == null ? new HateoasPageableHandlerMethodArgumentResolver() : resolver; this.baseUri = baseUri; } diff --git a/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java b/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java index 1b38b4e5f..4f3c5b369 100644 --- a/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/PagedResourcesAssemblerArgumentResolver.java @@ -32,10 +32,11 @@ import org.springframework.web.util.UriComponentsBuilder; * * @since 1.6 * @author Oliver Gierke + * @author Nick Williams */ public class PagedResourcesAssemblerArgumentResolver implements HandlerMethodArgumentResolver { - private final PageableHandlerMethodArgumentResolver resolver; + private final HateoasPageableHandlerMethodArgumentResolver resolver; private final MethodLinkBuilderFactory linkBuilderFactory; /** @@ -45,7 +46,7 @@ public class PagedResourcesAssemblerArgumentResolver implements HandlerMethodArg * @param resolver can be {@literal null}. * @param linkBuilderFactory can be {@literal null}, will be defaulted to a {@link ControllerLinkBuilderFactory}. */ - public PagedResourcesAssemblerArgumentResolver(PageableHandlerMethodArgumentResolver resolver, + public PagedResourcesAssemblerArgumentResolver(HateoasPageableHandlerMethodArgumentResolver resolver, MethodLinkBuilderFactory linkBuilderFactory) { this.resolver = resolver; diff --git a/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java index 5289da0b0..228a60736 100644 --- a/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java +++ b/src/main/java/org/springframework/data/web/SortHandlerMethodArgumentResolver.java @@ -25,7 +25,6 @@ import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Direction; import org.springframework.data.domain.Sort.Order; import org.springframework.data.web.SortDefault.SortDefaults; -import org.springframework.hateoas.mvc.UriComponentsContributor; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import org.springframework.web.bind.support.WebDataBinderFactory; @@ -33,7 +32,6 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.context.request.WebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -import org.springframework.web.util.UriComponentsBuilder; /** * {@link HandlerMethodArgumentResolver} to automatically create {@link Sort} instances from request parameters or @@ -42,8 +40,9 @@ import org.springframework.web.util.UriComponentsBuilder; * @since 1.6 * @author Oliver Gierke * @author Thomas Darimont + * @author Nick Williams */ -public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver, UriComponentsContributor { +public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { private static final String DEFAULT_PARAMETER = "sort"; private static final String DEFAULT_PROPERTY_DELIMITER = ","; @@ -76,10 +75,10 @@ public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentR * * @param sortParameter must not be {@literal null} or empty. */ - public void setSortParameter(String parameter) { + public void setSortParameter(String sortParameter) { - Assert.hasText(parameter); - this.sortParameter = parameter; + Assert.hasText(sortParameter); + this.sortParameter = sortParameter; } /** @@ -108,42 +107,16 @@ public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentR * (non-Javadoc) * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter) */ + @Override public boolean supportsParameter(MethodParameter parameter) { return Sort.class.equals(parameter.getParameterType()); } - /* - * (non-Javadoc) - * @see org.springframework.hateoas.mvc.UriComponentsContributor#enhance(org.springframework.web.util.UriComponentsBuilder, org.springframework.core.MethodParameter, java.lang.Object) - */ - public void enhance(UriComponentsBuilder builder, MethodParameter parameter, Object value) { - - if (!(value instanceof Sort)) { - return; - } - - Sort sort = (Sort) value; - - if (legacyMode) { - - List expressions = legacyFoldExpressions(sort); - Assert.isTrue(expressions.size() == 2, - String.format("Expected 2 sort expressions (fields, direction) but got %d!", expressions.size())); - builder.queryParam(getSortParameter(parameter), expressions.get(0)); - builder.queryParam(getLegacyDirectionParameter(parameter), expressions.get(1)); - - } else { - - for (String expression : foldIntoExpressions(sort)) { - builder.queryParam(getSortParameter(parameter), expression); - } - } - } - - /* + /* * (non-Javadoc) * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory) */ + @Override public Sort resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { @@ -218,7 +191,7 @@ public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentR * @param parameter will never be {@literal null}. * @return */ - private String getSortParameter(MethodParameter parameter) { + protected String getSortParameter(MethodParameter parameter) { StringBuilder builder = new StringBuilder(); @@ -246,7 +219,7 @@ public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentR return new Sort(Direction.fromStringOrNull(directions), fields.split(",")); } - private String getLegacyDirectionParameter(MethodParameter parameter) { + protected String getLegacyDirectionParameter(MethodParameter parameter) { return getSortParameter(parameter) + ".dir"; } @@ -292,7 +265,7 @@ public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentR * @param sort must not be {@literal null}. * @return */ - private List foldIntoExpressions(Sort sort) { + protected List foldIntoExpressions(Sort sort) { List expressions = new ArrayList(); ExpressionBuilder builder = null; @@ -322,7 +295,7 @@ public class SortHandlerMethodArgumentResolver implements HandlerMethodArgumentR * @param sort must not be {@literal null}. * @return */ - private List legacyFoldExpressions(Sort sort) { + protected List legacyFoldExpressions(Sort sort) { List expressions = new ArrayList(); ExpressionBuilder builder = null; diff --git a/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java b/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java index 1bec124ee..69022a097 100644 --- a/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java +++ b/src/main/java/org/springframework/data/web/config/EnableSpringDataWebSupport.java @@ -27,6 +27,8 @@ import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.repository.support.DomainClassConverter; +import org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver; +import org.springframework.data.web.HateoasSortHandlerMethodArgumentResolver; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; import org.springframework.data.web.PagedResourcesAssembler; import org.springframework.data.web.PagedResourcesAssemblerArgumentResolver; @@ -37,7 +39,8 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; /** - * Annotation to automatically register the following beans for usage with Spring MVC. + * Annotation to automatically register the following beans for usage with Spring MVC. Note that using this annotation + * will require Spring 3.2. *
    *
  • {@link DomainClassConverter} - to allow usage of domain types managed by Spring Data repositories as controller * method arguments bound with {@link PathVariable} or {@link RequestParam}.
  • @@ -46,8 +49,10 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupp *
  • {@link SortHandlerMethodArgumentResolver} - to allow injection of {@link Sort} instances into controller methods * automatically created from request parameters.
  • *
- * If Spring HATEOAS is present on the classpath we will additionall register the following beans: + * If Spring HATEOAS is present on the classpath we will register the following beans: *
    + *
  • {@link HateoasPageableHandlerMethodArgumentResolver} - instead of {@link PageableHandlerMethodArgumentResolver}
  • + *
  • {@link HateoasSortHandlerMethodArgumentResolver} - instead of {@link SortHandlerMethodArgumentResolver}
  • *
  • {@link PagedResourcesAssembler} - for injection into web components
  • *
  • {@link PagedResourcesAssemblerArgumentResolver} - for injection of {@link PagedResourcesAssembler} into * controller methods
  • diff --git a/src/main/java/org/springframework/data/web/config/HateoasAwareSpringDataWebConfiguration.java b/src/main/java/org/springframework/data/web/config/HateoasAwareSpringDataWebConfiguration.java index 1bf03d726..f8b6c5956 100644 --- a/src/main/java/org/springframework/data/web/config/HateoasAwareSpringDataWebConfiguration.java +++ b/src/main/java/org/springframework/data/web/config/HateoasAwareSpringDataWebConfiguration.java @@ -19,6 +19,8 @@ import java.util.List; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.web.HateoasPageableHandlerMethodArgumentResolver; +import org.springframework.data.web.HateoasSortHandlerMethodArgumentResolver; import org.springframework.data.web.PagedResourcesAssembler; import org.springframework.data.web.PagedResourcesAssemblerArgumentResolver; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -28,10 +30,31 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver; * * @since 1.6 * @author Oliver Gierke + * @author Nick Williams */ @Configuration public class HateoasAwareSpringDataWebConfiguration extends SpringDataWebConfiguration { + /* + * (non-Javadoc) + * @see org.springframework.data.web.config.SpringDataWebConfiguration#pageableResolver() + */ + @Bean + @Override + public HateoasPageableHandlerMethodArgumentResolver pageableResolver() { + return new HateoasPageableHandlerMethodArgumentResolver(sortResolver()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.web.config.SpringDataWebConfiguration#sortResolver() + */ + @Bean + @Override + public HateoasSortHandlerMethodArgumentResolver sortResolver() { + return new HateoasSortHandlerMethodArgumentResolver(); + } + @Bean public PagedResourcesAssembler pagedResourcesAssembler() { return new PagedResourcesAssembler(pageableResolver(), null); diff --git a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java index b780374c7..b5bccb327 100644 --- a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java +++ b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java @@ -41,11 +41,19 @@ public class SpringDataWebConfiguration extends WebMvcConfigurerAdapter { @Autowired private ApplicationContext context; + /* + * (non-Javadoc) + * @see org.springframework.data.web.config.SpringDataWebConfiguration#pageableResolver() + */ @Bean public PageableHandlerMethodArgumentResolver pageableResolver() { - return new PageableHandlerMethodArgumentResolver(); + return new PageableHandlerMethodArgumentResolver(sortResolver()); } + /* + * (non-Javadoc) + * @see org.springframework.data.web.config.SpringDataWebConfiguration#sortResolver() + */ @Bean public SortHandlerMethodArgumentResolver sortResolver() { return new SortHandlerMethodArgumentResolver(); @@ -79,7 +87,7 @@ public class SpringDataWebConfiguration extends WebMvcConfigurerAdapter { @Override public void addArgumentResolvers(List argumentResolvers) { - argumentResolvers.add(pageableResolver()); argumentResolvers.add(sortResolver()); + argumentResolvers.add(pageableResolver()); } } diff --git a/src/test/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolverUnitTests.java new file mode 100644 index 000000000..0100dcbf3 --- /dev/null +++ b/src/test/java/org/springframework/data/web/HateoasPageableHandlerMethodArgumentResolverUnitTests.java @@ -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 params = builder.build().getQueryParams(); + + List page = params.get("page"); + assertThat(page.size(), is(1)); + assertThat(page.get(0), is("1")); + + List 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)); + } +} diff --git a/src/test/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolverUnitTests.java new file mode 100644 index 000000000..d0492e740 --- /dev/null +++ b/src/test/java/org/springframework/data/web/HateoasSortHandlerMethodArgumentResolverUnitTests.java @@ -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)); + } +} diff --git a/src/test/java/org/springframework/data/web/LegacyPageableHandlerArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/LegacyPageableHandlerMethodArgumentResolverUnitTests.java similarity index 90% rename from src/test/java/org/springframework/data/web/LegacyPageableHandlerArgumentResolverUnitTests.java rename to src/test/java/org/springframework/data/web/LegacyPageableHandlerMethodArgumentResolverUnitTests.java index f1111333c..6563c1b41 100644 --- a/src/test/java/org/springframework/data/web/LegacyPageableHandlerArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/LegacyPageableHandlerMethodArgumentResolverUnitTests.java @@ -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", diff --git a/src/test/java/org/springframework/data/web/PageableDefaultUnitTests.java b/src/test/java/org/springframework/data/web/PageableDefaultUnitTests.java index 19519e851..1504f7a44 100644 --- a/src/test/java/org/springframework/data/web/PageableDefaultUnitTests.java +++ b/src/test/java/org/springframework/data/web/PageableDefaultUnitTests.java @@ -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(); diff --git a/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java index 5f124d2b5..71bce2c49 100644 --- a/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/PageableHandlerMethodArgumentResolverUnitTests.java @@ -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 params = builder.build().getQueryParams(); - - List page = params.get("page"); - assertThat(page.size(), is(1)); - assertThat(page.get(0), is("1")); - - List 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(""); diff --git a/src/test/java/org/springframework/data/web/PagedResourcesAssemblerUnitTests.java b/src/test/java/org/springframework/data/web/PagedResourcesAssemblerUnitTests.java index 9287971b1..86c02cfac 100644 --- a/src/test/java/org/springframework/data/web/PagedResourcesAssemblerUnitTests.java +++ b/src/test/java/org/springframework/data/web/PagedResourcesAssemblerUnitTests.java @@ -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() { diff --git a/src/test/java/org/springframework/data/web/SortHandlerArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/SortHandlerMethodArgumentResolverUnitTests.java similarity index 85% rename from src/test/java/org/springframework/data/web/SortHandlerArgumentResolverUnitTests.java rename to src/test/java/org/springframework/data/web/SortHandlerMethodArgumentResolverUnitTests.java index df0fa39aa..97643441b 100644 --- a/src/test/java/org/springframework/data/web/SortHandlerArgumentResolverUnitTests.java +++ b/src/test/java/org/springframework/data/web/SortHandlerMethodArgumentResolverUnitTests.java @@ -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); } diff --git a/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java b/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java index 365c1370a..5ca25a016 100644 --- a/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java +++ b/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java @@ -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 names = Arrays.asList(context.getBeanDefinitionNames()); + assertThat(names, hasItems("pageableResolver", "sortResolver")); assertThat(names, not(hasItems("pagedResourcesAssembler", "pagedResourcesAssemblerArgumentResolver"))); } diff --git a/src/test/java/org/springframework/data/web/config/PageableResourcesAssemblerIntegrationTests.java b/src/test/java/org/springframework/data/web/config/PageableResourcesAssemblerIntegrationTests.java index ee4d7bde9..466313b25 100644 --- a/src/test/java/org/springframework/data/web/config/PageableResourcesAssemblerIntegrationTests.java +++ b/src/test/java/org/springframework/data/web/config/PageableResourcesAssemblerIntegrationTests.java @@ -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 assembler; + @Autowired PagedResourcesAssembler assembler; @RequestMapping("/persons") PagedResources> sample(Pageable pageable) {