1

I try to parse JSON like in this snippet using gson:

{
"cod":"200",
"message":0,
"cnt":40,
"list":[
{"dt":1584565200,"main":{"temp":284.22,"feels_like":279.95,"temp_min":282.33,"temp_max":284.22,"pressure":1021,"sea_level":1021,"grnd_level":1011,"humidity":81,"temp_kf":1.89},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"clouds":{"all":100},"wind":{"speed":5.42,"deg":275},"sys":{"pod":"n"},"dt_txt":"2020-03-18 21:00:00"},
{"dt":1584576000,"main":{"temp":282.97,"feels_like":279.59,"temp_min":281.55,"temp_max":282.97,"pressure":1021,"sea_level":1021,"grnd_level":1011,"humidity":88,"temp_kf":1.42},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"clouds":{"all":100},"wind":{"speed":4.14,"deg":273},"rain":{"3h":0.44},"sys":{"pod":"n"},"dt_txt":"2020-03-19 00:00:00"},
{"dt":1584586800,"main":{"temp":281.44,"feels_like":277.55,"temp_min":280.5,"temp_max":281.44,"pressure":1020,"sea_level":1020,"grnd_level":1010,"humidity":87,"temp_kf":0.94},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10n"}],"clouds":{"all":100},"wind":{"speed":4.33,"deg":286},"rain":{"3h":0.81},"sys":{"pod":"n"},"dt_txt":"2020-03-19 03:00:00"},
{"dt":1584597600,"main":{"temp":279.82,"feels_like":276.13,"temp_min":279.35,"temp_max":279.82,"pressure":1021,"sea_level":1021,"grnd_level":1011,"humidity":89,"temp_kf":0.47},"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],"clouds":{"all":100},"wind":{"speed":3.66,"deg":311},"rain":{"3h":0.56},"sys":{"pod":"d"},"dt_txt":"2020-03-19 06:00:00"}]

In reality it's much longer, it has approximately 15,000 characters. All I need are temps, dts, rain or snow precipitation, so I've created classes below:

ForecastParams.java

import java.util.List;

public class ForecastParams {
    public List<_List> list;
}

_List.java

import java.util.List;

public class _List {
    public long dt;

    public Main main;

    public Rain rain;

    public Snow snow;
}

Main.java

public class Main {
    public double temp;
    public double feels_like;
    public double temp_min;
    public double temp_max;
    public int pressure;
    public int humidity;
}

Rain.java

public class Rain {
    @SerializedName("3h")
    public double rainPrep;
}

Snow.java

public class Snow {
    @SerializedName("3h")
    public double snowPrep;
}

I use AsyncTask to perform getting json from server and then parsing it (in main activity):

private class getForecastData extends AsyncTask<String, Void, Reader>{
        private Reader json;

        @Override
        protected Reader doInBackground(String... urls){
            try{
                json = RestAPIService.getStream(urls[0]);
            }catch (Exception e){
                e.printStackTrace();
            }

            return json;
        }

        @Override
        protected void onPostExecute(Reader json){
            try{
                Gson gson = new Gson();
                ForecastParams response = gson.fromJson(json, ForecastParams.class);
                List<_List> forecastList = response.list;
                double temp = 0;
                List<Long> dayTime = new ArrayList<>();
                List<Double> temps = new ArrayList<>();
                List<Double> rainPrep = new ArrayList<>();
                List<Double> snowPrep = new ArrayList<>();

                for (_List weather : forecastList){
                    dayTime.add(weather.dt);
                    temps.add(weather.main.temp);
                    rainPrep.add(weather.rain.rainPrep);
                    snowPrep.add(weather.snow.snowPrep);
                }

                setDtList(dayTime);
                setTempsList(temps);                
                setRainPrepList(rainPrep);
                setSnowPrepList(snowPrep);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

getStream is like:

static Reader getStream(String url) throws IOException {
    URL obj = new URL(url);
    HttpURLConnection connection = (HttpURLConnection)obj.openConnection();
    InputStream resBody;
    connection.setRequestMethod("GET");
    int responseCode = connection.getResponseCode();

    if (responseCode == HttpURLConnection.HTTP_OK) {
       resBody = connection.getInputStream();
    } else
        return null;

    connection.disconnect();

    Reader resBodyReader = new InputStreamReader(resBody, "UTF-8");

    return resBodyReader;
}

When launching an app I receive following stack trace:

W/System.err: android.os.NetworkOnMainThreadException
        at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1513)
        at java.net.SocketInputStream.read(SocketInputStream.java:175)
        at java.net.SocketInputStream.read(SocketInputStream.java:144)
        at com.android.okhttp.okio.Okio$2.read(Okio.java:136)
W/System.err:     at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
        at com.android.okhttp.okio.RealBufferedSource.read(RealBufferedSource.java:50)
        at com.android.okhttp.internal.http.Http1xStream$FixedLengthSource.read(Http1xStream.java:393)
        at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:371)
        at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at com.google.gson.stream.JsonReader.fillBuffer(JsonReader.java:1291)
        at com.google.gson.stream.JsonReader.skipQuotedValue(JsonReader.java:1119)
        at com.google.gson.stream.JsonReader.skipValue(JsonReader.java:1253)
W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
        at com.google.gson.Gson.fromJson(Gson.java:932)
        at com.google.gson.Gson.fromJson(Gson.java:870)
        at com.pklos.myweather.MainActivity$getForecastData.onPostExecute(MainActivity.java:243)
        at com.pklos.myweather.MainActivity$getForecastData.onPostExecute(MainActivity.java:202)
        at android.os.AsyncTask.finish(AsyncTask.java:695)
        at android.os.AsyncTask.access$600(AsyncTask.java:180)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

When I switch the StrictMode on like this (in onCreate method):

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy); 

I get stack trace like this (socket closed):

W/System.err: com.google.gson.JsonSyntaxException: java.net.SocketException: Socket closed
        at com.google.gson.Gson.fromJson(Gson.java:947)
        at com.google.gson.Gson.fromJson(Gson.java:870)
        at com.pklos.myweather.MainActivity$getForecastData.onPostExecute(MainActivity.java:243)
        at com.pklos.myweather.MainActivity$getForecastData.onPostExecute(MainActivity.java:202)
        at android.os.AsyncTask.finish(AsyncTask.java:695)
        at android.os.AsyncTask.access$600(AsyncTask.java:180)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:712)
        at android.os.Handler.dispatchMessage(Handler.java:106)
W/System.err:     at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
    Caused by: java.net.SocketException: Socket closed
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:119)
        at java.net.SocketInputStream.read(SocketInputStream.java:176)
W/System.err:     at java.net.SocketInputStream.read(SocketInputStream.java:144)
        at com.android.okhttp.okio.Okio$2.read(Okio.java:136)
        at com.android.okhttp.okio.AsyncTimeout$2.read(AsyncTimeout.java:211)
        at com.android.okhttp.okio.RealBufferedSource.read(RealBufferedSource.java:50)
        at com.android.okhttp.internal.http.Http1xStream$FixedLengthSource.read(Http1xStream.java:393)
        at com.android.okhttp.okio.RealBufferedSource$1.read(RealBufferedSource.java:371)
W/System.err:     at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:288)
        at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:351)
        at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:180)
        at java.io.InputStreamReader.read(InputStreamReader.java:184)
        at com.google.gson.stream.JsonReader.fillBuffer(JsonReader.java:1291)
        at com.google.gson.stream.JsonReader.nextQuotedValue(JsonReader.java:1031)
        at com.google.gson.stream.JsonReader.nextName(JsonReader.java:788)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:217)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
        at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
        at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
        at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
W/System.err:     at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
        at com.google.gson.Gson.fromJson(Gson.java:932)
        ... 12 more

My question is why is the socket closed? I'm confused by fact an app have already downloaded json from server. In the same way I parse another JSON (about 500 characters) and it works properly. Is amount of information crucial here? Or maybe the classes that handles the information from JSON are not written in right way? Is there any other way to handle with this issue?

  • I have two hints. I would probably try to rewrite `doInBackground` so that its returns parsed `ForecastParams` instead of Reader, so you have to parse data in the network thread. A second note, `AsyncTask` has been finally marked as deprecated and its usage is seen as a bad practice. – Michal Harakal Mar 22 '20 at 21:08
  • @MichalHarakal I rewrote `doInBackground` as you mentioned but nothig changed, still `Socket closed`. Is there any convienient way to not load whole JSON to memory or make it streamable? – Przemysław Kłos Mar 23 '20 at 18:55
  • I am not sure, but to avoid error in deserialiazation you can try to download the whole data as a string and parse later. I know, its not optimal, it just will show you that downloading and parsing works right. – Michal Harakal Mar 25 '20 at 17:44
  • I've found suitable code for reading JSON file from link (readUrl method) in this thread: [link](https://stackoverflow.com/questions/14961100/reading-json-from-url-java). My parser works but at least not in proper way I predicted - dts and temps are parsed well, but I have an issue with precipitations, which aren't mentioned in JSON when it' not raining. I've tried to handle nulls like `Double rain = (weather.rain.rainPrep == null) ? 0.0 : weather.rain.rainPrep;' but it doesn't work. Any ideas how to handle with that? – Przemysław Kłos Mar 28 '20 at 20:09

0 Answers0