org.springframework.web.servlet.mvc.method.annotation.PageResponseBodyAdvice Maven / Gradle / Ivy
package org.springframework.web.servlet.mvc.method.annotation;
import java.lang.reflect.Field;
import java.util.List;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.OffsetRequest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImplCustom;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Persistable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.querydsl.QSort;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.NumberUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.springframework.web.util.UriComponentsBuilder;
@ControllerAdvice
public class PageResponseBodyAdvice extends org.springframework.web.servlet.mvc.method.annotation.AbstractMappingJacksonResponseBodyAdvice {
/**
* @see ServletUriComponentsBuilder#fromCurrentRequest()
*/
@Override
protected void beforeBodyWriteInternal(MappingJacksonValue bodyContainer, MediaType contentType, MethodParameter returnType, ServerHttpRequest request, ServerHttpResponse response) {
Object value = bodyContainer.getValue();
if (value instanceof Page) {
Field field = ReflectionUtils.findField(value.getClass(), "pageable");
if (field != null) {
ReflectionUtils.makeAccessible(field);
Object pageable = ReflectionUtils.getField(field, value);
if (pageable instanceof Pageable) {
pageable = getPageable((Pageable) pageable);
value = getPage((Page) value, (Pageable) pageable, UriComponentsBuilder.fromHttpRequest(request));
if (pageable instanceof OffsetRequest) {
value = getPage((Page) value, (OffsetRequest) pageable, field);
}
bodyContainer.setValue(value);
}
}
}
}
private Page getPage(Page page, Pageable pageable, UriComponentsBuilder builder) {
if (page instanceof PageImplCustom) {
return page;
}
return new PageImplCustom<>(page.getContent(), pageable, page.getTotalElements(), builder);
}
private Pageable getPageable(Pageable pageable) {
Field field = ReflectionUtils.findField(pageable.getClass(), "sort");
if (field != null) {
ReflectionUtils.makeAccessible(field);
Object sort = ReflectionUtils.getField(field, pageable);
if (sort instanceof QSort) {
Sort value = null;
for (Order order : ((QSort) sort)) {
value = value == null ? new Sort(order) : value.and(new Sort(order));
}
ReflectionUtils.setField(field, pageable, value);
}
}
return pageable;
}
/**
*
* int first = (s = content.stream().reduce((start, end) -> start).orElse(null)) != null && s.getId() instanceof Number ? ((Number) s.getId()).intValue() : pageable.getFlag();
* int last = (s = content.stream().reduce((start, end) -> end).orElse(null)) != null && s.getId() instanceof Number ? ((Number) s.getId()).intValue() : pageable.getFlag();
*
*/
private Page getPage(Page page, OffsetRequest pageable, Field field) {
List content = page.getContent();
if (pageable.hasDirection() && ClassUtils.isAssignable(Persistable.class, CollectionUtils.findCommonElementType(content))) {
Persistable persistable;
boolean empty = CollectionUtils.isEmpty(content);
int first = !empty && (persistable = (Persistable) content.get(0)) != null && persistable.getId() instanceof Number
? NumberUtils.convertNumberToTargetClass((Number) persistable.getId(), Integer.class) : pageable.getId();
int last = !empty && (persistable = (Persistable) content.get(content.size() - 1)) != null && persistable.getId() instanceof Number
? NumberUtils.convertNumberToTargetClass((Number) persistable.getId(), Integer.class) : pageable.getId();
pageable.setFirst(first);
pageable.setLast(last);
pageable.setDirection(first < last ? Direction.ASC : Direction.DESC);
ReflectionUtils.setField(field, page, pageable);
}
return page;
}
}