Failed to write a request: no suitable HttpMessageConverter was found for the request type [org.json.JSONObject] and content type [application / json]

I dig myself in an attempt to send a POST request with a JSON payload to a remote server.

This GET curl command works fine:

curl -H "Accept:application/json" --user aaa@aaa.com :aaa "http://www.aaa.com:8080/aaa-project-rest/api/users/1" -i 

And this POST works fine too:

 curl -H "Accept:application/json" -H "Content-Type: application/json" "http://www.aaa.com:8080/aaa-project-rest/api/users/login" -X POST -d "{ \"email\" : \" aaa@aaa.com \", \"password\" : \"aaa\" }" -i 

And so I am trying to simulate it in my Android app.

The application works fine in the first GET request, but gives 400 Bad Request on the second POST.

Here is the code that works for a GET request:

  RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); HttpHeaders httpHeaders = Common.createAuthenticationHeaders(" aaa@aaa.com " + ":" + "aaa"); User user = null; ResponseEntity<User> responseEntity = restTemplate.exchange("http://" + REST_HOST + ":8080/aaa-project-rest/api/users/" + 1L, HttpMethod.GET, new HttpEntity<Object>(httpHeaders), User.class); 

Here is the source code for the POST request:

 RestTemplate restTemplate = new RestTemplate(); restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); User user = null; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); JSONObject jsonCredentials = new JSONObject(); jsonCredentials.put("email", REST_LOGIN); jsonCredentials.put("password", REST_PASSWORD); ResponseEntity<User> responseEntity = restTemplate.exchange("http://" + REST_HOST + ":" + REST_PORT + "/" + REST_APP + "/api/users/login", HttpMethod.POST, new HttpEntity<Object>(jsonCredentials, httpHeaders), User.class); 

But he gives a message:

 Could not write request: no suitable HttpMessageConverter found for request type [org.json.JSONObject] and content type [application/json] 

Here is the Spring REST controller:

 @RequestMapping(value = RESTConstants.SLASH + RESTConstants.LOGIN, method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public ResponseEntity<UserResource> login(@Valid @RequestBody CredentialsResource credentialsResource, UriComponentsBuilder builder) { HttpHeaders responseHeaders = new HttpHeaders(); User user = credentialsService.checkPassword(credentialsResource); userService.clearReadablePassword(user); if (user == null) { return new ResponseEntity<UserResource>(responseHeaders, HttpStatus.NOT_FOUND); } else { tokenAuthenticationService.addTokenToResponseHeader(responseHeaders, credentialsResource.getEmail()); responseHeaders.setLocation(builder.path(RESTConstants.SLASH + RESTConstants.USERS + RESTConstants.SLASH + "{id}").buildAndExpand(user.getId()).toUri()); UserResource createdUserResource = userResourceAssembler.toResource(user); ResponseEntity<UserResource> responseEntity = new ResponseEntity<UserResource>(createdUserResource, responseHeaders, HttpStatus.CREATED); return responseEntity; } } @RequestMapping(value = RESTConstants.SLASH + "{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public ResponseEntity<UserResource> findById(@PathVariable Long id, UriComponentsBuilder builder) { HttpHeaders responseHeaders = new HttpHeaders(); User user = userService.findById(id); if (user == null) { return new ResponseEntity<UserResource>(responseHeaders, HttpStatus.NOT_FOUND); } else { UserResource userResource = userResourceAssembler.toResource(user); responseHeaders.setLocation(builder.path(RESTConstants.SLASH + RESTConstants.USERS + RESTConstants.SLASH + "{id}").buildAndExpand(user.getId()).toUri()); ResponseEntity<UserResource> responseEntity = new ResponseEntity<UserResource>(userResource, responseHeaders, HttpStatus.OK); return responseEntity; } } 

CredentialsResource class code:

 public class CredentialsResource extends ResourceSupport { @NotEmpty @Email private String email; @NotEmpty private String password; public CredentialsResource() { } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } } 
+7
android post resttemplate
source share
3 answers

It's pretty late to answer, although I just missed the same problem and took some time to solve it. Therefore, I think I better share it and follow my decision.

Actually, the created exception is completely misleading. It MappingJackson2HttpMessageConverter out that the problem was not that MappingJackson2HttpMessageConverter did not know how to sort my object, which seemed strange, being JSON-, but the configuration of the underlying ObjectMapper .

What I did was disable the SerializationFeature.FAIL_ON_EMPTY_BEANS property like this

 restTemplate = new RestTemplate(); MappingJackson2HttpMessageConverter jsonHttpMessageConverter = new MappingJackson2HttpMessageConverter(); jsonHttpMessageConverter.getObjectMapper().configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); restTemplate.getMessageConverters().add(jsonHttpMessageConverter); 

and everything started to work as expected.

+5
source

I needed to do a few things to get this to work.

First I had to convert JSONObject to a string, like in:

 HttpEntity<String> entityCredentials = new HttpEntity<String>(jsonCredentials.toString(), httpHeaders); 

The reason is that there is no matching message converter for the JSONObject class, while there is one for the String class.

Second, I had to pass the true value to the RestTemplate constructor. Otherwise, I would receive 400 Bad Request.

 RestTemplate restTemplate = new RestTemplate(true); 

A true value tells the remainder pattern to use the default converters. If anyone knows why this is so, I would be happy to know more.

Third, I removed the unnecessary Jackson converter:

 restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter()); 

With these things, the query works very well.

Here is the complete code:

 RestTemplate restTemplate = new RestTemplate(true); User user = null; HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.setContentType(MediaType.APPLICATION_JSON); httpHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); try { JSONObject jsonCredentials = new JSONObject(); jsonCredentials.put("email", REST_LOGIN); jsonCredentials.put("password", REST_PASSWORD); Log.e(Constants.APP_NAME, ">>>>>>>>>>>>>>>> JSON credentials " + jsonCredentials.toString()); HttpEntity<String> entityCredentials = new HttpEntity<String>(jsonCredentials.toString(), httpHeaders); ResponseEntity<User> responseEntity = restTemplate.exchange("http://" + REST_HOST + ":" + REST_PORT + "/" + REST_APP + "/api/users/login", HttpMethod.POST, entityCredentials, User.class); if (responseEntity != null) { user = responseEntity.getBody(); } return user; } catch (Exception e) { Log.e(Constants.APP_NAME, ">>>>>>>>>>>>>>>> " + e.getLocalizedMessage()); } return null; 

I suspect there might be a way to explicitly use Jackson's converter and skip the true value in the rest of the template constructor, but this is just an assumption.

+2
source

The exception "no suitable HTTPMessageConverter was found" was thrown if the JSON implementation was not implemented in the class path. Check out the source code for RestTemplate:

 public RestTemplate() { this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); this.messageConverters.add(new ResourceHttpMessageConverter()); this.messageConverters.add(new SourceHttpMessageConverter<Source>()); this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); if (romePresent) { this.messageConverters.add(new AtomFeedHttpMessageConverter()); this.messageConverters.add(new RssChannelHttpMessageConverter()); } if (jackson2XmlPresent) { this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter()); } else if (jaxb2Present) { this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter()); } if (jackson2Present) { this.messageConverters.add(new MappingJackson2HttpMessageConverter()); } else if (gsonPresent) { this.messageConverters.add(new GsonHttpMessageConverter()); } } 

Add the JSON implementation to your class path. E. g .:

 implementation "com.fasterxml.jackson.core:jackson-databind:2.9.0" 
0
source

All Articles