quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.85k stars 2.7k forks source link

Spring Data JPA's Pageable and @PageableDefault are not supported as Controller method types #4041

Open hantsy opened 5 years ago

hantsy commented 5 years ago

Quarkus 0.22.0

Both Page result, Pageable params are not worked as expected.

https://github.com/hantsy/quarkus-sample/tree/master/spring-post-service

    @GetMapping()
    public ResponseEntity getAllPosts(
            @RequestParam(value = "q", required = false) String keyword,
            @RequestParam(value = "page", required = false, defaultValue = "0") int page,
            @RequestParam(value = "size", required = false, defaultValue = "10") int size
            /** //
             @PageableDefault(page = 0, size = 10, sort = "createdDate", direction = Direction.DESC) Pageable page*/) {

        //Page<Post> posts = this.postRepository.findAll(PageRequest.of(page, size));

        List<Post> posts = this.postRepository.findAll();

        return ok(posts);
    }
geoand commented 5 years ago

I'm not really sure what the issue is here, but Page and Pageable should be working as expected. See this.

Can you give some details of what exactly you think does not work correctly?

hantsy commented 5 years ago

In my sample, I tried to use @PageableDefault(page = 0, size = 10, sort = "createdDate", direction = Direction.DESC) Pageable page in request params, and return a Page object, both did not work.

Please tried my sample, and reset the commented codes.

I have used these in before Spring projects for years.

geoand commented 5 years ago

I'll try this soon, however I'll need a couple more things for you please:

Thanks

hantsy commented 5 years ago

Use my docker-compose file to serve a running Postgresql.

docker-compose up blogdb

I used a bean AppInitializer to init data.

geoand commented 5 years ago

So basically what you example uses is the PageableDefault correct? That we definitely don't support (yet).

I would suggest to refactor to use vanilla Page and Sort like in the examples I showed. Also returning Page seems kind of fishy to me to be honest. Is it something you seen often? I personally haven't encountered it in code

hantsy commented 5 years ago

In Spring Data,

  1. for request, PageRequest is an impl of Pageable.
  2. for response PageImpl implementsPage.

In method params, @PageableDefault(page = 0, size = 10, sort = "createdDate", direction = Direction.DESC) Pageable page) did not work. In the method, Page<Post> posts = this.postRepository.findAll(PageRequest.of(page, size)); did not work.

Check the original codes :https://github.com/hantsy/spring-microservice-sample/blob/master/post-service/src/main/java/com/hantsylabs/sample/springmicroservice/post/PostController.java#L45-L55

My example is copied from my Spring samples, it am sure the codes worked well.

geoand commented 5 years ago

I'll try it again and see what happens.

As a request from our side for future issue reporting, I would like to ask you to make it dead easy for people to reproduce your issues. Please remove any ambiguity and reduce extra steps to an absolute minimum.

Thanks

geoand commented 5 years ago

@hantsy Can you please explain what exactly you see is not working in this.postRepository.findAll(PageRequest.of(page, size))?

I tried it again and it worked as expected.

As I said @PageableDefault is not implemented yet, but we could perhaps fix that in the future.

hantsy commented 5 years ago

The exception is thrown when I ran mvn clean package quarkus:dev. The test failed. When I changed it to List<Post> posts = this.postRepository.findAll();, it works.

2019-09-17 14:32:53,204 INFO  [io.quarkus] (main) Quarkus 0.22.0 started in 2.919s. Listening on: http://[::]:8081
2019-09-17 14:32:53,205 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, jdbc-postgresql, narayana-jta, resteasy, spring-data-jpa, spring
-di, spring-web]
Hibernate:
    select
        post0_.id as id1_0_,
        post0_.content as content2_0_,
        post0_.createdAt as createdA3_0_,
        post0_.title as title4_0_
    from
        Post post0_ limit ?
Hibernate:
    select
        count(*) as col_0_0_
    from
        Post post0_
2019-09-17 14:32:54,786 SEVERE [org.ecl.yas.int.Marshaller] (executor-thread-1) Error getting value on: Page 1 of 1 containing com.example.Post instances
2019-09-17 14:32:54,792 SEVERE [org.ecl.yas.int.Marshaller] (executor-thread-1) Generating incomplete JSON
2019-09-17 14:32:54,801 ERROR [io.und.req.io] (executor-thread-1) Exception handling request 7c4cbcb1-c12b-4caa-87ff-c77c0901a931-1 to /posts: org.jboss.resteasy.s
pi.UnhandledException: javax.ws.rs.ProcessingException: RESTEASY008205: JSON Binding serialization error javax.json.bind.JsonbException: Error getting value on: Pa
ge 1 of 1 containing com.example.Post instances
        at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:381)
        at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:209)
        at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:587)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:508)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:252)
        at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:153)
        at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:363)
        at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:156)
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:238)
        at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249)
        at io.quarkus.resteasy.runtime.ResteasyFilter$ResteasyResponseWrapper.sendError(ResteasyFilter.java:64)
        at io.undertow.servlet.handlers.DefaultServlet.doGet(DefaultServlet.java:175)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:686)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:791)
        at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
        at io.quarkus.resteasy.runtime.ResteasyFilter.doFilter(ResteasyFilter.java:28)
        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:61)
        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
        at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
        at io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
        at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
        at io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
        at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:132)
        at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
        at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
        at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:60)
        at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:77)
        at io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:269)
        at io.undertow.servlet.handlers.ServletInitialHandler.access$100(ServletInitialHandler.java:78)
        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:133)
        at io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:130)
        at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
        at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
        at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$9$1$1.call(UndertowDeploymentRecorder.java:513)
        at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:249)
        at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:78)
        at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:99)
        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:376)
        at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
        at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1395)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at java.base/java.lang.Thread.run(Thread.java:834)
        at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: javax.ws.rs.ProcessingException: RESTEASY008205: JSON Binding serialization error javax.json.bind.JsonbException: Error getting value on: Page 1 of 1 co
ntaining com.example.Post instances
        at org.jboss.resteasy.plugins.providers.jsonb.JsonBindingProvider.writeTo(JsonBindingProvider.java:137)
        at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.writeTo(AbstractWriterInterceptorContext.java:193)
        at org.jboss.resteasy.core.interception.jaxrs.ServerWriterInterceptorContext.writeTo(ServerWriterInterceptorContext.java:64)
        at org.jboss.resteasy.core.interception.jaxrs.AbstractWriterInterceptorContext.proceed(AbstractWriterInterceptorContext.java:155)
        at org.jboss.resteasy.core.ServerResponseWriter.lambda$writeNomapResponse$2(ServerResponseWriter.java:156)
        at org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:405)
        at org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:232)
        at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:97)
        at org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:70)
        at org.jboss.resteasy.core.SynchronousDispatcher.writeResponse(SynchronousDispatcher.java:578)
        ... 51 more
Caused by: javax.json.bind.JsonbException: Error getting value on: Page 1 of 1 containing com.example.Post instances
        at org.eclipse.yasson.internal.model.GetValueCommand.getValue(GetValueCommand.java:36)
        at org.eclipse.yasson.internal.model.ReflectionPropagation.getValue(ReflectionPropagation.java:73)
        at org.eclipse.yasson.internal.model.PropertyModel.getValue(PropertyModel.java:285)
        at org.eclipse.yasson.internal.serializer.ObjectSerializer.marshallProperty(ObjectSerializer.java:80)
        at org.eclipse.yasson.internal.serializer.ObjectSerializer.serializeInternal(ObjectSerializer.java:61)
        at org.eclipse.yasson.internal.serializer.AbstractContainerSerializer.serialize(AbstractContainerSerializer.java:64)
        at org.eclipse.yasson.internal.Marshaller.serializeRoot(Marshaller.java:148)
        at org.eclipse.yasson.internal.Marshaller.marshall(Marshaller.java:76)
        at org.eclipse.yasson.internal.Marshaller.marshall(Marshaller.java:102)
        at org.eclipse.yasson.internal.JsonBinding.toJson(JsonBinding.java:118)
        at org.jboss.resteasy.plugins.providers.jsonb.JsonBindingProvider.writeTo(JsonBindingProvider.java:133)
        ... 60 more
Caused by: java.lang.IllegalAccessException: class org.eclipse.yasson.internal.model.GetFromGetter cannot access a member of class org.springframework.data.domain.
Chunk with modifiers "public"
        at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:361)
        at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:591)
        at java.base/java.lang.reflect.Method.invoke(Method.java:558)
        at org.eclipse.yasson.internal.model.GetFromGetter.internalGetValue(GetFromGetter.java:28)
        at org.eclipse.yasson.internal.model.GetValueCommand.getValue(GetValueCommand.java:34)
        ... 70 more
geoand commented 5 years ago

Thanks for clarifying.

Yes I mentioned in one of the comments above that returning Page will not work properly. I suggest you just return a List with the page data for the time being. I opened #4056 to track that.

geoand commented 5 years ago

@hantsy FYI, the issue you encountered with not being able to return ResponseEntity<Page<Customer>> has now been fixed on master

geoand commented 5 years ago

Note for future implementation

This could probably be implemented as follows:

gsmet commented 5 years ago

@geoand has this been implemented? I remember having seen a PR that looked related.

geoand commented 5 years ago

No @gsmet, this one has not been implemented yet. There was other related that were implemented but this one has not. It's very marginal and requires a lot of work so it's on the backburner for now :)

tkzhakuna commented 3 years ago

I got the same problem in my Rest Controller but this used to work : findAll(Pageable pageable){....}

Also tried this without success: findAll(@RequestParam("offset")int offset,@RequestParam("pageNumber")int pageNumber, @RequestParam("pageSize") int pageSize,@RequestParam("paged")boolean paged, @RequestParam("unpaged") boolean unpaged, final Pageable pageable){.....}

aureamunoz commented 5 days ago

cc @aureamunoz