Why is JSON document not fully consumed?
Asked Answered
H

3

9

I'm trying to retrieve JSON data from an external source for practice. I have gotten all the code in place but for some reason I get an error saying that the document is not fully consumed. I have watched and read multiple tutorials and guides, but still can't seem to get it right. I have also searched stack for answers, but since I don't know what's wrong, I don't really know what to look for.

All the code is in place and there is no obvious fault in it. The JSON data has been validated and it works to retrieve as raw JSON data, as seen in a log. The problem occur at the Gson conversion when the data should be transferred to a java data class. Any ideas what could be wrong?

public class JSONimport extends AsyncTask<Void, Void, DeserializedContainer> {

private static final String TAG = "TAG";

//VARIABLES TO HOLD JSON DATA
private OnLoadListener mListener;


//CONSTRUCTOR
public JSONimport(OnLoadListener listener) {
    this.mListener = listener;
}

//ASYNK, DO IN BACKGROUND THREAD
@Override
protected DeserializedContainer doInBackground(Void... voids) {
    String myJSON = ""; //TEMP VARIABLE TO HOLD JSON DATA
    String completeJSONdata = ""; //VARIABLE TO HOLD COMPLETE JSON DATA

    try {
        URL urlObject = new URL( "https://api.myjson.com/bins/161kkd" );
        HttpURLConnection httpURLConnection = (HttpURLConnection) urlObject.openConnection();
        InputStream inputStreamObject = httpURLConnection.getInputStream();
        BufferedReader bufferedReaderObject = new BufferedReader( new InputStreamReader( inputStreamObject ) );

        while (myJSON != null) {
            myJSON = bufferedReaderObject.readLine();
            completeJSONdata += myJSON;
        }

    } catch (MalformedURLException e) {
        e.printStackTrace();
        Log.d( TAG, "doInBackground: ERROR RETRIEVING URL" );
    } catch (IOException e) {
        e.printStackTrace();
        Log.d( TAG, "doInBackground: ERROR HTTP CONNECTION" );
    }


    //DESERIALIZATION, converting JSON to java variables, making the data easy to handle
    Gson gsonObject = new GsonBuilder()
            .setLenient()
            .create();
    DeserializedContainer deserializedContainerObject;

    deserializedContainerObject = gsonObject.fromJson( completeJSONdata, DeserializedContainer.class );
    //Log.d( TAG, "doInBackground: " + deserializedContainerObject.getDeserializedContainerList() );


    return deserializedContainerObject;
}

@Override
protected void onPostExecute(final DeserializedContainer result) {

    mListener.onSuccess( result );
    //FUNKAR ATT HÄMTA JSON DATA. KOLLA LOGCAT
    Log.d( TAG, "onPostExecuteLOL: " + result );
}

public static interface OnLoadListener {
    void onSuccess(DeserializedContainer container);
}}

The error is at deserializedContainerObject = gsonObject.fromJson( completeJSONdata, DeserializedContainer.class );

The data objects to hold the JSON data:

public class DeserializedContainer {
@SerializedName("deserializedContainerList")
public List<DeserializedVariables> deserializedContainerList = new ArrayList<>();

public List<DeserializedVariables> getDeserializedContainerList() {
    return deserializedContainerList;
}}

public class DeserializedVariables {
@SerializedName( "movieName" )
private String movieName;
@SerializedName( "movieYear" )
private int movieYear;
@SerializedName( "movieRating" )
private double movieRating;}

Relevant data from the main thread:

public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate( savedInstanceState );
    setContentView( R.layout.activity_main );

    //BACKGROUND THREAD
    JSONimport jsonImportObject = new JSONimport( new JSONimport.OnLoadListener() {
        @Override
        public void onSuccess(DeserializedContainer container) {
            container.getDeserializedContainerList();
        }
    } );
    jsonImportObject.execute();

    //Log.d( TAG, "onCreateGETTING DATA : " + jsonImportObject.getCompletedData());

    DeserializedContainer deserializedContainerObject = new DeserializedContainer();
    Log.d( TAG, "onCreate: " + deserializedContainerObject);

JSON:

{"deserializedContainerList":[{"movieName":"filmA","movieYear":2017,"movieRating":4.7},{"movieName":"filmB","movieYear":2018,"movieRating":4.8},{"movieName":"filmC","movieYear":2019,"movieRating":4.9}]}

Sorry for such a long post, hope you have the energy to go through it. I'm really stuck. I know of Retrofit and similar libraries, but I have spent so many hours on getting this right that I don't want to abandon it just yet :P

Thanks!

/////// UPDATE /////// I updated the code according to Laurent B's suggestion, and it worked! Or, at least it didn't crash. I tried printing the list on the main thread with the following code:

for(int i = 0; i < deserializedContainerObject.deserializedContainerList.size(); i++) {
        Log.d( TAG, "onCreate: " + deserializedContainerObject.deserializedContainerList.get( i ));

    }

But nothing showed. When checking deserializedContainerObject.deserializedContainerList.size() it showed 0. That is, no data has been added to the list... Hmmm. At least it doesn't crash, thanks to Laurent B so one step closer.

Hagberry answered 18/1, 2018 at 13:19 Comment(2)
Are you checking the object inside your onSuccess method DeserializedContainer container? deserializedContainerObject is declared outside of your onSuccess method so it makes sense that it's list has a size of 0.Sahib
@Joakim Sjöstedt check my answer..Pounds
P
1

The value is being pass, but however null is also getting passed with it so use an if statement rather than using while like this..

if (myJSON != null) {
                myJSON = bufferedReaderObject.readLine();
                completeJSONdata += myJSON;
            }

then convert in Gson like this..

    Gson gson = new Gson();
    deserializedContainerObject = gson.fromJson(completeJSONdata, DeserializedContainer.class);

write the getters and setters in DeserializedVariables class

public String getMovieName() {
         return movieName;
     }

     public void setMovieName(String movieName) {
         this.movieName = movieName;
     }

     public Integer getMovieYear() {
         return movieYear;
     }

     public void setMovieYear(Integer movieYear) {
         this.movieYear = movieYear;
     }

     public Double getMovieRating() {
         return movieRating;
     }

     public void setMovieRating(Double movieRating) {
         this.movieRating = movieRating;
     }

And now you can retrieve it in your onPostExecute() like this..

@Override
    protected void onPostExecute( DeserializedContainer result) {

        mListener.onSuccess( result );

        for (int i = 0; i <result.deserializedContainerList.size(); i++) {
            DeserializedVariables deserializedVariables = result.deserializedContainerList.get(i);
            Log.d( TAG, "onPostExecuss: " + deserializedVariables.getMovieName() );
        }

    }
Pounds answered 19/1, 2018 at 6:33 Comment(1)
AWESOME! It finally worked! Thank you so much for helping me, both visas singh and Laurent B! :) Now I can move on with my project YAY! :D :D :DTriphammer
E
1

Your completeJSONdata is incorrect as you are always putting "null" towards the end.

Instead your while clause should be for example :

        while ((myJSON = bufferedReaderObject.readLine()) != null) {
            completeJSONdata += myJSON;
        }

By the way, don't forget to close your streams for instance by using a try with :

try (InputStream inputStreamObject = httpURLConnection.getInputStream()) {
// ...
}
Enrichment answered 18/1, 2018 at 13:41 Comment(1)
Holy cow! It doesn't crash anymore :) It worked! Thanks a bunch Laurent! However, a new problem seems to have emerged - see the end off main thread.Triphammer
P
1

The value is being pass, but however null is also getting passed with it so use an if statement rather than using while like this..

if (myJSON != null) {
                myJSON = bufferedReaderObject.readLine();
                completeJSONdata += myJSON;
            }

then convert in Gson like this..

    Gson gson = new Gson();
    deserializedContainerObject = gson.fromJson(completeJSONdata, DeserializedContainer.class);

write the getters and setters in DeserializedVariables class

public String getMovieName() {
         return movieName;
     }

     public void setMovieName(String movieName) {
         this.movieName = movieName;
     }

     public Integer getMovieYear() {
         return movieYear;
     }

     public void setMovieYear(Integer movieYear) {
         this.movieYear = movieYear;
     }

     public Double getMovieRating() {
         return movieRating;
     }

     public void setMovieRating(Double movieRating) {
         this.movieRating = movieRating;
     }

And now you can retrieve it in your onPostExecute() like this..

@Override
    protected void onPostExecute( DeserializedContainer result) {

        mListener.onSuccess( result );

        for (int i = 0; i <result.deserializedContainerList.size(); i++) {
            DeserializedVariables deserializedVariables = result.deserializedContainerList.get(i);
            Log.d( TAG, "onPostExecuss: " + deserializedVariables.getMovieName() );
        }

    }
Pounds answered 19/1, 2018 at 6:33 Comment(1)
AWESOME! It finally worked! Thank you so much for helping me, both visas singh and Laurent B! :) Now I can move on with my project YAY! :D :D :DTriphammer
H
0

For people who are still struggling with this exception: The only solution that worked for me is to pretty-print the JSON before I give it to Gson (I had a hunch that maybe there is something wrong with the format itself although it wasn't throwing a JsonMalformattedError). Here's the code that worked for me :

val jsonPretty = JSONObject(jsonString).toString(2)

You can go ahead and pass jsonPretty as a string to Gson. This made GSON consume the JSON document fully. I believe the library struggles with extremely incoherent JSONs (for example, when there are too many white spaces or something). Im not sure why, but this worked for me at least.

Harumscarum answered 22/7, 2023 at 6:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.