Add SlicedResourcesAssembler for web integration.
Added SlicedResourcesAssembler to esaily convert Slice instances into SlicedResource instances and automatically build the required previous/next link based on PageableHandlerMethodArgumentResolver present in the MVC configuration. The assembler can either be injected into a Spring MVC controller or a controller method. The latter will then assume the controller methods URI to be used as pagination link base. Added necessary SlicedResourcesAssemblerArgumentResolver and MethodParameterAwareSlicedResourcesAssembler classes and wire up HateoasAwareSpringDataWebConfiguration configuration beans to that SlicedResourcesAssembler's can be auto-injected into controllers. Closes #1307
This commit is contained in:
committed by
Oliver Drotbohm
parent
83655663ea
commit
70f21bda9f
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
|
||||
/**
|
||||
* Custom {@link SlicedResourcesAssembler} that is aware of the {@link MethodParameter} it shall create links for.
|
||||
*
|
||||
* @author Michael Schout
|
||||
*/
|
||||
public class MethodParameterAwareSlicedResourcesAssembler<T> extends SlicedResourcesAssembler<T> {
|
||||
private final MethodParameter parameter;
|
||||
|
||||
/**
|
||||
* Creates a new {@link MethodParameterAwareSlicedResourcesAssembler} using the given
|
||||
* {@link MethodParameter}, {@link HateoasPageableHandlerMethodArgumentResolver} and base
|
||||
* URI.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @param resolver can be {@literal null}.
|
||||
* @param baseUri can be {@literal null}.
|
||||
*/
|
||||
public MethodParameterAwareSlicedResourcesAssembler(MethodParameter parameter,
|
||||
@Nullable HateoasPageableHandlerMethodArgumentResolver resolver, @Nullable UriComponents baseUri) {
|
||||
|
||||
super(resolver, baseUri);
|
||||
|
||||
Assert.notNull(parameter, "Method parameter must not be null");
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected MethodParameter getMethodParameter() {
|
||||
return parameter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.springframework.web.util.UriComponentsBuilder.fromUri;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.hateoas.*;
|
||||
import org.springframework.hateoas.SlicedModel.SliceMetadata;
|
||||
import org.springframework.hateoas.server.RepresentationModelAssembler;
|
||||
import org.springframework.hateoas.server.core.EmbeddedWrapper;
|
||||
import org.springframework.hateoas.server.core.EmbeddedWrappers;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
|
||||
import org.springframework.web.util.UriComponents;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
/**
|
||||
* {@link RepresentationModelAssembler} to easily convert {@link Slice} instances into
|
||||
* {@link SlicedModel}.
|
||||
*
|
||||
* @author Michael Schout
|
||||
*/
|
||||
public class SlicedResourcesAssembler<T>
|
||||
implements RepresentationModelAssembler<Slice<T>, SlicedModel<EntityModel<T>>> {
|
||||
|
||||
private final HateoasPageableHandlerMethodArgumentResolver pageableResolver;
|
||||
|
||||
private final Optional<UriComponents> baseUri;
|
||||
private final EmbeddedWrappers wrappers = new EmbeddedWrappers(false);
|
||||
|
||||
private boolean forceFirstRel = false;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SlicedResourcesAssembler} using the given
|
||||
* {@link PageableHandlerMethodArgumentResolver} and base URI. If the former is
|
||||
* {@literal null}, a default one will be created. If the latter is {@literal null}, calls
|
||||
* to {@link #toModel(Slice)} will use the current request's URI to build the relevant
|
||||
* previous and next links.
|
||||
*
|
||||
* @param resolver can be {@literal null}.
|
||||
* @param baseUri can be {@literal null}.
|
||||
*/
|
||||
public SlicedResourcesAssembler(@Nullable HateoasPageableHandlerMethodArgumentResolver resolver,
|
||||
@Nullable UriComponents baseUri) {
|
||||
this.pageableResolver = resolver == null ? new HateoasPageableHandlerMethodArgumentResolver() : resolver;
|
||||
this.baseUri = Optional.ofNullable(baseUri);
|
||||
}
|
||||
|
||||
private static String currentRequest() {
|
||||
return ServletUriComponentsBuilder.fromCurrentRequest().build().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether to always add {@code first} links to the {@link SlicedModel} *
|
||||
* created. Defaults to {@literal false} which means that {@code first} links onlys appear
|
||||
* in conjunction with {@code prev} and {@code next} links.
|
||||
*
|
||||
* @param forceFirstRel whether to always add {@code first} links to the
|
||||
* {@link SlicedModel} created.
|
||||
*/
|
||||
public void setForceFirstRel(boolean forceFirstRel) {
|
||||
this.forceFirstRel = forceFirstRel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SlicedModel<EntityModel<T>> toModel(Slice<T> entity) {
|
||||
return toModel(entity, EntityModel::of);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SlicedModel} by converting the given {@link Slice} into a
|
||||
* {@link SliceMetadata} instance and wrapping the contained elements into *
|
||||
* {@link SlicedModel} instances. Will add pagination links based on the given self link.
|
||||
*
|
||||
* @param slice must not be {@literal null}.
|
||||
* @param selfLink must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public SlicedModel<EntityModel<T>> toModel(Slice<T> slice, Link selfLink) {
|
||||
return toModel(slice, EntityModel::of, selfLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SlicedModel} by converting the given {@link Slice} into a
|
||||
* {@link SliceMetadata} instance and using the given {@link SlicedModel} to turn elements
|
||||
* of the {@link Slice} into resources.
|
||||
*
|
||||
* @param slice must not be {@literal null}.
|
||||
* @param assembler must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public <R extends RepresentationModel<?>> SlicedModel<R> toModel(Slice<T> slice,
|
||||
RepresentationModelAssembler<T, R> assembler) {
|
||||
return createModel(slice, assembler, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SlicedModel} by converting the given {@link Slice} into a
|
||||
* {@link SliceMetadata} instance and using the given {@link SlicedModel} to turn elements
|
||||
* of the {@link Slice} into resources. Will add pagination links based on the given the
|
||||
* self link.
|
||||
*
|
||||
* @param slice must not be {@literal null}.
|
||||
* @param assembler must not be {@literal null}.
|
||||
* @param link must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public <R extends RepresentationModel<?>> SlicedModel<R> toModel(Slice<T> slice,
|
||||
RepresentationModelAssembler<T, R> assembler, Link link) {
|
||||
return createModel(slice, assembler, Optional.of(link));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SlicedModel} with an empty collection {@link EmbeddedWrapper} for the
|
||||
* given domain type.
|
||||
*
|
||||
* @param slice must not be {@literal null}, content must be empty.
|
||||
* @param type must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public SlicedModel<?> toEmptyModel(Slice<?> slice, Class<?> type) {
|
||||
return toEmptyModel(slice, type, Optional.empty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SlicedModel} with an empty collection {@link EmbeddedWrapper} for the
|
||||
* given domain type.
|
||||
*
|
||||
* @param slice must not be {@literal null}, content must be empty.
|
||||
* @param type must not be {@literal null}.
|
||||
* @param link must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public SlicedModel<?> toEmptyModel(Slice<?> slice, Class<?> type, Link link) {
|
||||
return toEmptyModel(slice, type, Optional.of(link));
|
||||
}
|
||||
|
||||
public SlicedModel<?> toEmptyModel(Slice<?> slice, Class<?> type, Optional<Link> link) {
|
||||
Assert.notNull(slice, "Slice must not be null");
|
||||
Assert.isTrue(!slice.hasContent(), "Slice must not have any content");
|
||||
Assert.notNull(type, "Type must not be null");
|
||||
Assert.notNull(link, "Link must not be null");
|
||||
|
||||
SliceMetadata metadata = asSliceMetadata(slice);
|
||||
|
||||
EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(type);
|
||||
List<EmbeddedWrapper> embedded = Collections.singletonList(wrapper);
|
||||
|
||||
return addPaginationLinks(SlicedModel.of(embedded, metadata), slice, link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link SlicedModel} to be equipped with pagination links downstream.
|
||||
*
|
||||
* @param resources the original slices's elements mapped into {@link RepresentationModel}
|
||||
* instances.
|
||||
* @param metadata the calculated {@link SliceMetadata}, must not be {@literal null}.
|
||||
* @param slice the original page handed to the assembler, must not be {@literal null}.
|
||||
* @return must not be {@literal null}.
|
||||
*/
|
||||
protected <R extends RepresentationModel<?>, S> SlicedModel<R> createSlicedModel(List<R> resources,
|
||||
SliceMetadata metadata, Slice<S> slice) {
|
||||
Assert.notNull(resources, "Content resources must not be null");
|
||||
Assert.notNull(metadata, "SliceMetadata must not be null");
|
||||
Assert.notNull(slice, "Slice must not be null");
|
||||
|
||||
return SlicedModel.of(resources, metadata);
|
||||
}
|
||||
|
||||
private <S, R extends RepresentationModel<?>> SlicedModel<R> createModel(Slice<S> slice,
|
||||
RepresentationModelAssembler<S, R> assembler, Optional<Link> link) {
|
||||
Assert.notNull(slice, "Slice must not be null");
|
||||
Assert.notNull(assembler, "ResourceAssembler must not be null");
|
||||
|
||||
List<R> resources = new ArrayList<>(slice.getNumberOfElements());
|
||||
|
||||
for (S element : slice) {
|
||||
resources.add(assembler.toModel(element));
|
||||
}
|
||||
|
||||
SlicedModel<R> resource = createSlicedModel(resources, asSliceMetadata(slice), slice);
|
||||
|
||||
return addPaginationLinks(resource, slice, link);
|
||||
}
|
||||
|
||||
private <R> SlicedModel<R> addPaginationLinks(SlicedModel<R> resources, Slice<?> slice, Optional<Link> link) {
|
||||
UriTemplate base = getUriTemplate(link);
|
||||
|
||||
boolean isNavigable = slice.hasPrevious() || slice.hasNext();
|
||||
|
||||
if (isNavigable || forceFirstRel) {
|
||||
resources.add(
|
||||
createLink(base, PageRequest.of(0, slice.getSize(), slice.getSort()), IanaLinkRelations.FIRST));
|
||||
}
|
||||
|
||||
Link selfLink = link.map(Link::withSelfRel)
|
||||
.orElseGet(() -> createLink(base, slice.getPageable(), IanaLinkRelations.SELF));
|
||||
|
||||
resources.add(selfLink);
|
||||
|
||||
if (slice.hasPrevious()) {
|
||||
resources.add(createLink(base, slice.previousPageable(), IanaLinkRelations.PREV));
|
||||
}
|
||||
|
||||
if (slice.hasNext()) {
|
||||
resources.add(createLink(base, slice.nextPageable(), IanaLinkRelations.NEXT));
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a default URI string either from the one configured on then assembler or by
|
||||
* looking it up from the current request.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private UriTemplate getUriTemplate(Optional<Link> baseLink) {
|
||||
return UriTemplate.of(baseLink.map(Link::getHref).orElseGet(this::baseUriOrCurrentRequest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Link} with the given {@link LinkRelation} that will be based on the
|
||||
* given {@link UriTemplate} but enriched with the values of the given {@link Pageable}
|
||||
* (if not {@literal null}).
|
||||
*
|
||||
* @param base must not be {@literal null}.
|
||||
* @param pageable can be {@literal null}
|
||||
* @param relation must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private Link createLink(UriTemplate base, Pageable pageable, LinkRelation relation) {
|
||||
UriComponentsBuilder builder = fromUri(base.expand());
|
||||
pageableResolver.enhance(builder, getMethodParameter(), pageable);
|
||||
|
||||
return Link.of(UriTemplate.of(builder.build().toString()), relation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link MethodParameter} to be used to potentially qualify the paging and
|
||||
* sorting request parameters to. Default implementations returns {@literal null}, which
|
||||
* means the parameters will not be qualified.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
protected MethodParameter getMethodParameter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link SliceMetadata} instance from the given {@link Slice}.
|
||||
*
|
||||
* @param slice must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private SliceMetadata asSliceMetadata(Slice<?> slice) {
|
||||
Assert.notNull(slice, "Slice must not be null");
|
||||
|
||||
int number = pageableResolver.isOneIndexedParameters() ? slice.getNumber() + 1 : slice.getNumber();
|
||||
|
||||
return new SliceMetadata(slice.getSize(), number);
|
||||
}
|
||||
|
||||
private String baseUriOrCurrentRequest() {
|
||||
return baseUri.map(Object::toString).orElseGet(SlicedResourcesAssembler::currentRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright 2022 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
|
||||
*
|
||||
* https://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.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.log.LogMessage;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.hateoas.server.core.MethodParameters;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
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;
|
||||
|
||||
/**
|
||||
* {@link HandlerMethodArgumentResolver} to allow injection of {@link SlicedResourcesAssembler} into Spring MVC
|
||||
* controller methods.
|
||||
*
|
||||
* @author Michael Schout
|
||||
*/
|
||||
public class SlicedResourcesAssemblerArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
private static final Log logger = LogFactory.getLog(SlicedResourcesAssemblerArgumentResolver.class);
|
||||
|
||||
private static final String SUPERFLOUS_QUALIFIER = "Found qualified %s parameter, but a unique unqualified %s parameter; Using that one, but you might want to check your controller method configuration";
|
||||
private static final String PARAMETER_AMBIGUITY = "Discovered multiple parameters of type Pageable but no qualifier annotations to disambiguate";
|
||||
|
||||
private final HateoasPageableHandlerMethodArgumentResolver resolver;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SlicedResourcesAssemblerArgumentResolver} using the given
|
||||
* {@link PageableHandlerMethodArgumentResolver}.
|
||||
*
|
||||
* @param resolver can be {@literal null}.
|
||||
*/
|
||||
public SlicedResourcesAssemblerArgumentResolver(HateoasPageableHandlerMethodArgumentResolver resolver) {
|
||||
this.resolver = resolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns finds the {@link MethodParameter} for a {@link Pageable} instance matching the
|
||||
* given {@link MethodParameter} requesting a {@link SlicedResourcesAssembler}.
|
||||
*
|
||||
* @param parameter must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@Nullable
|
||||
private static MethodParameter findMatchingPageableParameter(MethodParameter parameter) {
|
||||
Method method = parameter.getMethod();
|
||||
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException(String.format("Could not obtain method from parameter %s", parameter));
|
||||
}
|
||||
|
||||
MethodParameters parameters = MethodParameters.of(method);
|
||||
List<MethodParameter> pageableParameters = parameters.getParametersOfType(Pageable.class);
|
||||
Qualifier assemblerQualifier = parameter.getParameterAnnotation(Qualifier.class);
|
||||
|
||||
if (pageableParameters.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pageableParameters.size() == 1) {
|
||||
MethodParameter pageableParameter = pageableParameters.get(0);
|
||||
MethodParameter matchingParameter = returnIfQualifiersMatch(pageableParameter, assemblerQualifier);
|
||||
|
||||
if (matchingParameter == null) {
|
||||
logger.info(LogMessage.format(SUPERFLOUS_QUALIFIER, SlicedResourcesAssembler.class.getSimpleName(),
|
||||
Pageable.class.getName()));
|
||||
}
|
||||
|
||||
return pageableParameter;
|
||||
}
|
||||
|
||||
if (assemblerQualifier == null) {
|
||||
throw new IllegalStateException(PARAMETER_AMBIGUITY);
|
||||
}
|
||||
|
||||
for (MethodParameter pageableParameter : pageableParameters) {
|
||||
MethodParameter matchingParameter = returnIfQualifiersMatch(pageableParameter, assemblerQualifier);
|
||||
|
||||
if (matchingParameter != null) {
|
||||
return matchingParameter;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException(PARAMETER_AMBIGUITY);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static MethodParameter returnIfQualifiersMatch(MethodParameter pageableParameter,
|
||||
@Nullable Qualifier assemblerQualifier) {
|
||||
|
||||
if (assemblerQualifier == null) {
|
||||
return pageableParameter;
|
||||
}
|
||||
|
||||
Qualifier pageableParameterQualifier = pageableParameter.getParameterAnnotation(Qualifier.class);
|
||||
|
||||
if (pageableParameterQualifier == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return pageableParameterQualifier.value().equals(assemblerQualifier.value()) ? pageableParameter : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return SlicedResourcesAssembler.class.equals(parameter.getParameterType());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {
|
||||
|
||||
MethodParameter pageableParameter = findMatchingPageableParameter(parameter);
|
||||
|
||||
if (pageableParameter != null) {
|
||||
return new MethodParameterAwareSlicedResourcesAssembler<>(pageableParameter, resolver, null);
|
||||
}
|
||||
else {
|
||||
return new SlicedResourcesAssembler<>(resolver, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,10 +28,13 @@ 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.data.web.SlicedResourcesAssembler;
|
||||
import org.springframework.data.web.SlicedResourcesAssemblerArgumentResolver;
|
||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
|
||||
/**
|
||||
* JavaConfig class to register {@link PagedResourcesAssembler} and {@link PagedResourcesAssemblerArgumentResolver}.
|
||||
* JavaConfig class to register {@link PagedResourcesAssembler}, {@link PagedResourcesAssemblerArgumentResolver},
|
||||
* {@link SlicedResourcesAssembler} and {@link SlicedResourcesAssemblerArgumentResolver}.
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Oliver Gierke
|
||||
@@ -47,6 +50,7 @@ public class HateoasAwareSpringDataWebConfiguration extends SpringDataWebConfigu
|
||||
private final Lazy<HateoasSortHandlerMethodArgumentResolver> sortResolver;
|
||||
private final Lazy<HateoasPageableHandlerMethodArgumentResolver> pageableResolver;
|
||||
private final Lazy<PagedResourcesAssemblerArgumentResolver> argumentResolver;
|
||||
private final Lazy<SlicedResourcesAssemblerArgumentResolver> slicedResourcesArgumentResolver;
|
||||
|
||||
/**
|
||||
* @param context must not be {@literal null}.
|
||||
@@ -63,6 +67,8 @@ public class HateoasAwareSpringDataWebConfiguration extends SpringDataWebConfigu
|
||||
.of(() -> context.getBean("pageableResolver", HateoasPageableHandlerMethodArgumentResolver.class));
|
||||
this.argumentResolver = Lazy.of(() -> context.getBean("pagedResourcesAssemblerArgumentResolver",
|
||||
PagedResourcesAssemblerArgumentResolver.class));
|
||||
this.slicedResourcesArgumentResolver = Lazy.of(() -> context.getBean("slicedResourcesAssemblerArgumentResolver",
|
||||
SlicedResourcesAssemblerArgumentResolver.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,11 +100,22 @@ public class HateoasAwareSpringDataWebConfiguration extends SpringDataWebConfigu
|
||||
return new PagedResourcesAssemblerArgumentResolver(pageableResolver.get());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SlicedResourcesAssembler<?> slicedResourcesAssembler() {
|
||||
return new SlicedResourcesAssembler<>(pageableResolver.get(), null);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SlicedResourcesAssemblerArgumentResolver slicedResourcesAssemblerArgumentResolver() {
|
||||
return new SlicedResourcesAssemblerArgumentResolver(pageableResolver.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
|
||||
super.addArgumentResolvers(argumentResolvers);
|
||||
|
||||
argumentResolvers.add(argumentResolver.get());
|
||||
argumentResolvers.add(slicedResourcesArgumentResolver.get());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user