Question

I'm using restTemplate (from the spring android framework) on my android application to contact a rest server with post, i'm using an AsyncTask to send the request and two classes Request and Response which are POJOs send in Json form.

public class RequestSender extends AsyncTask<Object, Void, Response> {
    private RestTemplate restTemplate = new RestTemplate();
    private static final String SERVER_REQUEST_PATH = "/path/to/rest/service";

    @Override
    protected Response doInBackground(Object... args) {
        String url = (String) args[0] + SERVER_REQUEST_PATH;
        Request requestArgs = (Request) args[1];
            Response response = null;

        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        try {
               response = restTemplate.postForObject(url, requestArgs, Response.class);
        } catch (RestClientException e) {
            e.printStackTrace();
            response = null;
        }
        return response;
    }
}

As you can see, the code is quite simple, and is working fine most of the time but not in a particular sequence:

  1. I make a first (or more) request to the server;
  2. I restart the server without restarting the app;
  3. I make a new request to the server;

Then the first request after the server reboot (step 3) is not send to the server by the postForObject(...) method, but next ones are. This first request throw me an Error instead:

07-10 10:24:13.402: W/System.err(4827): org.springframework.web.client.ResourceAccessException: I/O error: null; nested exception is java.io.EOFException
    07-10 10:24:13.402: W/System.err(4827):     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:491)
    07-10 10:24:13.402: W/System.err(4827):     at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:439)
    07-10 10:24:13.402: W/System.err(4827):     at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:317)
    07-10 10:24:13.402: W/System.err(4827):     at com.myapp.servercommunication.RequestSender.doInBackground(RequestSender.java:42)
    07-10 10:24:13.406: W/System.err(4827):     at com.myapp.servercommunication.RequestSender.doInBackground(RequestSender.java:1)
    07-10 10:24:13.406: W/System.err(4827):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
    07-10 10:24:13.406: W/System.err(4827):     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
    07-10 10:24:13.406: W/System.err(4827):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
    07-10 10:24:13.406: W/System.err(4827):     at java.lang.Thread.run(Thread.java:856)
    07-10 10:24:13.409: W/System.err(4827): Caused by: java.io.EOFException
    07-10 10:24:13.413: W/System.err(4827):     at libcore.io.Streams.readAsciiLine(Streams.java:203)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:560)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:813)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274)
    07-10 10:24:13.417: W/System.err(4827):     at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486)
    07-10 10:24:13.417: W/System.err(4827):     at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:54)
    07-10 10:24:13.417: W/System.err(4827):     at org.springframework.http.client.SimpleClientHttpResponse.getStatusCode(SimpleClientHttpResponse.java:80)
    07-10 10:24:13.421: W/System.err(4827):     at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:46)
    07-10 10:24:13.421: W/System.err(4827):     at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:477)
    07-10 10:24:13.421: W/System.
    err(4827):  ... 11 more

Even if the use case isn't important I'm wondering why this error is thrown, is there a problem with my implementation, or is it a quite normal behavior of RestTemplate?

Was it helpful?

Solution

No doubts java.io.EOFException appears on the server side. If you use keep-alive on your server side - switch it off like this:

 HttpHeaders headers = new HttpHeaders();
 headers.set("Connection", "Close");

or this: System.setProperty("http.keepAlive", "false");

Another solution is changing the http client.In Spring for Android the default HTTP Client for a RestTemplate is determined by the version of Android on the device. API 9 or newer uses HttpURLConnection, older uses HTTPClient. To explicitly set the client to the old one, use yourRestTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());

Please refer this:http://static.springsource.org/spring-android/docs/1.0.1.RELEASE/reference/htmlsingle/#d4e34

Spring RestTemplate is not an ideal REST client and unfortunately there are a lot of problems with it in production code.

OTHER TIPS

Recently I faced the same issue when sending the request from REST Template. We tried a lot adding "http.keepAlive" in HTTP Headers but it worked some times and some times it did not worked. Finally we able to resolved this issue after setting "Accept-Language" headers with following piece of code :

HttpHeaders headers = new HttpHeaders();
headers.set("Accept-Language", "en-US,en;q=0.8");

If you use new spring-android v.2.0.0.M3 its need to include maven

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient-android</artifactId>
            <version>4.3.5.1</version>
        </dependency>

or gradle

dependencies {
    compile('org.apache.httpcomponents:httpclient-android:4.3.5.1')
}

If Spring for Android detects HttpClient 4.3, then it will automatically configure it as the default ClientHttpRequestFactory

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top