12

if use Page/Pageable in controller with rest, I got error,because they hasn't empty construct for deserialization

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of org.springframework.data.domain.Page, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
 at [Source: java.io.PushbackInputStream@67635da8; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148) ~[jackson-databind-2.6.4.jar:2.6.4]
at com.fasterxml.jackson.databind.DeserializationContext.instantiationException(DeserializationContext.java:892) ~[jackson-databind-2.6.4.jar:2.6.4]
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserialize(AbstractDeserializer.java:139) ~[jackson-databind-2.6.4.jar:2.6.4]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3736) ~[jackson-databind-2.6.4.jar:2.6.4]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2810) ~[jackson-databind-2.6.4.jar:2.6.4]
at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:221) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
... 30 common frames omitted
Dreampie
  • 1,321
  • 4
  • 17
  • 32
  • maybe this can help https://stackoverflow.com/questions/34099559/how-to-consume-pageentity-response-using-spring-resttemplate – Joand May 25 '22 at 13:46

2 Answers2

4

The Pageable implementation Page is not a pure POJO that Jackson expects. However, you can build you own implementation of Pageable. You'll be able to pass down that implementation of yours to Spring Data since it will respect the Pageable contract.

I had you problem and came around by implementing Pageable myself so my Java Rest Client could exchange with my Spring Data Jpa Server.

Daniel Lavoie
  • 1,852
  • 1
  • 16
  • 19
  • jpa has implementation of these,PageImpl and PageRequest,but no empty construct,so can't deserialization,and JpaRepository default return PageImpl how can change to custom implementation – Dreampie Jan 27 '16 at 02:26
  • You write your own implementation of Pageable interface. Spring Data works with interface, so you will be pass your custom RestPageRequest with the empty construct to JPA repository without problem as long as your custom class implements Pageable. – Daniel Lavoie Jan 27 '16 at 09:45
  • the code in this accepted answer https://stackoverflow.com/questions/34099559/how-to-consume-pageentity-response-using-spring-resttemplate – Joand May 25 '22 at 13:46
3

If you pass the parameters throught the HTTP Body, you need use a concrete implementation. The Daniel's solution is recommanded.

Another smart solution is using the HandlerMethodArgumentResolver

Step 1 - Creation of your argument handler similar to this

public class PageableHandler implements HandlerMethodArgumentResolver
{
    @Override
    public boolean supportsParameter(MethodParameter methodParameter)
    {
        return methodParameter.getParameterType().equals(Pageable.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception
    {
        String limit = nativeWebRequest.getParameter("limit");
        int size = toInt(limit, 100);

        String offset = nativeWebRequest.getParameter("offset");
        int page = (toInt(offset, size) / size);
        Sort sort = null;
        String sortStr = nativeWebRequest.getParameter("sort");
        String orderStr = nativeWebRequest.getParameter("order");
        if(sortStr != null && orderStr != null)
        {
            Direction direction = "asc".equalsIgnoreCase(orderStr) ? Direction.ASC : Direction.DESC;
            sort = new Sort(direction, sortStr);
        }        
        return new PageRequest(page, size, sort);
    }

    private int toInt(String value, int defaultValue)
    {
        int resultValue = defaultValue;
        if(value != null)
        {
            try
            {
                resultValue = Integer.parseInt(value);
            }catch(NumberFormatException e)
            {
            }
        }
        return resultValue;
    }

}

Step 2 - Register your handler on a Spring Configuration

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {


    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(new PageableHandler());
        super.addArgumentResolvers(argumentResolvers);
    }
}

Step 3 - Enjoy use on your controller

@RequestMapping(value = "/api/personne", method = RequestMethod.GET)
public List<Personne> getAllPersonnes(Pageable pageable) {
    return adminService.getAllPersonnes(pageable);
}

Step 4 - Example of REST GET

http://localhost:8080/api/personne?offset=2&limit=25
Bruno Régnier
  • 361
  • 3
  • 4