Polishing.

Allow nullable OffsetScrollPosition and add support for values wrapped within Optional.

Update tests. Reformat code. Add issue tags to tests.

See #2856
Original pull request: #2861
This commit is contained in:
Mark Paluch
2023-07-04 15:44:54 +02:00
parent 391607bd14
commit 80b8e12641
6 changed files with 220 additions and 147 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2023 the original author or authors.
* Copyright 2023 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.
@@ -17,7 +17,6 @@ package org.springframework.data.web;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
@@ -27,27 +26,31 @@ import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Argument resolver to extract a {@link OffsetScrollPosition} object from a {@link NativeWebRequest} for a particular
* {@link MethodParameter}. A {@link OffsetScrollPositionArgumentResolver} can either resolve {@link OffsetScrollPosition} itself or wrap another
* {@link OffsetScrollPositionArgumentResolver} to post-process {@link OffsetScrollPosition}.
* {@link MethodParameter}. A {@link OffsetScrollPositionArgumentResolver} can either resolve
* {@link OffsetScrollPosition} itself or wrap another {@link OffsetScrollPositionArgumentResolver} to post-process
* {@link OffsetScrollPosition}.
*
* @since 3.2
* @author Yanming Zhou
* @see HandlerMethodArgumentResolver
* @author Mark Paluch
* @since 3.2
* @see org.springframework.web.method.support.HandlerMethodArgumentResolver
*/
public interface OffsetScrollPositionArgumentResolver extends HandlerMethodArgumentResolver {
/**
* Resolves a {@link OffsetScrollPosition} method parameter into an argument value from a given request.
* Resolves a {@link OffsetScrollPosition} method parameter into an argument value from a given request. Supports also
* wrapped arguments in {@link java.util.Optional}.
*
* @param parameter the method parameter to resolve. This parameter must have previously been passed to
* {@link #supportsParameter} which must have returned {@code true}.
* @param mavContainer the ModelAndViewContainer for the current request
* @param webRequest the current request
* @param binderFactory a factory for creating {@link WebDataBinder} instances
* @return the resolved argument value
* @return the resolved argument value or {@literal null} if the value cannot be resolved. The returned value
* considers {@link MethodParameter#isOptional() Optional} wrapping by returing either the value wrapped
* within Optional or Optional.empty().
*/
@NonNull
@Override
OffsetScrollPosition resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2013-2023 the original author or authors.
* Copyright 2023 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.
@@ -15,6 +15,8 @@
*/
package org.springframework.data.web;
import java.util.Arrays;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.lang.Nullable;
@@ -23,27 +25,28 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import java.util.Arrays;
/**
* {@link HandlerMethodArgumentResolver} to automatically create {@link OffsetScrollPosition} instances from request parameters.
* {@link HandlerMethodArgumentResolver} to automatically create {@link OffsetScrollPosition} instances from request
* parameters.
*
* @since 3.2
* @author Yanming Zhou
* @since 3.2
*/
public class OffsetScrollPositionHandlerMethodArgumentResolver extends OffsetScrollPositionHandlerMethodArgumentResolverSupport
implements OffsetScrollPositionArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return OffsetScrollPosition.class.equals(parameter.getParameterType());
return OffsetScrollPosition.class.equals(parameter.nestedIfOptional().getNestedParameterType());
}
@Override
public OffsetScrollPosition resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {
String[] offsetParameter = webRequest.getParameterValues(getOffsetParameter(parameter));
return parseParameterIntoOffsetScrollPosition(offsetParameter != null ? Arrays.asList(offsetParameter) : null);
String[] offsetParameter = webRequest.getParameterValues(getOffsetParameter(parameter.nestedIfOptional()));
return adaptArgumentIfNecessary(
parseParameterIntoOffsetScrollPosition(offsetParameter != null ? Arrays.asList(offsetParameter) : null),
parameter);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 the original author or authors.
* Copyright 2023 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.
@@ -15,22 +15,23 @@
*/
package org.springframework.data.web;
import java.util.List;
import java.util.Optional;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.data.domain.ScrollPosition;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Objects;
/**
* Base class providing methods for handler method argument resolvers to create {@link OffsetScrollPosition} instances from request
* parameters.
* Base class providing methods for handler method argument resolvers to create {@link OffsetScrollPosition} instances
* from request parameters.
*
* @since 3.2
* @author Yanming Zhou
* @since 3.2
* @see OffsetScrollPositionHandlerMethodArgumentResolver
* @see ReactiveOffsetScrollPositionHandlerMethodArgumentResolver
*/
@@ -71,7 +72,7 @@ public abstract class OffsetScrollPositionHandlerMethodArgumentResolverSupport {
* @param parameter can be {@literal null}.
* @return the offset parameter
*/
protected String getOffsetParameter(@Nullable MethodParameter parameter) {
protected String getOffsetParameter(MethodParameter parameter) {
StringBuilder builder = new StringBuilder();
@@ -89,19 +90,39 @@ public abstract class OffsetScrollPositionHandlerMethodArgumentResolverSupport {
* Parses the given source into a {@link OffsetScrollPosition} instance.
*
* @param source could be {@literal null} or empty.
* @return parsed OffsetScrollPosition
* @return parsed OffsetScrollPosition or {@literal null} if it cannot be constructed.
*/
@Nullable
OffsetScrollPosition parseParameterIntoOffsetScrollPosition(@Nullable List<String> source) {
// No parameter or Single empty parameter, e.g "offset="
if (source == null || source.size() == 1 && !StringUtils.hasText(source.get(0))) {
return ScrollPosition.offset();
if (CollectionUtils.isEmpty(source) || (source.size() == 1 && !StringUtils.hasText(source.get(0)))) {
return null;
}
try {
long offset = Long.parseLong(source.get(0));
return ScrollPosition.offset(offset);
} catch (NumberFormatException ex) {
return ScrollPosition.offset();
return null;
}
}
/**
* Adapt the given argument against the method parameter, if necessary.
*
* @param arg the resolved argument.
* @param parameter the method parameter descriptor.
* @return the adapted argument, or the original resolved argument as-is.
*/
@Nullable
Object adaptArgumentIfNecessary(@Nullable Object arg, MethodParameter parameter) {
if (parameter.getParameterType() == Optional.class) {
return arg == null ? Optional.empty() : Optional.of(arg);
}
return arg;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2017-2023 the original author or authors.
* Copyright 2023 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.
@@ -15,37 +15,36 @@
*/
package org.springframework.data.web;
import java.util.List;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.OffsetScrollPosition;
import org.springframework.lang.NonNull;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.server.ServerWebExchange;
import java.util.List;
/**
* Reactive {@link HandlerMethodArgumentResolver} to create {@link OffsetScrollPosition} instances from query string parameters.
* Reactive {@link HandlerMethodArgumentResolver} to create {@link OffsetScrollPosition} instances from query string
* parameters.
*
* @since 3.2
* @author Yanming Zhou
* @since 3.2
*/
public class ReactiveOffsetScrollPositionHandlerMethodArgumentResolver extends OffsetScrollPositionHandlerMethodArgumentResolverSupport
implements SyncHandlerMethodArgumentResolver {
public class ReactiveOffsetScrollPositionHandlerMethodArgumentResolver
extends OffsetScrollPositionHandlerMethodArgumentResolverSupport implements SyncHandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return OffsetScrollPosition.class.equals(parameter.getParameterType());
return OffsetScrollPosition.class.equals(parameter.nestedIfOptional().getNestedParameterType());
}
@NonNull
@Override
public OffsetScrollPosition resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext,
public Object resolveArgumentValue(MethodParameter parameter, BindingContext bindingContext,
ServerWebExchange exchange) {
List<String> offsetParameter = exchange.getRequest().getQueryParams().get(getOffsetParameter(parameter));
return parseParameterIntoOffsetScrollPosition(offsetParameter);
return adaptArgumentIfNecessary(parseParameterIntoOffsetScrollPosition(offsetParameter), parameter);
}
}