Support Spring Data Pageable in Feign Client

See original GitHub issue

I am using Feign for requesting a MicroService who support Spring Data Pageable functionnality.

This is my FeignClient Interface :

 @FeignClient(FeignServiceId.SERVICE_ID)
 @RequestMapping(value = "api/document")
 public interface DocumentApi {

    @RequestMapping(method = RequestMethod.GET, value = "user/{userLogin}")
    Page<DeclarationDT> getDeclarationsByUserLogin(@PathVariable("userLogin") String userLogin, Pageable pageable);

}

When i make a call to the getDeclarationsByUserLogin, Feign do a POST request whereas i specify RequestMethod.GET.

I think this is due to the fact that Feign not support the Spring Data Pageable functionnality.

Is it possible to implement support for this feature ?

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:18
  • Comments:32 (11 by maintainers)

github_iconTop GitHub Comments

48reactions
IsNullcommented, Oct 17, 2016

This bugged me as well, and I wanted to use the same method signature on the client (feign) as on the server side, i.e. Page<T> and Pageable in the feign interface.

I’ve come up with the following solution:

Pageable support in Feign

/**
     * This encoder adds support for pageable, which will be applied to the query parameters.
     */
    private class PageableQueryEncoder implements Encoder {

        private final Encoder delegate;

        PageableQueryEncoder(Encoder delegate){
            this.delegate = delegate;
        }

        @Override
        public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {

            if(object instanceof Pageable){
                Pageable pageable = (Pageable)object;
                template.query("page", pageable.getPageNumber() + "");
                template.query("size", pageable.getPageSize() + "");

                if(pageable.getSort() != null) {
                    Collection<String> existingSorts = template.queries().get("sort");
                    List<String> sortQueries  = existingSorts != null ? new ArrayList<>(existingSorts) : new ArrayList<>();
                    for (Sort.Order order : pageable.getSort()) {
                        sortQueries.add(order.getProperty() + "," + order.getDirection());
                    }
                    template.query("sort", sortQueries);
                }

            }else{
                delegate.encode(object, bodyType, template);
            }
        }
    }

This encoder can be added to your current encoder by composition:

Sample configuration

@Configuration
@EnableFeignClients
public class FeignClientConfig {

    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    @Bean
    public Encoder feignEncoder() {
        return new PageableQueryEncoder(new SpringEncoder(messageConverters));
    }
}

Page<T> support

This is a simple Jackson mapper issue, so it can be solved by adding a mixin for Page<T>

Register (.mixIn(Page.class, PageMixIn.class)) the MixIn

    @JsonDeserialize(as = SimplePageImpl.class)
    private interface PageMixIn{ }
public class SimplePageImpl<T> implements Page<T> {

    private final Page<T> delegate;

    public SimplePageImpl(
            @JsonProperty("content") List<T> content,
            @JsonProperty("page")int number,
            @JsonProperty("size") int size,
            @JsonProperty("totalElements") long totalElements){
        delegate = new PageImpl<>(content, new PageRequest(number, size), totalElements);
    }


    @JsonProperty
    @Override
    public int getTotalPages() {
        return delegate.getTotalPages();
    }

    @JsonProperty
    @Override
    public long getTotalElements() {
        return delegate.getTotalElements();
    }

    @JsonProperty("page")
    @Override
    public int getNumber() {
        return delegate.getNumber();
    }

    @JsonProperty
    @Override
    public int getSize() {
        return delegate.getSize();
    }

    @JsonProperty
    @Override
    public int getNumberOfElements() {
        return delegate.getNumberOfElements();
    }

    @JsonProperty
    @Override
    public List<T> getContent() {
        return delegate.getContent();
    }

    @JsonProperty
    @Override
    public boolean hasContent() {
        return delegate.hasContent();
    }

    @JsonIgnore
    @Override
    public Sort getSort() {
        return delegate.getSort();
    }

    @JsonProperty
    @Override
    public boolean isFirst() {
        return delegate.isFirst();
    }

    @JsonProperty
    @Override
    public boolean isLast() {
        return delegate.isLast();
    }

    @JsonIgnore
    @Override
    public boolean hasNext() {
        return delegate.hasNext();
    }

    @JsonIgnore
    @Override
    public boolean hasPrevious() {
        return delegate.hasPrevious();
    }

    @JsonIgnore
    @Override
    public Pageable nextPageable() {
        return delegate.nextPageable();
    }
    @JsonIgnore
    @Override
    public Pageable previousPageable() {
        return delegate.previousPageable();
    }
    @JsonIgnore
    @Override
    public <S> Page<S> map(Converter<? super T, ? extends S> converter) {
        return delegate.map(converter);
    }

    @JsonIgnore
    @Override
    public Iterator<T> iterator() {
        return delegate.iterator();
    }

Maybe that helps someone 😃

8reactions
tjuchniewiczcommented, Oct 24, 2016

Works for me. Thanks a lot @IsNull !

Pageable must be annotated with @RequestBody. Looks like Feign Encoder is only applied for body parameters.

My Jackson configuration for Spring Boot:

public class MyJacksonModule extends SimpleModule {

    @Override
    public void setupModule(SetupContext context) {
        context.setMixInAnnotations(Page.class, PageMixIn.class);
    }
}

@Configuration
public class MyJacksonConfiguration {

    @Bean
    public Module myJacksonModule() {
        return new MyJacksonModule();
    }
}
Read more comments on GitHub >

github_iconTop Results From Across the Web

Spring Data Pageable not supported as RequestParam in ...
I think your code doesn't work because you are using @RequestParam annotation for Pageable parameter in your Feign method.
Read more >
How to use pagination in Spring Boot — OpenFeign - Medium
Lets create simple page custom object to get page data source above. and also need to create custom config for Feign Interface that...
Read more >
FeignClient: How to use Pageable? #2672 - GitHub
I am build a MicroService who support Spring Data Pageable functionnality. like this: @PostMapping("search") @OverRide public Result<Page> ...
Read more >
Spring Cloud OpenFeign
Spring Data Support ; 1.21. ... This project provides OpenFeign integrations for Spring Boot apps through ... Feign is a declarative web service...
Read more >
how to pass Spring Pageable to FeignClient-Spring MVC
How am I supposed to pass an unpaged but sorted Pageable to a Spring JPA repository? How to pass List<String> in post method...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found