Our team upgraded from Hoxton.SR2 to Hoxton.SR7 and we started to have an issue with sorting.
When I look at the request coming from a feing call I see something like that
Hoxton.SR2 = /api/v1/driver/?statuses=Active&page=0&size=10&sort=driver_filename,ASC] Hoxton.SR7 = /api/v1/driver/?statuses=Active&page=0&size=10&sort=driver_filename&sort=ASC]
if you look you have 2 times the same request parameter. sort=driver_filename&sort=ASC.
Is something change in the config that I need to fix or its a bug on your side?
Thank you!
Comment From: jar3czek
It looks like the changes in OpenFeign core library is the cause: https://github.com/OpenFeign/feign/commit/a7b7c01806324126dd844a9a912e309754bc4dc9#diff-52499e1757ad7b3aeb1163f476846de3R190
Every non encoded query param value is splitted by comma to multiple values after this commit.
Comment From: OlgaMaciaszek
Yes, the issue is in Feign Core, however, please see this workaround. Let me know if it solves your issue.
Comment From: royremi
Ill try the work around and let you know,
Thank you All!
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.
Comment From: TokenJan
Hi all, I have also met this issue, the suggested workaround by @OlgaMaciaszek is useful in the single sort property situation, but not gonna work in multiple sort properties with directions.
For example: we have two sort properties createdAt and startDate with sort direction DESC. The query string by default looks like /api/v1/xxx/?sort=createdAt&sort=DESC&sort=startDate&sort=DESC, while it may look like /api/v1/xxx/?sort=createdAt,DESC,startDate,DESC when @CollectionFormat(feign.CollectionFormat.CSV) annotation is used. Apparently, neither of the query string is correct.
We found a workaround for this case. We reimplement the PageableSpringEncoder like this:
public class CustomizedPageableSpringEncoder implements Encoder {
private final Encoder delegate;
/**
* Page index parameter name.
*/
private static final String PAGE_PARAMETER = "page";
/**
* Page size parameter name.
*/
private static final String SIZE_PARAMETER = "size";
/**
* Sort parameter name.
*/
private static final String SORT_PARAMETER = "sort";
/**
* Creates a new PageableSpringEncoder with the given delegate for fallback. If no
* delegate is provided and this encoder cant handle the request, an EncodeException
* is thrown.
*
* @param delegate The optional delegate.
*/
public CustomizedPageableSpringEncoder(Encoder delegate) {
this.delegate = delegate;
}
@Override
public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
if (supports(object)) {
if (object instanceof Pageable) {
Pageable pageable = (Pageable) object;
if (pageable.isPaged()) {
template.query(PAGE_PARAMETER, pageable.getPageNumber() + "");
template.query(SIZE_PARAMETER, pageable.getPageSize() + "");
}
applySort(template, pageable.getSort());
} else if (object instanceof Sort) {
Sort sort = (Sort) object;
applySort(template, sort);
}
} else {
if (delegate != null) {
delegate.encode(object, bodyType, template);
} else {
throw new EncodeException(
"PageableSpringEncoder does not support the given object "
+ object.getClass()
+ " and no delegate was provided for fallback!");
}
}
}
private void applySort(RequestTemplate template, Sort sort) {
Collection<String> existingSorts = template.queries().get(SORT_PARAMETER);
List<String> sortQueries = existingSorts != null ? new ArrayList<>(existingSorts)
: new ArrayList<>();
for (Sort.Order order : sort) {
sortQueries.add(order.getProperty() + "%2C" + order.getDirection());
}
if (!sortQueries.isEmpty()) {
template.query(SORT_PARAMETER, sortQueries);
}
}
}
protected boolean supports(Object object) {
return object instanceof Pageable || object instanceof Sort;
}
}
The only difference is to separate the sort property and sort direction by %2C instead of , so that the sort pair would not be splitted. (see QueryTemplate.java in feign-core)
I'd like to ask if there is any concern for this workaround, or if there is any better solution for this case. Thanks in advance.