9

I have a POJO of the form:

@Data
public class BaseRequest {
    private String type;
    private Map<String, Object> details;
    private Map<String, Object> signature;
}

I have a service running which only accepts Content Type: "application/x-www-form-urlencoded".

I have written a client in Java which uses Spring's RestTemplate to make calls.

public String getInvoice(BaseRequest req, String url) {
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

    HttpEntity<BaseRequest> httpEntity = new HttpEntity<BaseRequest>(req, headers);
    String response = this.restTemplate.postForObject(url, httpEntity, String.class);
    return response;
}

However, it throws an error:

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [com.x.y.z.BaseRequest] and content type [application/x-www-form-urlencoded]

It works if I set the content type as JSON:

headers.setContentType(MediaType.APPLICATION_JSON);

I know it works for JSON because I have configured my RestTemplate Bean with JacksonHTTPMessageConverter. So I can easily convert POJOs to application/json. However, I am not able to figure out how to do that with application/x-www-form-urlencoded.

I've been searching this for awhile now, and the only solution which I've found is to write my own converter to convert my BaseRequest class to Spring's MultiValueMap, and then Spring's FormHttpMessageConverter will automatically handle it. But I want to avoid doing that. Is there any other way around this?

Any leads would be appreciated. Thanks!

EDIT: My question is different from @JsonProperty not working for Content-Type : application/x-www-form-urlencoded. The conversion happening there is about accepting data in application/x-www-form-urlencoded and converting it to a POJO. My question is about converting a POJO to application/x-www-form-urlencoded while using Spring's resttemplate to make calls. And like I mentioned, I know I can achieve this by writing my own converter to convert my POJO to Spring's MultiValueMap. However, I want to know if I can avoid doing this.

EDIT:

Dump of $_POST on the API when I send my data as MultiValueMap<String, Object>:

"array(0) {
}"

Dump of $_POST on the API when I send my data through Postman in the correct format:

"array(2) {
  ["type"]=>
  string(16) "abcd"
  ["details"]=>
  array(1) {
  ["template_file"]=>
  string(16) "x.html"
  }
}"
Qawls
  • 91
  • 1
  • 4
  • So you have annotated your controller method with "produces(application/x-www-form-urlencoded)"? – daniu Apr 17 '18 at 11:04
  • @dainu The code of the controller method is on a different service and I can't make changes there. And that service is written in PHP. I am just making API calls to that service from my service (which is written in Java). – Qawls Apr 17 '18 at 11:06

1 Answers1

1

Try to convert your nested object in request payload to the org.springframework.util.MultiValueMap. Add and implement converter method in your POJO

public class BaseRequest {
    // ...

    public MultiValueMap<String, Object> toMap() {
        MultiValueMap<String, Object> result = new LinkedMultiValueMap<>();
        result.add("type", type);
        result.put("details", details);
        result.put("signature", signature);
        return result;
    }
}

Now use it during request creation

HttpEntity<BaseRequest> httpEntity = new HttpEntity<BaseRequest>(req.toMap(), headers);

That is caused because inside FormHttpMessageConverter which performs actual conversion method canRead(Class<?>, MediaType) checks if MultiValueMap.class.isAssignableFrom(clazz) where clazz is your payload object. In your case it failed, so FormHttpMessageConverter skipped.

Hope it helps!

Sergey Prokofiev
  • 1,815
  • 1
  • 12
  • 21
  • Hey, thanks for the response. Like I've mentioned in my question, I want to avoid writing my own converter to convert my POJO to MultiValueMap. I say this because in MultiValueMap, if I insert the details (which is of the type Map), it does not go properly formatted to the server, so the server is not able to parse it. I'm adding the output of $_REQUEST on the server to which this call is being made in the EDIT. – Qawls Apr 17 '18 at 12:00
  • You can change signature of the `MultiValueMap` to `MultiValueMap` and format your object manually according your needs. – Sergey Prokofiev Apr 17 '18 at 12:09
  • yes, but I want to avoid doing that since writing that converter would be ugly. Isn't there some library like jackson which could handle this conversion for me? Or is the problem that I'm facing too uncommon? – Qawls Apr 17 '18 at 12:33
  • @Qawls, Spring already doing it for you, it takes your request from objects and do all converting/processing/handling callback. It's not ugly to write a specific representation of your data if your server is unable to process it otherwise. – Sergey Prokofiev Apr 17 '18 at 12:40
  • @Qawls, if you want good beautiful workaround you need to fix your PHP code, which is not possible, so I recommend you stick to working solution instead of chasing "best". – Sergey Prokofiev Apr 17 '18 at 12:43
  • Wanted to know if there's something like jackson which can do it for me, or maybe there's something that I'm missing here. I guess I'll resort to writing the converter myself. Thanks a lot for your help. – Qawls Apr 17 '18 at 13:08