0

I'm trying to retrieve some data from a REST service using spring for Android. However I'm running into problems. I'm also using Robospice - and as such have a method like so:

 public FunkyThingsList loadDataFromNetwork() throws Exception {
        String baseURI =context.getResources().getString(R.string.baseWebServiceURI);
                String uri = baseURI + "/FunkyThings/date/" + dateToLookUp.toString("yyyy-MM-dd");
        RestTemplate restTemplate = getRestTemplate();
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setAccept( Arrays.asList(MediaType.APPLICATION_JSON));
        HttpAuthentication authHeader = new HttpBasicAuthentication(username, password);
        headers.setAuthorization(authHeader);

        // Create the request body as a MultiValueMap
        MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
        HttpMessageConverter<String> stringConverter = new StringHttpMessageConverter();
        FormHttpMessageConverter formConverter = new FormHttpMessageConverter();
        List<HttpMessageConverter<?>> msgConverters = restTemplate.getMessageConverters();
        msgConverters.add(formConverter);
        msgConverters.add(stringConverter);
        restTemplate.setMessageConverters(msgConverters);

        HttpEntity<?> httpEntity = new HttpEntity<Object>(map, headers);
        final ResponseEntity<FunkyThingsList> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity,FunkyThingsList.class);

        return responseEntity.getBody();
    }

Unfortunately this isn't working. I'm getting the following exception thrown:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [com.MyProject.DataClassPojos.RoboSpiceArrayLists.FunkyThingsList] and content type [application/json;charset=utf-8]

Now based on my Googling I get the feeling I need to add a message converter. I'm just not sure which message converter I need, or where I add it?

Chris Nevill
  • 5,922
  • 11
  • 44
  • 79

2 Answers2

1

For the default JSON HttpMessageConverter, you'll need to add either Jackson 1 or Jackson 2 to your classpath.

Otherwise, you can add some other JSON library and write your own HttpMessageConverter which can do the deserialization. You add it to the RestTemplate. You can either use the constructor or this method.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • I've changed it to msgConverters.add(formConverter); msgConverters.add(stringConverter); msgConverters.add(new MappingJacksonHttpMessageConverter()); restTemplate.setMessageConverters(msgConverters); but still getting the same response :/ – Chris Nevill Aug 05 '14 at 14:56
  • Correct, you need to add Jackson to your class path, and then add the corresponding MappingJackson2HttpMessageConverter. Alternatively, you can use Gson with GsonHttpMessageConverter. Both message converters handle the application/json media type. The point is that Jackson or Gson must be included as a dependency in your project. – Roy Clarkson Aug 05 '14 at 14:58
  • I'm using Gradle : compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.13' Then importing in my java file: import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; So I think that's my classpath covered? – Chris Nevill Aug 05 '14 at 15:05
  • @ChrisNevill There's a compile time classpath and a runtime classpath. If your app fails with a `ClassNotFoundException`, your classpath is missing that class. Does it? – Sotirios Delimanolis Aug 05 '14 at 15:07
  • No it doesn't. It's compiling fine. – Chris Nevill Aug 05 '14 at 15:07
  • It's also running fine and then still producing the "Could not extract response: no suitable HttpMessageConverter found for response type" exception at the point of the spring request – Chris Nevill Aug 05 '14 at 15:08
  • @ChrisNevill You shouldn't need to add it manually. It's one of the defaults the `RestTemplate` registers by itself. Can you post your type (for which it fails) and the http response's body? – Sotirios Delimanolis Aug 05 '14 at 15:11
  • 1
    @SotiriosDelimanolis that's not quite correct unfortunately. Spring for Android RestTemplate does not register any message converters by default. Chris, you need to add msgConverters.add(jacksonMessageConverter); – Roy Clarkson Aug 05 '14 at 15:49
  • I've jumped deep down in the debugger into MappingJacksonHttpMessageConverter.java. There's a canRead method and when this is being called on my FunkyThingsList class it's returning false - it can't desearialize the object. So it would seem there's something I'm missing regarding that class – Chris Nevill Aug 05 '14 at 16:00
  • @ChrisNevill Which is why I asked you to post it along with the response body :) – Sotirios Delimanolis Aug 05 '14 at 16:01
  • I'm struggling to find the response body in the debugger. It's coming up null. I'm not sure why that is yet. I know the server sides working since I can get results from it fine using 'Postman' – Chris Nevill Aug 05 '14 at 16:04
  • @ChrisNevill I wouldn't be surprised if `RestTemplate` streams it so you won't get it as a single String. Post the result from Postman for now. – Sotirios Delimanolis Aug 05 '14 at 16:08
  • I got there eventually. I've created a cut down version of my FunkyThings class which also is used by ORMLite and low and behold it's now working. Out of time for today... but at least I know I'm on the right track - there's something that can't be serialized in my original class. Thanks for the help from both of you. – Chris Nevill Aug 05 '14 at 16:29
  • @ChrisNevill please let us know if you have further questions. For your and Sotirios's reference, I work on the Spring for Android project. This issue with the RestTemplate constructor not registering default converters is causing a lot of pain in the community, and I'm planning to resolve this and return some consistency with RestTemplate in the core SpringFramework project. We originally went this route to limit resource usage, but it's just causing too much confusion. – Roy Clarkson Aug 06 '14 at 06:54
  • Thanks Roy. I'll let you know if I have any more issues. I'll also comment here to conclude why my object was not de-serialized - just to complete the solution. I'm out of the office for a few days at the mo. – Chris Nevill Aug 07 '14 at 09:48
  • I forgot to add here. The problem turned out to be because I was using Yoda Date Times and also OrmLite ForeignCollection fields. The Yoda issue I resolved by following the answer here: http://stackoverflow.com/questions/13678147/joda-time-2-1-and-android-noclassdeffounderror The Ormlite issue I resolved by seperating my Robospice/Spring Pojos from my Data storage POJOs - using ModelMapper to map between them. – Chris Nevill Aug 19 '14 at 11:14
0

If you are following the Spring for Android tutorial and you get the same error - this might be of help:

In your MainActivity.java:

...
RestTemplate restTemplate = new RestTemplate();
MappingJacksonHttpMessageConverter converter = new
MappingJacksonHttpMessageConverter();    
converter.setSupportedMediaTypes(Collections.singletonList(MediaType.TEXT_HTML));
restTemplate.getMessageConverters().add(converter);

Use the converter in the call and configure it to use as a Media Type the TEXT_HTML, then use the instance of the converter.

Also the tutorial is a bit outdated so use the latest versions as suggested here in your build.gradle:

dependencies{
 //Spring Framework for REST calls and Jackson for JSON processing
 compile 'org.springframework.android:spring-android-rest-template:2.0.0.M3'

 compile 'com.fasterxml.jackson.core:jackson-databind:2.4.1.3'
}
repositories {
 maven {
    url 'https://repo.spring.io/libs-milestone'
 }
}
palamunder
  • 2,555
  • 1
  • 19
  • 20