[英]Gson throws IllegalStateException when attempting to parse List
我正在學習數據持久性,這是我第一次嘗試 JSON。 我已經閱讀了一些指南,從我可以看出的代碼在存儲對象的兩次嘗試中都是正確的。 我得到了使用 Gson 編寫的文件,但是當嘗試使用 fromJson() 方法解析對象時,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 示例。 第一個看起來像它除了添加“{“股票”:”(你在下面看到的)“}”:
[
{
"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,但在第 1 行第 12 列處為 STRING
(當使用第一種方法時,此行更改為“預期的 BEGIN_OBJECT 但在第 1 行第 2 列處為 BEGIN_ARRAY”)。 在
com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176) ...
我打算嘗試將每個對象單獨添加到 JSONArray 中,但是當我開始在那里遇到麻煩時,我想我應該問一下。 該指南提到反射很重要,我猜測我的問題在於堆棧跟蹤的第二行,但同樣,這是我第一次嘗試使用 JSON。 如果我忘記包含任何內容,請告訴我,我會在評論中發布。
謝謝您的幫助。
附錄:對象僅在寫入文件和從文件中提取時才會拋出這些異常。 它們在轉換為 JSON 字符串然后再返回時不會拋出。 無論我使用 Files.write() 還是 Files.newBufferedWriter() 都會發生這種情況。
感謝所有看過我問題的人。 我聯系了 Gson 的 github 頁面,他們對我的班級做出了以下更正:
您提供的所有代碼都可以得到極大的修復、改進和重構。
無需創建多個 Gson 實例:實例化它們的成本相對較高,但被設計為線程安全且不可變的,因此可以重用。 不需要從 java.lang.String 序列化和反序列化——這只是昂貴的,因為它必須在堆中創建多個字符串,而這只是浪費堆和時間降低性能。 為什么它在您的情況下不起作用是 Files.readAllBytes(...) 返回 byte[] 您試圖轉換為字符串。 在 Java 中,沒有任何數組具有直觀的 toString 實現(您可以通過簡單地將任何字節數組打印到 System.out 來檢查它)。 為了將其轉換為字符串(這可能是一個消耗內存的實例),new String(byte[])(甚至 new 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);
}
}
感謝 lyubomyr-shaydariv(Gson 貢獻者)的回答。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.