Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NullPointerException when using Spring RestTemplate in Android

I'm using a Spring 3 MVC Server that is hosted on Windows Azure, and am using this to provide users with interaction both through a web browser and an Android device. All code is written in Java.

When I interact with the server through the browser, everything is OK, and when interacting with it using Android it works OK if the server is run as localhost. However, when I interact with the Azure hosted server using the Android client, I randomly (but always eventually) get a NullPointerException, so sometimes the code runs fine but eventually this will show up. Exactly where I get the NullPointer changes, but it is always during a HTTP call using RestTemplate.

Another strange thing, when running the Android app in debug, the code will run to some arbitrary point in the code (still crashing at a RestTemplate call), but the stack trace for the NullPointerException will point to a call made earlier on.

The general code I make for a call is similar to the following:

 private class ChangeDirectory extends AsyncTask< String, Void, Boolean >
{
    @Override
    protected Boolean doInBackground(String... directoryName) {

        RestTemplate restTemplate = new RestTemplate();
        restTemplate.getMessageConverters().add( new StringHttpMessageConverter() );

        String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";

        restTemplate.put(url, 
                         directoryName[0]);
        return true;
    }
}

And the stack trace looks like:

09-05 11:32:05.081: E/AndroidRuntime(535): Caused by: java.lang.NullPointerException
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.http.client.SimpleClientHttpResponse.getStatusCode(SimpleClientHttpResponse.java:62)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:46)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:476)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:438)
09-05 11:32:05.081: E/AndroidRuntime(535):  at org.springframework.web.client.RestTemplate.put(RestTemplate.java:364)
09-05 11:32:05.081: E/AndroidRuntime(535):  at com.artmaps.im.activity.HomeActivity$ChangeDirectory.doInBackground(HomeActivity.java:192)
09-05 11:32:05.081: E/AndroidRuntime(535):  at com.artmaps.im.activity.HomeActivity$ChangeDirectory.doInBackground(HomeActivity.java:1)
09-05 11:32:05.081: E/AndroidRuntime(535):  at android.os.AsyncTask$2.call(AsyncTask.java:264)
09-05 11:32:05.081: E/AndroidRuntime(535):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
09-05 11:32:05.081: E/AndroidRuntime(535):  ... 5 more

which points to the restTemplate.put(url, directoryName[0]); call

I've tried putting in statements on the server side, and when these NullPointers are thrown it appears that the request isn't received by the server as the statements aren't reached.

Any help as to the cause of the NullPointerException would be very much appreciated as i'm pretty confused by this, especially as sometimes it works and sometimes it doesn't

EDIT: After looking around some more it appears there is a bug in the Spring for Android framework, as per https://jira.springsource.org/browse/ANDROID-102

This helps a little, but still doesn't explain why it works sometimes and only fails when interacting with the server based in Azure

like image 431
Patrick Tyler Avatar asked Dec 07 '25 02:12

Patrick Tyler


3 Answers

Thought I'd post what I found in case anybody else gets stuck on this. It turned out to be somehow related to the bug I posted in the edit to my question.

I got around this by removing the Spring RestTemplate calls and using DefaultHttpClient instead.

E.g. changing this:

RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add( new StringHttpMessageConverter() );

    String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";

    restTemplate.put(url, 
                     directoryName[0]);
    return true;

to this:

String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";
        try {

            HttpClient client = new DefaultHttpClient();
            HttpPut putRequest = new HttpPut(url);
            putRequest.setEntity(new StringEntity(directoryName[0]));
            client.execute(putRequest);

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
like image 80
Patrick Tyler Avatar answered Dec 08 '25 14:12

Patrick Tyler


Thought I'd post what I found in case anybody else gets stuck on this. It turned out to be somehow related to the bug I posted in the edit to my question.

I got around this by removing the Spring RestTemplate calls and using DefaultHttpClient instead.

E.g. changing this:

RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add( new StringHttpMessageConverter() );

    String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";

    restTemplate.put(url, 
                     directoryName[0]);
    return true;

to this:

String url = "http://" + Constants.DNS +"/ui/android/cloud/change_directory";
        try {

            HttpClient client = new DefaultHttpClient();
            HttpPut putRequest = new HttpPut(url);
            putRequest.setEntity(new StringEntity(directoryName[0]));
            client.execute(putRequest);

        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
like image 22
Patrick Tyler Avatar answered Dec 08 '25 15:12

Patrick Tyler


If you are getting this error, chances are that you have a problem with Gzip compression : Here is work around, tested on ICS & JB, but that should work everywhere :

Inspired from http://android-developers.blogspot.fr/2011/09/androids-http-clients.html

    RestTemplate restTemplate = new RestTemplate() {
        @Override
        protected ClientHttpRequest createRequest( URI url, HttpMethod method ) throws IOException {
            ClientHttpRequest request = super.createRequest( url, method );
            HttpHeaders headers = request.getHeaders();
            headers.setAcceptEncoding( ContentCodingType.GZIP );

            return request;
        }
    };

    if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO ) {
        System.setProperty( "http.keepAlive", "false" );
    }

    try {
        long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
        File httpCacheDir = new File( getCacheDir(), "http" );
        Class.forName( "android.net.http.HttpResponseCache" ) //
                .getMethod( "install", File.class, long.class )//
                .invoke( null, httpCacheDir, httpCacheSize );
    } catch ( Exception httpResponseCacheNotAvailable ) {
        Ln.v( "Http cache disabled" );
    }

Where Ln is RoboGuice Log library.

like image 35
Snicolas Avatar answered Dec 08 '25 14:12

Snicolas