Skip to content

[Java Spring RestTemplate] Could not write request: no suitable HttpMessageConverter exception when using client #513

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

Closed
MatanRubin opened this issue Jul 9, 2018 · 10 comments

Comments

@MatanRubin
Copy link
Contributor

Description

I have generated a Java RestTemplate client using the sample PetStore API. I compiled and installed the client, then used it from a Spring Boot 2.0.3 application like this:

My configuration:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
    return restTemplateBuilder.build();
}

@Bean
public ApiClient apiClient(RestTemplate restTemplate) {
    return new ApiClient(restTemplate);
}

@Bean
public PetApi petApi(ApiClient apiClient) {
    return new PetApi(apiClient);
}

The code that uses the client:

@Autowired
PetApi petApi;

public void testClient() {
    petApi.findPetsByStatus(Collections.singletonList("sold"));
}

This caused the following exception:

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [java.lang.Object] and content type [application/json]

	at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:965)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:721)
	at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:668)
	at org.openapitools.client.ApiClient.invokeAPI(ApiClient.java:547)
	at org.openapitools.client.api.PetApi.findPetsByStatus(PetApi.java:156)
	at com.XXXX.XXXX.XXX.testClient(XXXXX.java:27)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
openapi-generator version

3.0.2

OpenAPI declaration file content or url

The sample Pet Store API:
https://github.com/raw/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/2_0/petstore.yaml

Command line used for generation

Followed the instruction on the main README file with the java language and resttemplate generator.

Steps to reproduce

Here's a sample project that shows the issue:
demo-6.zip

To see the issue, unpack the zip and:

mvn clean install
mvn spring-boot:run
@jmini jmini changed the title [Java RestTemplate] Could not write request: no suitable HttpMessageConverter exception when using client [Java Spring RestTemplate] Could not write request: no suitable HttpMessageConverter exception when using client Jul 9, 2018
@macjohnny
Copy link
Member

@MatanRubin I guess you are missing the jackson message converter, see http://forum.spring.io/forum/spring-projects/android/126794-no-suitable-httpmessageconverter-found

@MatanRubin
Copy link
Contributor Author

@macjohnny , thanks for the quick reply.
That was what I initially thought, but was able to rule it out by debugging the application and seeing which message converters my RestTemplate had. This is what I saw:

restTemplate = {RestTemplate@5137} 
 messageConverters = {ArrayList@5152}  size = 10
  0 = {ByteArrayHttpMessageConverter@5160} 
  1 = {StringHttpMessageConverter@5161} 
  2 = {StringHttpMessageConverter@5162} 
  3 = {ResourceHttpMessageConverter@5163} 
  4 = {ResourceRegionHttpMessageConverter@5164} 
  5 = {SourceHttpMessageConverter@5165} 
  6 = {AllEncompassingFormHttpMessageConverter@5166} 
  7 = {MappingJackson2HttpMessageConverter@5167} 
  8 = {MappingJackson2HttpMessageConverter@5168} 
  9 = {Jaxb2RootElementHttpMessageConverter@5169} 

As you can see, MappingJackson2HttpMessageConverter is registered.

I also tried debugging right to the point where RestTemplate was trying to use the converter. It seems that the issue is more related to the fact that it tries to convert "request type [java.lang.Object]", and less with the fact that it tries to convert to "content type [application/json]".

Do you know why the request type is java.lang.Object?

@rubms
Copy link
Contributor

rubms commented Jul 19, 2018

It is a problem in the library. The error was inserted in this commit (0fb1ffa#diff-8476983adf7dcdaf957e0aed45e5c8b4) on June 7th (pull request #98).

Instead of having a null post body in operations not accepting a body (like GET), now a plain new Object()t is always created. That object cannot be serialized by the message converter.

This behavior needs to be rolled back or fixed.

@macjohnny
Copy link
Member

@rubms thanks for the analysis. I also think this should be reverted for GET requests.
@bmordue @jmini what do you think?

rubms pushed a commit to rubms/openapi-generator that referenced this issue Jul 19, 2018
…form HTTP requests without a body and an empty Object is used as body instead. In these cases an exception is thrown indicating that it is not possible to find a message converter for java.lang.Object and application/json.
@rubms
Copy link
Contributor

rubms commented Jul 19, 2018

I just created the #605 pull request in order to get this issue fixed. In it I suggest to use null, as default, for POST body only for RestTemplate, whose behavior gets broken as message converters are not able to properly convert ´java.lang.Object´.

@jmini
Copy link
Member

jmini commented Jul 19, 2018

When I read the description of #98:

It's safer to initialize the request body to an empty Object instead of null if there are no body parameters. In particular, this allows Jackson to successfully serialize a POST request with no body parameters when the Content-Type header is set to "application/json", which is set by default.

It comes to my mind that I have started to work on #476. There the use case is that if there is no body (which I guess is the case when it is null) then the client should not send a content type at all.

Feel free to comment on #476 if you think this is a good idea.
If we implement #476 (I have a branch where I started to do it), then maybe we can revert #98...

rubms pushed a commit to rubms/openapi-generator that referenced this issue Jul 20, 2018
jmini pushed a commit that referenced this issue Jul 20, 2018
…605)

#513 Fixed error that causes exception when trying to perform HTTP requests without a body and an empty Object is used as body instead. In these cases an exception is thrown indicating that it is not possible to find a message converter for java.lang.Object and application/json.
@jmini
Copy link
Member

jmini commented Jul 20, 2018

Is this fixed by merge of PR #605 ?

@rubms
Copy link
Contributor

rubms commented Jul 25, 2018

@jmini, I have just launched a code generation using https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator/3.1.2-SNAPSHOT/openapi-generator-3.1.2-20180724.111208-30.jar and, indeed, the error is not reproduced anymore.

@MatanRubin, could you please confirm?

@MatanRubin
Copy link
Contributor Author

I have just tested this using version 3.1.2 and I confirm the issue I saw is now resolved. Thanks a lot for the quick resolution!

On a side note - this was a serious bug in a very basic scenario for a very common library (i.e. the generated client fails a simple GET for Java + RestTemplate). Don't we have tests that cover this kind of scenarios for all languages and libraries? Not trying to blame anyone here, just asking out of curiosity and to see maybe I can contribute some tests that will help prevent this kind of issues.

@jmini
Copy link
Member

jmini commented Jul 30, 2018

@MatanRubin : I have opened an other issue to discuss your tests question: #689 I would appreciate some feedback there.

A-Joshi pushed a commit to ihsmarkitoss/openapi-generator that referenced this issue Feb 27, 2019
…penAPITools#605)

OpenAPITools#513 Fixed error that causes exception when trying to perform HTTP requests without a body and an empty Object is used as body instead. In these cases an exception is thrown indicating that it is not possible to find a message converter for java.lang.Object and application/json.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants