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

[BUG][Java][RestTemplate][WebClient] Java client generator doesn't support deepObject in query #14691

Closed
5 of 6 tasks
jorgerod opened this issue Feb 14, 2023 · 15 comments
Closed
5 of 6 tasks

Comments

@jorgerod
Copy link
Contributor

Bug Report Checklist

  • Have you provided a full/minimal spec to reproduce the issue?
  • Have you validated the input using an OpenAPI validator (example)?
  • Have you tested with the latest master to confirm the issue still exists?
  • Have you searched for related issues/PRs?
  • What's the actual output vs expected output?
  • [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description

Java RestTemplate and Java Webclient generator don't support deepObject in query

openapi-generator version

5.4.0, 6.3.0

OpenAPI declaration file content or url
openapi: 3.0.0

info:
  title: Example
  description: Example of deepObject failure.
  version: 1.0.0

paths:
  /test:
    get:
      operationId: test
      parameters:
        - name: filter
          in: query
          style: deepObject
          explode: true
          schema:
            type: object
            properties:
              search:
                description: Filter.
                type: string
      responses:
        '200':
          description: Response.
Generation Details

java -jar openapi-generator-cli.jar generate -g java -i openapi-rest.yml -o openapi --library resttemplate
java -jar openapi-generator-cli.jar generate -g java -i openapi-rest.yml -o openapi --library webclient

Related issues/PRs
Suggest a fix
@wing328
Copy link
Member

wing328 commented Feb 16, 2023

can you try the native or apache-httpclient library, which has better support for deep object query paramters?

@jorgerod
Copy link
Contributor Author

Hello

With apache-httpclient it didn't work for me. it generates a url like this:

/api/team?query=class%20TeamCriteriaDTODTO%20%7B%0A%20%20%20%20teamIdList%3A%20%5B%5D%0A%20%20%20%20teamKeyList%3A%20%5B%5D%0A%20%20%20%20key%3A%20kkk%0A%20%20%20%20name%3A%20null%0A%20%20%20%20description%3A%20dddd%0A%20%20%20%20typeIdList%3A%20%5B%5D%0A%20%20%20%20managerLogin%3A%20null%0A%20%20%20%20department%3A%20d%0A%20%20%20%20includeTeamMembers%3A%20true%0A%20%20%20%20includeTeamProfiles%3A%20true%0A%20%20%20%20includeTeamProjects%3A%20true%0A%20%20%20%20includeTeamResources%3A%20false%0A%20%20%20%20includeTeamAchievements%3A%20false%0A%7D

With native the generated code doesn't even compile.

@jorgerod
Copy link
Contributor Author

@GregDThomas
Copy link
Contributor

The resttemplate library should be fixed in the PR at #14825

@stephenmontgomery
Copy link

Copy of #4808 (comment)

Doesn't work with Spring Weblient generation in openapi-generator-maven-plugin:6.40. Generates same error as #4808 (comment) ie ?pageable=class%20Pageable%20%7B%0A%20%20%20%20page%3A%200%0A%20%20%20%20size%3A%20100%0A%20%20%20%20sort%3A%20%5Bname%5D%0A%7D

In Swagger UI it creates the expected ?page=0&size=20&sort=name

Caused by: org.springframework.core.codec.DecodingException: JSON decoding error: Cannot deserialize value of type `com.contrastsecurity.authz.client.model.SortObject` from Array value (token `JsonToken.START_ARRAY`); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `com.contrastsecurity.authz.client.model.SortObject` from Array value (token `JsonToken.START_ARRAY`)
 at [Source: (io.netty.buffer.ByteBufInputStream); line: 1, column: 426] (through reference chain: com.contrastsecurity.authz.client.model.PageUserAccessGroupResponse["pageable"]->com.contrastsecurity.authz.client.model.PageableObject["sort"])
	at org.springframework.http.codec.json.AbstractJackson2Decoder.processException(AbstractJackson2Decoder.java:242)
	Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below: 
Error has been observed at the following site(s):
	*__checkpoint ⇢ Body from GET http://localhost:10005/organizations/f4546458-72ae-4784-a7e2-a440761fb92e/user-access-groups/user/388f1310-7dfd-44f6-82ad-be7e8997c08c?pageable=class%20Pageable%20%7B%0A%20%20%20%20page%3A%200%0A%20%20%20%20size%3A%20100%0A%20%20%20%20sort%3A%20%5Bname%5D%0A%7D [DefaultClientResponse]
Original Stack Trace:
		at org.springframework.http.codec.json.AbstractJackson2Decoder.processException(AbstractJackson2Decoder.java:242)
		at org.springframework.http.codec.json.AbstractJackson2Decoder.decode(AbstractJackson2Decoder.java:198)
		at org.springframework.http.codec.json.AbstractJackson2Decoder.lambda$decodeToMono$1(AbstractJackson2Decoder.java:179)
		at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125)
		at reactor.core.publisher.FluxContextWrite$ContextWriteSubscriber.onNext(FluxContextWrite.java:107)
		at reactor.core.publisher.FluxMapFuseable$MapFuseableConditionalSubscriber.onNext(FluxMapFuseable.java:299)
		at reactor.core.publisher.FluxFilterFuseable$FilterFuseableConditionalSubscriber.onNext(FluxFilterFuseable.java:337)
		at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1839)
		at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:160)
		at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)
		at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:260)
		at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:144)
		at reactor.netty.channel.FluxReceive.onInboundComplete(FluxReceive.java:415)
		at reactor.netty.channel.ChannelOperations.onInboundComplete(ChannelOperations.java:424)
		at reactor.netty.channel.ChannelOperations.terminate(ChannelOperations.java:478)
		at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:712)
		at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:113)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
		at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
		at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
		at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
		at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
		at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
		at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
		at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
		at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788)
		at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
		at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
		at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
		at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
		at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
		at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
		at java.base/java.lang.Thread.run(Thread.java:833)
	Suppressed: java.lang.Exception: #block terminated with an error
		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:139)
		at reactor.core.publisher.Mono.block(Mono.java:1766)

@ghost
Copy link

ghost commented Aug 4, 2023

yep, same problem ts-axios :={

@stephenmontgomery
Copy link

Any word on this?

@GregDThomas
Copy link
Contributor

This bug ticket explicitly mentions the Java RestTemplate in the title.

I believe this was fixed in #14825 released in 7.0.0

@nefarian-gaming
Copy link

The bug still exist in 7.0.1 for webclient. Any ideas for a workaround?

@stephenmontgomery
Copy link

stephenmontgomery commented Dec 1, 2023

This bug ticket explicitly mentions the Java RestTemplate in the title.

I believe this was fixed in #14825 released in 7.0.0

Still doesn't work with resttemplate on 7.0.1 either @GregDThomas:

It's unable to parse empty body response eg {"content":[],"pageable":{"pageNumber":0,"pageSize":20,"sort":[],"offset":0,"paged":true,"unpaged":false},"last":true,"totalPages":0,"totalElements":0,"size":20,"number":0,"sort":[],"first":true,"numberOfElements":0,"empty":true}

Error is:

org.springframework.web.client.RestClientException: Error while extracting response for type [class com.contrastsecurity.authz.client.model.PageRoleResponse] and content type [application/json]

	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:118)
	at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1132)
	at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1115)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:865)
	at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:714)
	at com.contrastsecurity.authz.client.invoker.ApiClient.invokeAPI(ApiClient.java:582)
	at com.contrastsecurity.authz.client.api.RolesApi.getAllRolesWithHttpInfo(RolesApi.java:240)
	at com.contrastsecurity.authz.client.api.RolesApi.getAllRoles(RolesApi.java:187)
	at com.contrastsecurity.authz.client.AuthzClientTest.shouldGetPagedResults(AuthzClientTest.java:65)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
	at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
	at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
	at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
	at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
	at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
	at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
	at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
	at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
	at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
	at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
	at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:55)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
	at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
	at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
	at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
	at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53)
	at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.contrastsecurity.authz.client.model.SortObject` from Array value (token `JsonToken.START_ARRAY`)
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:406)
	at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:354)
	at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:103)
	... 78 more
Caused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `com.contrastsecurity.authz.client.model.SortObject` from Array value (token `JsonToken.START_ARRAY`)
 at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 63] (through reference chain: com.contrastsecurity.authz.client.model.PageRoleResponse["pageable"]->com.contrastsecurity.authz.client.model.PageableObject["sort"])

I really don't care if it's RestTemplate or Webclient as long as it works. I haven't seen any OneApi-generated Java client that works with Spring Paging (and I've tried them all).

@GregDThomas
Copy link
Contributor

This ticket is talking about sending a query string in the request. Looks like your problem is in parsing a response, so a different issue.

@stephenmontgomery
Copy link

Prob time @GregDThomas to open an epic and just get 1 OneAPI Java client working with Spring Data Paging. This ticket is still open and related (long-running) #4808 re-opened. I'm not sure you get any points if just the request works...

@GregDThomas
Copy link
Contributor

The title of this ticket makes it clear that it's about the deepObject in the /query/ for both RestTemplate and WebClient. I believe the RestTemplate side is fixed, just not WebClient (TBH I think this issue should be closed as a duplicate of #14790)

If you raise a different ticket describing your different issue of how RestTemplate is failing to to parse the response, you're more likely to get it resolved.

But by far the best way to get it resolved is to raise a ticket and then submit a PR to fix it.

@jorgerod
Copy link
Contributor Author

jorgerod commented Feb 21, 2024

The title of this ticket makes it clear that it's about the deepObject in the /query/ for both RestTemplate and WebClient. I believe the RestTemplate side is fixed, just not WebClient (TBH I think this issue should be closed as a duplicate of #14790)

@GregDThomas RestTemplate problem continues in version 7.3.0

@jorgerod
Copy link
Contributor Author

Closed in favor of #14790

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants