2

I am somewhat new to HTTP REST operations on Android, and a server I am working with uses PUT commands to process updates. I am having a difficult time using Spring (for Android) with Jackson2. The server doesn't seem to work with application/json put requests (though it will reply with them), and only seem to work with application/x-www-form-urlencoded versions (tested with python and curl. On python, if I set the header type to application/json, it fails.

I am using the latest versions of Spring and Jackson2, and I know everything is setup properly because my get request on the same URL gets me all the correct information.

I am using Robospice, but I don't really think that is relevant. Here is my request code.

@Override
public GPIO loadDataFromNetwork() throws Exception {
    String url = String.format("http://%s/api/control/gpio", ip);
    RestTemplate rt = getRestTemplate();
    DefaultHttpClient client = new DefaultHttpClient();
    Credentials defaultcreds = new UsernamePasswordCredentials("admin",
            password);

    client.getCredentialsProvider().setCredentials(
            new AuthScope(routerip, 80, AuthScope.ANY_REALM), defaultcreds);
    // Makes authentication work.
    rt.setRequestFactory(new HttpComponentsClientHttpRequestFactory(client));
    HttpHeaders requestHeaders = new HttpHeaders(); 
    requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

    HttpEntity request = new HttpEntity(data, requestHeaders);
    List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
    MappingJackson2HttpMessageConverter map = new MappingJackson2HttpMessageConverter();
    messageConverters.add(map);
    messageConverters.add(new FormHttpMessageConverter());
    rt.setMessageConverters(messageConverters);

    ResponseEntity<GPIO> r = rt.exchange(url, HttpMethod.PUT, request, GPIO.class);
    return r.getBody();
}

I am getting the exception stating it cannot find a way to convert:

02-01 10:59:29.466: E//DefaultRequestRunner.java:138(30086): 
10:59:29.474 Thread-11651 An exception occurred during request network 
execution :Could not write request: no suitable HttpMessageConverter 
found for request type [com.xxxxx.control.gpio.GPIO] and content 
type [application/x-www-form-urlencoded]

GPIO is my POJO object. I want to 'put' that to the server, as in serialize and put it.

I have looked at the following question that seems fairly relevant:

However, I need the result of my put command, and that requires me to use exchange() because Spring's put() returns nothing.

I have tried several different items (such as removing GPIO references, setting specific headres...) and none seem to work. I have a feeling this is probably an easy solution that I don't know how to fix. If anyone can help me that would be great.

TLDR: I'm using Spring for Android with Jackson2. I want to serialize my object (in this example, GPIO) so I can do a PUT request with the content type application/x-www-form-urlencoded. However I cannot get jackson to convert to that type, only to application/json, which does not work for me. I am not sure how to fix this, and I have run out of ideas. If I can't find a solution I'll probably have to dumb robospice. (or jackson, not sure which yet.)

Solution

Spring for Android doesn't seem to simplify things, so I dumped it and used the apache client directly in my loadDataFromNetwork() method. Robospice handles it pretty well and I can get the responses I need. If you are new to HTTP like I was take the time and learn the apache client, it's far easier in my opinion. Tweaking the ObjectMapper (like making a JsonTree and parsing that) made it much easier to get the data I needed without having to do as much work with POJO objects.

Community
  • 1
  • 1
Mgamerz
  • 2,872
  • 2
  • 27
  • 48
  • You may want to have a look at [`FormHttpMessageConverter`](https://github.com/spring-projects/spring-android/blob/master/spring-android-rest-template/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java) as I believe it doesn't know of your `GPIO` class – gunar Feb 01 '14 at 23:53
  • I've added that to the types of converters but I'm not sure how to get it to see my class. I have many classes that will likely need to be serialized as my API is fairly large. – Mgamerz Feb 02 '14 at 04:07
  • Can you share the client (javascript/jquery, etc.) code that calls the method? I was having a similar problem that required a specific format for encoding the request body. – Pedantic Feb 03 '14 at 18:24
  • Uh... I don't have access to the source code of the server (if that's what you are asking). I can ask the people who own it but it seems to reject application/json puts. – Mgamerz Feb 03 '14 at 18:26
  • It's located here: https://github.com/Mgamerz/RouterAPIShowcase/blob/MobileMapper/src/com/cs481/mobilemapper/responses/control/gpio/PutRequest.java It doesn't use jquery/javascript though. – Mgamerz Feb 03 '14 at 18:27
  • I redact my last edit - sorry, I thought this was an issue on the server side. Spring+Jackson2 made me think it was a server-side issue. – Pedantic Feb 03 '14 at 18:28
  • I edited the post to make it a bit clearer. – Mgamerz Feb 03 '14 at 18:29
  • Have you tried Retrofit (https://github.com/square/retrofit)? This is really easy to do using Retrofit. – Luis Feb 10 '14 at 13:55
  • I think I might just dump spring. They advertise as convenient but don't even make a convenience method for put responses like they do for the others... – Mgamerz Feb 10 '14 at 14:28

3 Answers3

1

If you can format the data you want to send into MultiValueMap<String, String>, then a possible way around this is to use FormHttpMessageConverter.

FormHttpMessageConverter: (you can see examples in the link)

An HttpMessageConverter implementation that can read and write form data from the HTTP request and response. By default, this converter reads and writes the media type application/x-www-form-urlencoded. Form data is read from and written into a MultiValueMap<String,String>.

Raanan
  • 4,777
  • 27
  • 47
  • 1
    Ubfortunately I cannot. It is wrapped in encapsulating elements which made this not work. I spent 2 days on this... Gave up on that route. – Mgamerz Feb 10 '14 at 17:49
  • Did you try setSupportedMediaTypes on the MappingJackson2HttpMessageConverter with "application/x-www-form-urlencoded" ? ( you need to build an array of mediatypes) I'm using that when receiving weird contenttypes maybe it will work the other way around? – Raanan Feb 10 '14 at 17:56
  • Tried that. My data must have a data=params format and this doesn't do that unfortunately. The params must be UTF8 but the data= part should not be. – Mgamerz Feb 10 '14 at 17:57
  • I know. I forgot to update the question. The people I am working for asked me to make it private unfortunately. – Mgamerz Feb 10 '14 at 18:14
  • Can you post the POJO? – Raanan Feb 10 '14 at 18:14
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/47183/discussion-between-raanan-and-mgamerz) – Raanan Feb 10 '14 at 18:15
  • Where I am at (work) the SO chat is blocked so I can't use that right now. I'm going to award you the bounty for helping me with this though. I'll reply in the chat when I can. – Mgamerz Feb 10 '14 at 18:16
  • Can you test serializing your POJO using ObjectMapper writeValueAsString ? – Raanan Feb 10 '14 at 18:27
0

After re-reading, here's a shot at a real answer - you are explicitly using the x-www-form-urlencoded content type by using this RequestHeader:

HttpHeaders requestHeaders = new HttpHeaders(); 
requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

You should be using APPLICATION_JSON - Here's the Javadoc.

You should also consider specifying the charset and datatype in the headers. Jaxson is very specific about this, and if you don't have access to the server code you don't know what headers they expect.

Pedantic
  • 5,032
  • 2
  • 24
  • 37
  • The server does not accept application/json - I tested with python. Curl and Python by default send as x-www-form-urlencoded type. (I also used Wireshark and confirmed this). If I set the type in python to application/json (it does indeed send the proper JSON object), the server responds with an exception. (exception: 'key'). However it works with x-www-form-urlencoded. The server takes `x-www-form-urlencoded` and respond with a `JSON` object. (That's standard Jquery from what I've heard, apparently.) – Mgamerz Feb 03 '14 at 18:48
  • @Mgamerz this is the exact issue I'm also facing, still searching for help – Suresh May 24 '22 at 08:56
0

dude i am using Loopj's AsyncHttpClient for rest and json dataset. Here is the link below Here

Very simple and easy to understand. U can try this thing.

MehmetF
  • 61
  • 1
  • 14
  • This doesn't really integrate into robospice however, and AsyncTask's are bad when you have rotation of the device (which is why I am using robospice). – Mgamerz Feb 10 '14 at 17:08