Ivan
Ivan

Reputation: 6608

Gson saving JSON to disk and loading back to memory

I'm saving my JSONObject to disk and then when I try to load it back to JSONObject, I get the following exception on this line of the loadSavedScheduleFromDisk method:

JSONObject jsonObject = gson.fromJson(reader, JSONObject.class);

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated string at line 1 column 74040 path $.nameValuePairs..values[32].values[2].nameValuePairs.disciplineVersionId

Here is my code:

private void loadSavedScheduleFromDisk(Activity act) {
    try {
        File file = new File(((Context)act).getCacheDir()+"/"+SCHED_CACHE_FILENAME);

        Gson gson = new Gson();
        InputStreamReader freader = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
        JsonReader reader = new JsonReader(freader);//new FileReader(file));
        reader.setLenient(true);
        JSONObject jsonObject = gson.fromJson(reader, JSONObject.class);
        parseSchedule(jsonObject);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

private void saveScheduleToDisk(Activity act, JSONObject jsonObject )
{
    try {
        File file = new File(((Context)act).getCacheDir()+"/"+SCHED_CACHE_FILENAME);

        //Writer writer = new FileWriter(file);
        Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8"));
        Gson gson = new GsonBuilder().create();
        gson.toJson(jsonObject, writer);

    } catch (Exception e) {
        e.printStackTrace();
    }
}

It is quite symmetrical and I can't understand why it doesn't work - I think if I use API to save my JSONObject to disk and it saves OK, then how come I can't load same data back?

Upvotes: 0

Views: 942

Answers (1)

DEV-Jacol
DEV-Jacol

Reputation: 607

I think the problem is that you do not close WRITER or the default adapter change your data

the error indicates that you have a badly closed JSON maybe your object has not been compressed correctly or String escape was incorrect

this is my proposition and my tests pass me

I create JSONFileUtil and I use AutoCloseable If you need to close a stream, then best practice would be to use the try-with-resources statement link

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;

public class JSONFileUtil {

    public void save(File file, MyDTO myDto) {
        try (Writer writer = new OutputStreamWriter(new FileOutputStream(file), Charset.forName("UTF-8"))) {
            writer.write(new Gson().toJson(myDto));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public MyDTO load(File file) {
        try (InputStreamReader freader = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"))) {
            JsonReader reader = new JsonReader(freader);
            return new Gson().fromJson(reader, MyDTO.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

And MyDTO

import java.util.Date;

public class MyDTO {

    public String valueString;
    public Long valueLong;
    public Date valueDate;
}

and my test

import java.io.File;
import java.util.Date;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

public class JSONFileUtilTest {

    @Test
    public void saveAndLoad() {
        //given:
        MyDTO myDTO = new MyDTO();
        myDTO.valueString = "aaa";
        myDTO.valueLong = 4L;
        myDTO.valueDate = new Date(1551427491625L);
        File cacheFile = new File("cache" + File.separator + "name.json");
        //when:
        JSONFileUtil jsonFileUtil = new JSONFileUtil();
        jsonFileUtil.save(cacheFile, myDTO);
        MyDTO resultMyDto = jsonFileUtil.load(cacheFile);
        //then:
        assertEquals(myDTO.valueLong, resultMyDto.valueLong);  //4
        assertEquals(myDTO.valueString, resultMyDto.valueString);  // "aaa"
        assertEquals(myDTO.valueDate.toString(), resultMyDto.valueDate.toString());  // "Mar 1, 2019 9:04:51 AM" OK
        assertNotEquals(myDTO.valueDate.getTime(), resultMyDto.valueDate.getTime()); // it not 1551427491625L but 1551427491000L --> 1551427491625L because the default date format does not store milliseconds 
        //to store this you need to write your adapter

    }
}

Upvotes: 1

Related Questions