Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring-data throw JsonMappingException when using PageImpl #41292

Closed
jedla97 opened this issue Jun 18, 2024 · 16 comments · Fixed by #45114
Closed

Spring-data throw JsonMappingException when using PageImpl #41292

jedla97 opened this issue Jun 18, 2024 · 16 comments · Fixed by #45114
Labels
area/spring Issues relating to the Spring integration kind/bug Something isn't working
Milestone

Comments

@jedla97
Copy link
Contributor

jedla97 commented Jun 18, 2024

Describe the bug

Returnning PageImpl to the endpoint causing throw com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.UnsupportedOperationException) (through reference chain: org.springframework.data.domain.PageImpl["pageable"]->org.springframework.data.domain.Unpaged["pageSize"])

This is probably caused by bump of spring in #40344.

The attached reproduces working with 3.11.2 and failing with 999-SNAPSHOT

Also using quarkus-rest-jackson the endpoint return 500 and using quarkus-resteasy-jackson return 400 but that's probably difference in implamentation of these extensions.

Using quarkus-resteasy-jackson returning Not able to deserialize data provided. and error is shown only in log.

Expected behavior

Expecting to get result from endpoint based on passed parameters.

For example on http://localhost:8080/book/paged?size=1&page=0 return should be like this

{"content":[{"bid":1,"name":"Sapiens","publicationYear":2011,"isbn":9789295055025}],"pageable":"INSTANCE","last":true,"totalPages":1,"totalElements":1,"first":true,"numberOfElements":1,"size":0,"number":0,"sort":{"sorted":false,"unsorted":true,"empty":true},"empty":false}

Actual behavior

Error:

java.lang.UnsupportedOperationException
	at org.springframework.data.domain.Unpaged.getPageSize(Unpaged.java:65)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:183)
	at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:732)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:770)
	at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:183)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:502)
	at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:341)
	at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1574)
	at com.fasterxml.jackson.databind.ObjectWriter._writeValueAndClose(ObjectWriter.java:1275)
	at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:1098)
	at io.quarkus.resteasy.reactive.jackson.runtime.serialisers.BasicServerJacksonMessageBodyWriter.writeResponse(BasicServerJacksonMessageBodyWriter.java:39)
	at org.jboss.resteasy.reactive.server.core.ServerSerialisers.invokeWriter(ServerSerialisers.java:217)
	at org.jboss.resteasy.reactive.server.core.serialization.DynamicEntityWriter.write(DynamicEntityWriter.java:113)
	at org.jboss.resteasy.reactive.server.handlers.ResponseWriterHandler.handle(ResponseWriterHandler.java:32)
	at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:147)
	at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:599)
	at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2516)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2495)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1521)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Resulted in: com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.UnsupportedOperationException) (through reference chain: org.springframework.data.domain.PageImpl["pageable"]->org.springframework.data.domain.Unpaged["pageSize"])
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:402)
	at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:361)
	at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:323)
	at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:778)
	... 23 more

How to Reproduce?

  1. git clone -b spring-paged-rest [email protected]:jedla97/quarkus-reproducers.git
  2. cd quarkus-reproducers
  3. mvn clean verify
  4. To pass test use mvn clean verify -Dquarkus.platform.version=3.11.2

In addition you can run it in dev mode and access it on http://localhost:8080/book/paged?size=1&page=0

Also you can try resteasy by change branche to spring-paged-resteasy

Output of uname -a or ver

Fedora 40, Ubuntu 22 (Github runner)

Output of java -version

OpenJDK 21

Quarkus version or git rev

main

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.9.3

Additional information

No response

@jedla97 jedla97 added the kind/bug Something isn't working label Jun 18, 2024
@quarkus-bot quarkus-bot bot added the area/spring Issues relating to the Spring integration label Jun 18, 2024
Copy link

quarkus-bot bot commented Jun 18, 2024

/cc @geoand (spring)

@jedla97
Copy link
Contributor Author

jedla97 commented Jun 18, 2024

cc aureamunoz as this is probably related to bump of the spring

@gsmet
Copy link
Member

gsmet commented Jun 19, 2024

Let's make sure we add some tests when we fix this. Thanks!

jedla97 added a commit to jedla97/quarkus-test-suite that referenced this issue Jun 19, 2024
@michalvavrik
Copy link
Member

hey @jedla97 @aureamunoz, I am looking at the Quarkus QE test coverage for Spring and wondering about this one. Is this fixed, to do, or not a bug?

@jedla97
Copy link
Contributor Author

jedla97 commented Sep 19, 2024

I try the reproducer and it's still failing, so it's not fixed/explained.

From my POV it's a bug, as this worked fine before. Maybe it's only error in implementation as something changes but I don't see anything in our migration guide.

@aureamunoz
Copy link
Member

Oops, I completely missed this one, I need to take a look closer. I will work on it next week

@michalvavrik
Copy link
Member

Thanks @jedla97 @aureamunoz

@aureamunoz
Copy link
Member

aureamunoz commented Sep 24, 2024

I investigated this issue, and it turns out the problem isn't on our side. Starting from Spring Boot 3.2, Unpaged instances are no longer Jackson-serializable by default. As mentioned in the linked issue, the problem isn't that Unpaged instances now are non-serializable. Previously, Unpaged was represented as an Enum, which always serialized to a String. However, this has changed—Unpaged is now represented by an object, which alters the serialization behavior.

To resolve this, you should use the PageImpl constructor that takes a List of content, pagination details, and the total item count, rather than just passing the collection. In your reproducer code, passing only the collection results in the creation of an Unpaged object making it non-serializable.

To fix the issue, I recommend updating the BookStore#findPaged method as follows:

public Page<Book> findPaged(Pageable pageable) {
        List<Book> list = this.findAll().list();
        return new PageImpl<>(list,pageable,list.size());
    }

cc @jedla97 @michalvavrik

@michalvavrik
Copy link
Member

thanks for investigation @aureamunoz I'll let @jedla97 look into it when he is back next week

@aureamunoz
Copy link
Member

Can we close this one? @jedla97 @michalvavrik ?

@michalvavrik
Copy link
Member

hey @jedla97 please check or ping me directly if you don't have time and I'll. thanks

@jedla97
Copy link
Contributor Author

jedla97 commented Dec 4, 2024

I'll look at this later this week.

jedla97 added a commit to jedla97/quarkus-test-suite that referenced this issue Dec 12, 2024
The original test was based on serialization, which is no longer possible out of bot.
In quarkusio/quarkus#41292 was suggested use this modification to make the original code work.
Now we checking if retunred json, pageable item contains specific values.

For more info see quarkusio/quarkus#41292 (comment)
@jedla97
Copy link
Contributor Author

jedla97 commented Dec 12, 2024

@aureamunoz thanks for instruction. It worked fine in jvm. I just needed to refactor the test for it which was checking the serialization (for native specificaly). As now the serialization is not out-of-box the whole behavioral is different.

I have just one question. Is the missing elements paged and unpaged in pageable element expected?

"pageable": {
    "pageNumber": 1,
    "pageSize": 2,
    "sort": {
      "sorted": false,
      "unsorted": true,
      "empty": true
    },
    "offset": 2,
    "unpaged": false,
    "paged": true
  },

This is just part of the response. In native the same part looks like this:

"pageable":{
    "pageNumber":1,
    "pageSize":2,
    "sort":{
      "unsorted":true,
      "sorted":false,
      "empty":true
    },
    "offset":2
},

@aureamunoz
Copy link
Member

Oh! good catch! the paged/unpaged attributes should be present. I've just raised a PR for fixing it.

aureamunoz added a commit to aureamunoz/quarkus that referenced this issue Dec 16, 2024
aureamunoz added a commit to aureamunoz/quarkus that referenced this issue Dec 17, 2024
gsmet pushed a commit to gsmet/quarkus that referenced this issue Dec 17, 2024
@aureamunoz
Copy link
Member

aureamunoz commented Dec 17, 2024

The PR has been merged @jedla97 , can we close this one?

@geoand geoand closed this as completed Dec 17, 2024
@geoand geoand added this to the 3.18 - main milestone Dec 17, 2024
@jedla97
Copy link
Contributor Author

jedla97 commented Dec 17, 2024

I see this is already closed. But can confirm that the fix for native is working, so I'm not against closing this issue.

jedla97 added a commit to jedla97/quarkus-test-suite that referenced this issue Dec 18, 2024
The original test was based on serialization, which is no longer possible out of bot.
In quarkusio/quarkus#41292 was suggested use this modification to make the original code work.
Now we checking if retunred json, pageable item contains specific values.

For more info see quarkusio/quarkus#41292 (comment)
jedla97 added a commit to jedla97/quarkus-test-suite that referenced this issue Dec 18, 2024
The original test was based on serialization, which is no longer possible out of box.
In quarkusio/quarkus#41292 was suggested use this modification to make the original code work.
Now we checking if returned json, pageable item contains specific values.

For more info see quarkusio/quarkus#41292 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/spring Issues relating to the Spring integration kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants