Gson выдает IllegalStateException при попытке проанализировать список - PullRequest
1 голос
/ 20 марта 2020

Я изучаю постоянство данных, и это моя первая попытка JSON. Я прочитал несколько руководств, и из того, что я могу сказать, код был правильным в обеих попытках сохранения объектов. Я получаю файл, написанный с использованием Gson, но Gson генерирует исключения при попытке проанализировать объекты с помощью метода from Json (). У меня следующий вопрос:

  • Если я использую тот же тип для преобразования в / из JSON, что мне не хватает, что скажет Gson, как правильно анализировать мой объект (ы)?

Я испробовал три разных подхода, два из которых приведены ниже. Сначала я попытался сохранить класс-обертку для списка объектов, которые, как предполагает руководство, я должен уметь делать:

public class JSONConverter {
    private static Path path = Paths.get("src\\json\\JSONList.json");
    private static Type stockType = new TypeToken<StocksList>(){}.getType();

    public static void convertToJSON(StocksList stocks, Path path) {
        Gson json = new Gson();     
        String storedStocks = json.toJson(stocks, stockType);// I also tried "StocksList.class" here            
        checkForFile(path);
        try (BufferedWriter writer = Files.newBufferedWriter(path)) {
            writer.write(storedStocks);
        } catch (IOException e) {
            e.printStackTrace();
            //handle later
        }
    }

    static void checkForFile(Path path) {
        if (Files.notExists(path)) {
            try {
                Files.createFile(path);
            } catch (IOException e) {
                e.printStackTrace();
                //handle later
            }
        }
    }

    public static StocksList convertFromJSON(Path path) {
        StocksList stocksList = new StocksList();
        Gson json = new Gson();
        String fromJson;
        try {
            fromJson = Files.readAllBytes(path).toString();
            stocksList = json.fromJson(fromJson, stockType);
            return stocksList;
        } catch (IOException e) {
            return stocksList;
        }
    }
}

Мой второй подход состоял в том, чтобы вывести список из класса-обертки и попытаться преобразовать его. на JSON:

public class JSONConverter {
    private static Path path = Paths.get("src\\json\\JSONList.json");
    private static Type listType = new TypeToken<List<Stock>>(){}.getType();

    public static void convertToJSON(StocksList stocks, Path path) {
        Gson json = new Gson();     
        List<Stock> temp = stocks.getStocks();
        String storedStocks = json.toJson(temp, listType);
        checkForFile(path);
        try (BufferedWriter writer = Files.newBufferedWriter(path)) {
            writer.write(storedStocks);
        } catch (IOException e) {
            e.printStackTrace();
            //handle later
        }
    }

    static void checkForFile(Path path) {
        if (Files.notExists(path)) {
            try {
                Files.createFile(path);
            } catch (IOException e) {
                e.printStackTrace();
                //handle later
            }
        }
    }


    public static StocksList convertFromJSON(Path path) {
        StocksList stocksList = new StocksList();
        List<Stock> stocks = new ArrayList<>();
        Gson json = new Gson();
        String fromJson;
        try {
            fromJson = Files.readAllBytes(path).toString();
            stocks = json.fromJson(fromJson, listType);
            //wraps the list in the stockslist class
            stocksList.setStocks(stocks);
            return stocksList;
        } catch (IOException e) {
            e.printStackTrace();
            return stocksList;
        }
    }
}

Вот пример JSON, написанный первым методом с использованием второго подхода. Первый выглядит так, за исключением добавления "{" stocks ":" (что вы видите ниже) "}":

[
{
    "ticker": "INTC",
    "currentPrice": "45.94",
    "marginOfSafety": 0.25,
    "lastDate": "2019-12-28",
    "cashYield": "7.4",
    "MCap": "196485365760",
    "enterpriseValue": "281213850000",
    "sharesOut": "4417000000",
    "oddPercentGrowth": false,
    "newCompany": false,
    "safeValue": "51.35",
    "fairValue": "68.47",
    "evEbitda": "8.56",
    "fcf": [
        "16932000000",
        "14611750000"
    ],
    "rOnAssets": "21",
    "rOnCapital": "20",
    "croic": "16.47",
    "equityToDebt": "3.0",
    "cashOnHand": "4194000000",
    "cashToDebt": "0.17",
    "changeInDebt": "210000000",
    "capEfficiency": [
        "18",
        "7",
        "-26",
        "-21",
        "1"
    ],
    "fcfChange": [
        "18.81",
        "11.71"
    ],
    "profitMargin": [
        "46",
        "38"
    ]
},
{
    "ticker": "HCC",
    "currentPrice": "12.99",
    "marginOfSafety": 0.5,
    "lastDate": "2018-12-31",
    "cashYield": "46.1",
    "MCap": "664587904",
    "enterpriseValue": "1572623480",
    "sharesOut": "52812000",
    "oddPercentGrowth": true,
    "newCompany": true,
    "safeValue": "236.94",
    "fairValue": "473.87",
    "evEbitda": "2.59",
    "fcf": [
        "457776000",
        "306126750"
    ],
    "rOnAssets": "49",
    "rOnCapital": "59",
    "croic": "38.77",
    "equityToDebt": "1.0",
    "cashOnHand": "205577000",
    "cashToDebt": "0.44",
    "changeInDebt": "125283000",
    "capEfficiency": [
        "292",
        "798",
        "-365",
        "-397",
        "-1"
    ],
    "fcfChange": [
        "33.9",
        "33.9"
    ],
    "profitMargin": [
        "40",
        "8"
    ]
}
]

Оба броска:

com.google.gson .JsonSyntaxException: java .lang.IllegalStateException: ожидалось BEGIN_OBJECT, но было STRING в строке 1 столбца 12

(эта строка изменяется на «Ожидаемый BEGIN_OBJECT, но была BEGIN_ARRAY в строке 1 столбца 2» при использовании первый подход). в

com.google.gson.internal.bind.ReflectiveTypeAdapterFactory $ Adapter.read (ReflectiveTypeAdapterFactory. java: 176) ...

я собирался попробуйте добавить каждый объект по отдельности в JSONArray, но когда у меня возникли проблемы, я решил просто спросить. В руководстве упоминалось, что рефлексия была важна, и я предполагаю, что моя проблема в этом заключается из-за второй строки трассировки стека, но опять же, я впервые пытаюсь использовать JSON. Если я забыл включить что-либо, дайте мне знать, и я опубликую это в комментарии.

Спасибо за помощь.

ADDENDUM: объекты выдают эти исключения только при записи и извлечении из файла. Они не бросают при преобразовании в JSON String, а затем снова обратно. Это происходит независимо от того, использую ли я Files.write () или Files.newBufferedWriter ().

1 Ответ

0 голосов
/ 12 апреля 2020

Спасибо всем, кто просмотрел мой вопрос. Я обратился к странице Gson Github, и они ответили со следующими исправлениями для моего класса:

Весь код, который вы предоставили, может быть значительно исправлен, улучшен и подвергнут рефакторингу.

Нет необходимо создать несколько экземпляров Gson: их создание относительно дорого, но они предназначены для многопоточной обработки и неизменяемости, поэтому их можно использовать повторно. Не нужно сериализовать и десериализовать из java .lang.String - это просто дорого, если нужно создать несколько строк в куче, просто тратя кучу и время снижая производительность. Почему в вашем случае это не работает, так это то, что Files.readAllBytes (...) возвращает byte [], который вы пытаетесь преобразовать в строку. В Java нет массивов с интуитивно понятной реализацией toString (вы можете проверить это, просто распечатав любой байтовый массив в System.out). Чтобы преобразовать его в строку (это может быть экземпляр, потребляющий память), новый String (byte []) (или даже новая String (byte [], Charset)) является подходящим способом. Я действительно не помню, как работают файлы, но, вероятно, нет необходимости проверять наличие файла: они могут быть перезаписаны без каких-либо дополнительных проверок. В этом случае токены типов не нужны: StockList.class также является типом. По сути, все, что вам нужно, это просто так:

private static final Gson gson = new GsonBuilder()
    .disableHtmlEscaping()
    .disableInnerClassSerialization()
    .create();

public static void main(final String... args)
        throws IOException {
    final StocksList before = new StocksList(ImmutableList.of(new Stock("INTC"), new 
 Stock("HCC")));
    final Path path = Paths.get("doc.json");
    write(path, before);
    final StocksList after = read(path);
    System.out.println(after.equals(before));
}

private static void write(final Path path, final StocksList stocks)
        throws IOException {
    try ( final Writer writer = new OutputStreamWriter(new 
FileOutputStream(path.toFile())) ) {
        gson.toJson(stocks, writer);
     }
}

 private static StocksList read(final Path path)
        throws IOException {
    try ( final Reader reader = new InputStreamReader(new 
 FileInputStream(path.toFile())) ) {
         return gson.fromJson(reader, StocksList.class);
    }
}

Спасибо Любомир-Шайдарив (сотрудник Gson) за ответ.

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