DATACMNS-867 - Second draft.

This commit is contained in:
Oliver Gierke
2016-06-21 16:52:28 +02:00
parent 57ed50a730
commit d4811e29d9
222 changed files with 2297 additions and 2138 deletions

View File

@@ -77,7 +77,7 @@ public class HateoasPageableHandlerMethodArgumentResolver extends PageableHandle
String pagePropertyName = getParameterNameToUse(getPageParameterName(), parameter);
String sizePropertyName = getParameterNameToUse(getSizeParameterName(), parameter);
List<TemplateVariable> names = new ArrayList<TemplateVariable>();
List<TemplateVariable> names = new ArrayList<>();
MultiValueMap<String, String> queryParameters = template.getQueryParams();
boolean append = !queryParameters.isEmpty();

View File

@@ -185,14 +185,14 @@ class MapDataBinder extends WebDataBinder {
PropertyPath leafProperty = getPropertyPath(propertyName).getLeafProperty();
TypeInformation<?> owningType = leafProperty.getOwningType();
TypeInformation<?> propertyType = owningType.getProperty(leafProperty.getSegment());
TypeInformation<?> propertyType = leafProperty.getTypeInformation();
propertyType = propertyName.endsWith("]") ? propertyType.getActualType() : propertyType;
if (conversionRequired(value, propertyType.getType())) {
PropertyDescriptor descriptor = BeanUtils
.getPropertyDescriptor(owningType.getType(), leafProperty.getSegment());
PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(owningType.getType(),
leafProperty.getSegment());
MethodParameter methodParameter = new MethodParameter(descriptor.getReadMethod(), -1);
TypeDescriptor typeDescriptor = TypeDescriptor.nested(methodParameter, 0);
@@ -289,11 +289,11 @@ class MapDataBinder extends WebDataBinder {
Class<?> actualPropertyType = path.getType();
TypeDescriptor valueDescriptor = conversionService.canConvert(String.class, actualPropertyType) ? TypeDescriptor
.valueOf(String.class) : TypeDescriptor.valueOf(HashMap.class);
TypeDescriptor valueDescriptor = conversionService.canConvert(String.class, actualPropertyType)
? TypeDescriptor.valueOf(String.class) : TypeDescriptor.valueOf(HashMap.class);
return path.isCollection() ? TypeDescriptor.collection(emptyValue.getClass(), valueDescriptor) : TypeDescriptor
.map(emptyValue.getClass(), TypeDescriptor.valueOf(String.class), valueDescriptor);
return path.isCollection() ? TypeDescriptor.collection(emptyValue.getClass(), valueDescriptor)
: TypeDescriptor.map(emptyValue.getClass(), TypeDescriptor.valueOf(String.class), valueDescriptor);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.web;
import static org.springframework.data.web.SpringDataAnnotationUtils.*;
import java.lang.reflect.Method;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.MethodParameter;
@@ -50,9 +51,9 @@ public class PageableHandlerMethodArgumentResolver implements PageableArgumentRe
private static final String DEFAULT_PREFIX = "";
private static final String DEFAULT_QUALIFIER_DELIMITER = "_";
private static final int DEFAULT_MAX_PAGE_SIZE = 2000;
static final Pageable DEFAULT_PAGE_REQUEST = new PageRequest(0, 20);
static final Pageable DEFAULT_PAGE_REQUEST = PageRequest.of(0, 20);
private Pageable fallbackPageable = DEFAULT_PAGE_REQUEST;
private Optional<Pageable> fallbackPageable = Optional.of(DEFAULT_PAGE_REQUEST);
private SortArgumentResolver sortResolver;
private String pageParameterName = DEFAULT_PAGE_PARAMETER;
private String sizeParameterName = DEFAULT_SIZE_PARAMETER;
@@ -92,14 +93,17 @@ public class PageableHandlerMethodArgumentResolver implements PageableArgumentRe
* {@link PageableDefaults} (the latter only supported in legacy mode) can be found at the method parameter to be
* resolved.
* <p>
* If you set this to {@literal null}, be aware that you controller methods will get {@literal null} handed into them
* in case no {@link Pageable} data can be found in the request. Note, that doing so will require you supply bot the
* page <em>and</em> the size parameter with the requests as there will be no default for any of the parameters
* available.
* If you set this to {@literal Optional#empty()}, be aware that you controller methods will get {@literal null}
* handed into them in case no {@link Pageable} data can be found in the request. Note, that doing so will require you
* supply bot the page <em>and</em> the size parameter with the requests as there will be no default for any of the
* parameters available.
*
* @param fallbackPageable the {@link Pageable} to be used as general fallback.
*/
public void setFallbackPageable(Pageable fallbackPageable) {
public void setFallbackPageable(Optional<Pageable> fallbackPageable) {
Assert.notNull(fallbackPageable, "Fallback Pageable must not be null!");
this.fallbackPageable = fallbackPageable;
}
@@ -235,33 +239,32 @@ public class PageableHandlerMethodArgumentResolver implements PageableArgumentRe
assertPageableUniqueness(methodParameter);
Pageable defaultOrFallback = getDefaultFromAnnotationOrFallback(methodParameter);
Optional<Pageable> defaultOrFallback = getDefaultFromAnnotationOrFallback(methodParameter);
String pageString = webRequest.getParameter(getParameterNameToUse(pageParameterName, methodParameter));
String pageSizeString = webRequest.getParameter(getParameterNameToUse(sizeParameterName, methodParameter));
boolean pageAndSizeGiven = StringUtils.hasText(pageString) && StringUtils.hasText(pageSizeString);
Optional<Integer> page = parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, true);
Optional<Integer> pageSize = parseAndApplyBoundaries(pageSizeString, maxPageSize, false);
if (!pageAndSizeGiven && defaultOrFallback == null) {
if (!(page.isPresent() && pageSize.isPresent()) && !defaultOrFallback.isPresent()) {
return null;
}
int page = StringUtils.hasText(pageString) ? parseAndApplyBoundaries(pageString, Integer.MAX_VALUE, true)
: defaultOrFallback.getPageNumber();
int pageSize = StringUtils.hasText(pageSizeString) ? parseAndApplyBoundaries(pageSizeString, maxPageSize, false)
: defaultOrFallback.getPageSize();
int p = page.orElseGet(
() -> defaultOrFallback.map(it -> it.getPageNumber()).orElseThrow(() -> new IllegalStateException()));
int ps = pageSize
.orElseGet(() -> defaultOrFallback.map(it -> it.getPageSize()).orElseThrow(() -> new IllegalStateException()));
// Limit lower bound
pageSize = pageSize < 1 ? defaultOrFallback.getPageSize() : pageSize;
ps = ps < 1 ? defaultOrFallback.map(it -> it.getPageSize()).orElseThrow(() -> new IllegalStateException()) : ps;
// Limit upper bound
pageSize = pageSize > maxPageSize ? maxPageSize : pageSize;
ps = ps > maxPageSize ? maxPageSize : ps;
Sort sort = sortResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
// Default if necessary and default configured
sort = sort == null && defaultOrFallback != null ? defaultOrFallback.getSort() : sort;
return new PageRequest(page, pageSize, sort);
return PageRequest.of(p, ps,
sort.isSorted() ? sort : defaultOrFallback.map(it -> it.getSort()).orElseGet(() -> Sort.unsorted()));
}
/**
@@ -284,10 +287,10 @@ public class PageableHandlerMethodArgumentResolver implements PageableArgumentRe
return builder.append(source).toString();
}
private Pageable getDefaultFromAnnotationOrFallback(MethodParameter methodParameter) {
private Optional<Pageable> getDefaultFromAnnotationOrFallback(MethodParameter methodParameter) {
if (methodParameter.hasParameterAnnotation(PageableDefault.class)) {
return getDefaultPageRequestFrom(methodParameter);
return Optional.of(getDefaultPageRequestFrom(methodParameter));
}
return fallbackPageable;
@@ -306,10 +309,10 @@ public class PageableHandlerMethodArgumentResolver implements PageableArgumentRe
}
if (defaults.sort().length == 0) {
return new PageRequest(defaultPageNumber, defaultPageSize);
return PageRequest.of(defaultPageNumber, defaultPageSize);
}
return new PageRequest(defaultPageNumber, defaultPageSize, defaults.direction(), defaults.sort());
return PageRequest.of(defaultPageNumber, defaultPageSize, defaults.direction(), defaults.sort());
}
/**
@@ -321,13 +324,17 @@ public class PageableHandlerMethodArgumentResolver implements PageableArgumentRe
* @param shiftIndex whether to shift the index if {@link #oneIndexedParameters} is set to true.
* @return
*/
private int parseAndApplyBoundaries(String parameter, int upper, boolean shiftIndex) {
private Optional<Integer> parseAndApplyBoundaries(String parameter, int upper, boolean shiftIndex) {
if (!StringUtils.hasText(parameter)) {
return Optional.empty();
}
try {
int parsed = Integer.parseInt(parameter) - (oneIndexedParameters && shiftIndex ? 1 : 0);
return parsed < 0 ? 0 : parsed > upper ? upper : parsed;
return Optional.of(parsed < 0 ? 0 : parsed > upper ? upper : parsed);
} catch (NumberFormatException e) {
return 0;
return Optional.of(0);
}
}
}

View File

@@ -87,7 +87,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
*/
@Override
public PagedResources<Resource<T>> toResource(Page<T> entity) {
return toResource(entity, new SimplePagedResourceAssembler<T>());
return toResource(entity, new SimplePagedResourceAssembler<>());
}
/**
@@ -100,7 +100,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
* @return
*/
public PagedResources<Resource<T>> toResource(Page<T> page, Link selfLink) {
return toResource(page, new SimplePagedResourceAssembler<T>(), selfLink);
return toResource(page, new SimplePagedResourceAssembler<>(), selfLink);
}
/**
@@ -152,7 +152,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
EmbeddedWrapper wrapper = wrappers.emptyCollectionOf(type);
List<EmbeddedWrapper> embedded = Collections.singletonList(wrapper);
return addPaginationLinks(new PagedResources<EmbeddedWrapper>(embedded, metadata), page, link);
return addPaginationLinks(new PagedResources<>(embedded, metadata), page, link);
}
/**
@@ -185,7 +185,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
Assert.notNull(metadata, "PageMetadata must not be null!");
Assert.notNull(page, "Page must not be null!");
return new PagedResources<R>(resources, metadata);
return new PagedResources<>(resources, metadata);
}
private <S, R extends ResourceSupport> PagedResources<R> createResource(Page<S> page,
@@ -194,7 +194,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
Assert.notNull(page, "Page must not be null!");
Assert.notNull(assembler, "ResourceAssembler must not be null!");
List<R> resources = new ArrayList<R>(page.getNumberOfElements());
List<R> resources = new ArrayList<>(page.getNumberOfElements());
for (S element : page) {
resources.add(assembler.toResource(element));
@@ -212,7 +212,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
boolean isNavigable = page.hasPrevious() || page.hasNext();
if (isNavigable || forceFirstAndLastRels) {
resources.add(createLink(base, new PageRequest(0, page.getSize(), page.getSort()), Link.REL_FIRST));
resources.add(createLink(base, PageRequest.of(0, page.getSize(), page.getSort()), Link.REL_FIRST));
}
if (page.hasPrevious()) {
@@ -229,7 +229,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
int lastIndex = page.getTotalPages() == 0 ? 0 : page.getTotalPages() - 1;
resources.add(createLink(base, new PageRequest(lastIndex, page.getSize(), page.getSort()), Link.REL_LAST));
resources.add(createLink(base, PageRequest.of(lastIndex, page.getSize(), page.getSort()), Link.REL_LAST));
}
return resources;
@@ -293,7 +293,7 @@ public class PagedResourcesAssembler<T> implements ResourceAssembler<Page<T>, Pa
@Override
public Resource<T> toResource(T entity) {
return new Resource<T>(entity);
return new Resource<>(entity);
}
}
}

View File

@@ -86,9 +86,9 @@ public class PagedResourcesAssemblerArgumentResolver implements HandlerMethodArg
MethodParameter pageableParameter = findMatchingPageableParameter(parameter);
if (pageableParameter != null) {
return new MethodParameterAwarePagedResourcesAssembler<Object>(pageableParameter, resolver, fromUriString);
return new MethodParameterAwarePagedResourcesAssembler<>(pageableParameter, resolver, fromUriString);
} else {
return new PagedResourcesAssembler<Object>(resolver, fromUriString);
return new PagedResourcesAssembler<>(resolver, fromUriString);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.web;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.MethodParameter;
@@ -47,7 +48,7 @@ public class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
private static final String DEFAULT_PARAMETER = "sort";
private static final String DEFAULT_PROPERTY_DELIMITER = ",";
private static final String DEFAULT_QUALIFIER_DELIMITER = "_";
private static final Sort DEFAULT_SORT = null;
private static final Sort DEFAULT_SORT = Sort.unsorted();
private static final String SORT_DEFAULTS_NAME = SortDefaults.class.getSimpleName();
private static final String SORT_DEFAULT_NAME = SortDefault.class.getSimpleName();
@@ -143,14 +144,17 @@ public class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
}
if (annotatedDefault != null) {
return appendOrCreateSortTo(annotatedDefault, null);
return appendOrCreateSortTo(annotatedDefault, Sort.unsorted());
}
if (annotatedDefaults != null) {
Sort sort = null;
Sort sort = Sort.unsorted();
for (SortDefault currentAnnotatedDefault : annotatedDefaults.value()) {
sort = appendOrCreateSortTo(currentAnnotatedDefault, sort);
}
return sort;
}
@@ -170,11 +174,10 @@ public class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
String[] fields = SpringDataAnnotationUtils.getSpecificPropertyOrDefaultFromValue(sortDefault, "sort");
if (fields.length == 0) {
return null;
return Sort.unsorted();
}
Sort sort = new Sort(sortDefault.direction(), fields);
return sortOrNull == null ? sort : sortOrNull.and(sort);
return sortOrNull.and(new Sort(sortDefault.direction(), fields));
}
/**
@@ -214,25 +217,27 @@ public class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
}
String[] elements = part.split(delimiter);
Direction direction = elements.length == 0 ? null : Direction.fromStringOrNull(elements[elements.length - 1]);
for (int i = 0; i < elements.length; i++) {
Optional<Direction> direction = elements.length == 0 ? Optional.empty()
: Direction.fromOptionalString(elements[elements.length - 1]);
if (i == elements.length - 1 && direction != null) {
continue;
}
int lastIndex = direction.map(it -> elements.length - 1).orElseGet(() -> elements.length);
String property = elements[i];
if (!StringUtils.hasText(property)) {
continue;
}
allOrders.add(new Order(direction, property));
for (int i = 0; i < lastIndex; i++) {
toOrder(elements[i], direction).ifPresent(it -> allOrders.add(it));
}
}
return allOrders.isEmpty() ? null : new Sort(allOrders);
return allOrders.isEmpty() ? Sort.unsorted() : Sort.by(allOrders);
}
private static Optional<Order> toOrder(String property, Optional<Direction> direction) {
if (!StringUtils.hasText(property)) {
return Optional.empty();
}
return Optional.of(direction.map(it -> new Order(it, property)).orElseGet(() -> new Order(property)));
}
/**
@@ -244,7 +249,7 @@ public class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
*/
protected List<String> foldIntoExpressions(Sort sort) {
List<String> expressions = new ArrayList<String>();
List<String> expressions = new ArrayList<>();
ExpressionBuilder builder = null;
for (Order order : sort) {
@@ -274,7 +279,7 @@ public class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
*/
protected List<String> legacyFoldExpressions(Sort sort) {
List<String> expressions = new ArrayList<String>();
List<String> expressions = new ArrayList<>();
ExpressionBuilder builder = null;
for (Order order : sort) {
@@ -301,7 +306,7 @@ public class SortHandlerMethodArgumentResolver implements SortArgumentResolver {
*/
class ExpressionBuilder {
private final List<String> elements = new ArrayList<String>();
private final List<String> elements = new ArrayList<>();
private final Direction direction;
/**

View File

@@ -102,7 +102,7 @@ abstract class SpringDataAnnotationUtils {
*/
public static void assertQualifiersFor(Class<?>[] parameterTypes, Annotation[][] annotations) {
Set<String> values = new HashSet<String>();
Set<String> values = new HashSet<>();
for (int i = 0; i < annotations.length; i++) {

View File

@@ -116,7 +116,7 @@ public @interface EnableSpringDataWebSupport {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> imports = new ArrayList<String>();
List<String> imports = new ArrayList<>();
imports.add(HATEOAS_PRESENT ? HateoasAwareSpringDataWebConfiguration.class.getName()
: SpringDataWebConfiguration.class.getName());

View File

@@ -71,7 +71,7 @@ public class HateoasAwareSpringDataWebConfiguration extends SpringDataWebConfigu
@Bean
public PagedResourcesAssembler<?> pagedResourcesAssembler() {
return new PagedResourcesAssembler<Object>(pageableResolver(), null);
return new PagedResourcesAssembler<>(pageableResolver(), null);
}
@Bean

View File

@@ -95,7 +95,7 @@ public class SpringDataWebConfiguration extends WebMvcConfigurerAdapter {
FormattingConversionService conversionService = (FormattingConversionService) registry;
DomainClassConverter<FormattingConversionService> converter = new DomainClassConverter<FormattingConversionService>(
DomainClassConverter<FormattingConversionService> converter = new DomainClassConverter<>(
conversionService);
converter.setApplicationContext(context);
}

View File

@@ -61,7 +61,7 @@ public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentR
Optional<ConversionService> conversionService) {
this.bindingsFactory = factory;
this.predicateBuilder = new QuerydslPredicateBuilder(conversionService.orElse(new DefaultConversionService()),
this.predicateBuilder = new QuerydslPredicateBuilder(conversionService.orElseGet(DefaultConversionService::new),
factory.getEntityPathResolver());
}
@@ -104,7 +104,7 @@ public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentR
TypeInformation<?> domainType = extractTypeInfo(parameter).getActualType();
Optional<? extends Class<? extends QuerydslBinderCustomizer>> map = annotation
.<Class<? extends QuerydslBinderCustomizer>> map(it -> it.bindings());
.<Class<? extends QuerydslBinderCustomizer>>map(it -> it.bindings());
QuerydslBindings bindings = bindingsFactory.createBindingsFor(domainType,
(Optional<Class<? extends QuerydslBinderCustomizer<?>>>) map);
@@ -125,7 +125,7 @@ public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentR
.ofNullable(parameter.getParameterAnnotation(QuerydslPredicate.class));
return annotation.filter(it -> !Object.class.equals(it.root()))//
.<TypeInformation<?>> map(it -> ClassTypeInformation.from(it.root()))//
.<TypeInformation<?>>map(it -> ClassTypeInformation.from(it.root()))//
.orElseGet(() -> detectDomainType(ClassTypeInformation.fromReturnTypeOf(parameter.getMethod())));
}
@@ -145,6 +145,6 @@ public class QuerydslPredicateArgumentResolver implements HandlerMethodArgumentR
return source;
}
return detectDomainType(source.getComponentType());
return detectDomainType(source.getRequiredComponentType());
}
}