Gson сохраняет JSON на диск и загружает обратно в память - PullRequest
0 голосов
/ 28 февраля 2019

Я сохраняю свой JSONObject на диск, а затем при попытке загрузить его обратно в JSONObject я получаю следующее исключение в этой строке метода loadSavedScheduleFromDisk:

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

com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: неопределенная строка в столбце строки 1 74040 путь $ .nameValuePairs..values ​​[32] .values ​​[2] .nameValuePairs.disciplineVersionId

Вот мой код:

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

Это довольно симметрично, и я не могу понять, почему это не работает - я думаю, что если я использую API для сохранения моего JSONObject на диск, и он сохраняет ОК, тогдапочему я не могу загрузить те же данные обратно?

1 Ответ

0 голосов
/ 01 марта 2019

Я думаю, что проблема в том, что вы не закрываете WRITER или адаптер по умолчанию меняет ваши данные

ошибка указывает, что у вас плохо закрыт JSON, возможно, ваш объект не был сжат правильно или экранирование строки было неверным

это мое предложение, и мои тесты проходят мимо меня

Я создаю JSONFileUtil и использую AutoCloseable. Если вам нужно закрыть поток, то рекомендуется использовать инструкцию try-with-resources ссылка

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

}

И MyDTO

import java.util.Date;

public class MyDTO {

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

и мой тест

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

    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...