Refine @PageableDefault and @SortDefault annotations.
We now use MergedAnnotations to evaluate annotation attributes and to use aliasing across attributes. Also, SortDefault is not repeatable. Closes #2657
This commit is contained in:
@@ -21,6 +21,7 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.web.SortDefault.SortDefaults;
|
||||
|
||||
@@ -31,6 +32,7 @@ import org.springframework.data.web.SortDefault.SortDefaults;
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -43,22 +45,24 @@ public @interface PageableDefault {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@AliasFor("size")
|
||||
int value() default 10;
|
||||
|
||||
/**
|
||||
* The default-size the injected {@link org.springframework.data.domain.Pageable} should get if no corresponding
|
||||
* parameter defined in request (default is 10).
|
||||
* parameter defined in request (default is {@code 10}).
|
||||
*/
|
||||
@AliasFor("value")
|
||||
int size() default 10;
|
||||
|
||||
/**
|
||||
* The default-pagenumber the injected {@link org.springframework.data.domain.Pageable} should get if no corresponding
|
||||
* parameter defined in request (default is 0).
|
||||
* The default page number the injected {@link org.springframework.data.domain.Pageable} should use if no
|
||||
* corresponding parameter defined in request (default is {@code 0}).
|
||||
*/
|
||||
int page() default 0;
|
||||
|
||||
/**
|
||||
* The properties to sort by by default. If unset, no sorting will be applied at all.
|
||||
* The properties to sort by default. If unset, no sorting will be applied at all.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
@@ -238,30 +240,34 @@ public abstract class PageableHandlerMethodArgumentResolverSupport {
|
||||
|
||||
private Pageable getDefaultFromAnnotationOrFallback(MethodParameter methodParameter) {
|
||||
|
||||
PageableDefault defaults = methodParameter.getParameterAnnotation(PageableDefault.class);
|
||||
MergedAnnotation<PageableDefault> defaults = MergedAnnotations.from(methodParameter.getParameterAnnotations())
|
||||
.get(PageableDefault.class);
|
||||
|
||||
if (defaults != null) {
|
||||
if (defaults.isPresent()) {
|
||||
return getDefaultPageRequestFrom(methodParameter, defaults);
|
||||
}
|
||||
|
||||
return fallbackPageable;
|
||||
}
|
||||
|
||||
private static Pageable getDefaultPageRequestFrom(MethodParameter parameter, PageableDefault defaults) {
|
||||
private static Pageable getDefaultPageRequestFrom(MethodParameter parameter,
|
||||
MergedAnnotation<PageableDefault> defaults) {
|
||||
|
||||
int defaultPageNumber = defaults.page();
|
||||
Integer defaultPageSize = getSpecificPropertyOrDefaultFromValue(defaults, "size");
|
||||
int defaultPageNumber = defaults.getInt("page");
|
||||
int defaultPageSize = defaults.getInt("size");
|
||||
|
||||
if (defaultPageSize < 1) {
|
||||
Method annotatedMethod = parameter.getMethod();
|
||||
throw new IllegalStateException(String.format(INVALID_DEFAULT_PAGE_SIZE, annotatedMethod));
|
||||
}
|
||||
|
||||
if (defaults.sort().length == 0) {
|
||||
String[] sort = defaults.getStringArray("sort");
|
||||
if (sort.length == 0) {
|
||||
return PageRequest.of(defaultPageNumber, defaultPageSize);
|
||||
}
|
||||
|
||||
return PageRequest.of(defaultPageNumber, defaultPageSize, defaults.direction(), defaults.sort());
|
||||
return PageRequest.of(defaultPageNumber, defaultPageSize, defaults.getEnum("direction", Sort.Direction.class),
|
||||
sort);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -287,5 +293,4 @@ public abstract class PageableHandlerMethodArgumentResolverSupport {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@ package org.springframework.data.web;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
|
||||
@@ -30,10 +32,12 @@ import org.springframework.data.domain.Sort.Direction;
|
||||
*
|
||||
* @since 1.6
|
||||
* @author Oliver Gierke
|
||||
* @author Mark Palich
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Repeatable(SortDefault.SortDefaults.class)
|
||||
public @interface SortDefault {
|
||||
|
||||
/**
|
||||
@@ -41,13 +45,15 @@ public @interface SortDefault {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@AliasFor("sort")
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* The properties to sort by by default. If unset, no sorting will be applied at all.
|
||||
* The properties to sort by default. If unset, no sorting will be applied at all.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@AliasFor("value")
|
||||
String[] sort() default {};
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,6 +23,9 @@ import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.annotation.RepeatableContainers;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
import org.springframework.data.domain.Sort.Order;
|
||||
@@ -121,31 +124,26 @@ public abstract class SortHandlerMethodArgumentResolverSupport {
|
||||
*/
|
||||
protected Sort getDefaultFromAnnotationOrFallback(MethodParameter parameter) {
|
||||
|
||||
SortDefaults annotatedDefaults = parameter.getParameterAnnotation(SortDefaults.class);
|
||||
SortDefault annotatedDefault = parameter.getParameterAnnotation(SortDefault.class);
|
||||
MergedAnnotations mergedAnnotations = MergedAnnotations.from(parameter, parameter.getParameterAnnotations(),
|
||||
RepeatableContainers.of(SortDefault.class, SortDefaults.class));
|
||||
|
||||
if (annotatedDefault != null && annotatedDefaults != null) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Cannot use both @%s and @%s on parameter %s; Move %s into %s to define sorting order",
|
||||
SORT_DEFAULTS_NAME, SORT_DEFAULT_NAME, parameter.toString(), SORT_DEFAULT_NAME, SORT_DEFAULTS_NAME));
|
||||
List<MergedAnnotation<SortDefault>> annotations = mergedAnnotations.stream(SortDefault.class).toList();
|
||||
|
||||
if (annotations.isEmpty()) {
|
||||
return fallbackSort;
|
||||
}
|
||||
|
||||
if (annotatedDefault != null) {
|
||||
return appendOrCreateSortTo(annotatedDefault, Sort.unsorted());
|
||||
if (annotations.size() == 1) {
|
||||
return appendOrCreateSortTo(annotations.get(0), Sort.unsorted());
|
||||
}
|
||||
|
||||
if (annotatedDefaults != null) {
|
||||
Sort sort = Sort.unsorted();
|
||||
|
||||
Sort sort = Sort.unsorted();
|
||||
|
||||
for (SortDefault currentAnnotatedDefault : annotatedDefaults.value()) {
|
||||
sort = appendOrCreateSortTo(currentAnnotatedDefault, sort);
|
||||
}
|
||||
|
||||
return sort;
|
||||
for (MergedAnnotation<SortDefault> currentAnnotatedDefault : annotations) {
|
||||
sort = appendOrCreateSortTo(currentAnnotatedDefault, sort);
|
||||
}
|
||||
|
||||
return fallbackSort;
|
||||
return sort;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,9 +154,9 @@ public abstract class SortHandlerMethodArgumentResolverSupport {
|
||||
* @param sortOrNull
|
||||
* @return
|
||||
*/
|
||||
private Sort appendOrCreateSortTo(SortDefault sortDefault, Sort sortOrNull) {
|
||||
private Sort appendOrCreateSortTo(MergedAnnotation<SortDefault> sortDefault, Sort sortOrNull) {
|
||||
|
||||
String[] fields = SpringDataAnnotationUtils.getSpecificPropertyOrDefaultFromValue(sortDefault, "sort");
|
||||
String[] fields = sortDefault.getStringArray("sort");
|
||||
|
||||
if (fields.length == 0) {
|
||||
return Sort.unsorted();
|
||||
@@ -167,8 +165,8 @@ public abstract class SortHandlerMethodArgumentResolverSupport {
|
||||
List<Order> orders = new ArrayList<>(fields.length);
|
||||
for (String field : fields) {
|
||||
|
||||
Order order = new Order(sortDefault.direction(), field);
|
||||
orders.add(sortDefault.caseSensitive() ? order : order.ignoreCase());
|
||||
Order order = new Order(sortDefault.getEnum("direction", Sort.Direction.class), field);
|
||||
orders.add(sortDefault.getBoolean("caseSensitive") ? order : order.ignoreCase());
|
||||
}
|
||||
|
||||
return sortOrNull.and(Sort.by(orders));
|
||||
|
||||
@@ -91,8 +91,10 @@ abstract class SpringDataAnnotationUtils {
|
||||
* @param annotation must not be {@literal null}.
|
||||
* @param property must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @deprecated since 3.0 as this method is no longer used within the Framework.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Deprecated
|
||||
public static <T> T getSpecificPropertyOrDefaultFromValue(Annotation annotation, String property) {
|
||||
|
||||
Object propertyDefaultValue = AnnotationUtils.getDefaultValue(annotation, property);
|
||||
|
||||
Reference in New Issue
Block a user