Why is JSON document not fully consumed?

17,848

Solution 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() );
        }

    }

Solution 2

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()) {
// ...
}
Share:
17,848
Joakim Sjöstedt
Author by

Joakim Sjöstedt

Updated on June 26, 2022

Comments

  • Joakim Sjöstedt
    Joakim Sjöstedt almost 2 years

    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.