Gson解析API返回数据遇MalformedJsonException问题求助
问题:Gson解析API响应时触发JSON格式错误
API返回的响应数据
[{attendanceWithTaskCount=[{InstallerPresent=3.0, TotalTaskDone=8.0}], installersDetails=[{InstallerName=abc- fjd, JobType=erret, TaskCount=6.0}]}]
用于解析的代码
public void installersAttendanceWithTaskCount(String date) { TaskController.getInstance(SupervisorTaskSummaryActivity.this).installersAttendanceWithTaskCount(SupervisorTaskSummaryActivity.this, String.valueOf(UserInfo.getUserInfo().getUserId()), date, new IActionCallback() { @Override public void onSuccess(Object data) { try { Gson gson = new Gson(); Log.d("API response: ", String.valueOf(data)); // Parse the response JSON as an array JsonArray jsonArray = gson.fromJson(String.valueOf(data), JsonArray.class); Log.d("API jsonArray: ", String.valueOf(jsonArray)); if (jsonArray.size() > 0) { // Extract the first object from the array JsonObject jsonObject = jsonArray.get(0).getAsJsonObject(); // Extract data from "installersDetails" array JsonArray installersArray = jsonObject.getAsJsonArray("installersDetails"); if (installersArray.size() > 0) { installerAttendanceWithTaskCountList = new ArrayList<>(); for (JsonElement item : installersArray) { if (item.isJsonObject()) { JsonObject taskSummary = item.getAsJsonObject(); String InstallerName = taskSummary.get("InstallerName").getAsString(); // Replace spaces in the InstallerName field with underscores //InstallerName = InstallerName.replaceAll(" ", "_"); String JobType = taskSummary.get("JobType").getAsString(); Double TaskCount = taskSummary.get("TaskCount").getAsDouble(); installerAttendanceWithTaskCountModel model = new installerAttendanceWithTaskCountModel(InstallerName, JobType, TaskCount); installerAttendanceWithTaskCountList.add(model); } } // Creating RecyclerView adapter and setting it installerAttendaceWithTaskCountAdapter adapter = new installerAttendaceWithTaskCountAdapter(SupervisorTaskSummaryActivity.this, installerAttendanceWithTaskCountList); recycler_view.setAdapter(adapter); } } } catch (Exception e) { e.printStackTrace(); } } @Override public void onFailure(int errorCode, final String errorMessage) { runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(SupervisorTaskSummaryActivity.this, errorMessage, Toast.LENGTH_SHORT).show(); } }); } }); }
错误日志
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 118 path $[0].installersDetails[0].InstallerName 2023-09-27 17:01:03.416 22744-22744 System.err W at com.google.gson.internal.Streams.parse(Streams.java:56) 2023-09-27 17:01:03.416 22744-22744 System.err W at com.google.gson.JsonParser.parse(JsonParser.java:84) 2023-09-27 17:01:03.416 22744-22744 System.err W at com.google.gson.JsonParser.parse(JsonParser.java:59) 2023-09-27 17:01:03.416 22744-22744 System.err W at com.google.gson.JsonParser.parse(JsonParser.java:45) 2023-09-27 17:01:03.417 22744-22744 System.err W at .view.SupervisorTaskSummary.SupervisorTaskSummaryActivity$2.onSuccess(SupervisorTaskSummaryActivity.java:135) 2023-09-27 17:01:03.417 22744-22744 System.err W at .coreengine.controllers.TaskController$30.onSuccess(TaskController.java:3229) 2023-09-27 17:01:03.417 22744-22744 System.err W at .coreengine.controllers.TaskController$30.onSuccess(TaskController.java:3223) 2023-09-27 17:01:03.417 22744-22744 System.err W at .coreengine.webapi.CommProvider$1.onResponse(CommProvider.java:118) 2023-09-27 17:01:03.417 22744-22744 System.err W at .coreengine.webapi.GsonRequest.deliverResponse(GsonRequest.java:120) 2023-09-27 17:01:03.417 22744-22744 System.err W at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:102) 2023-09-27 17:01:03.417 22744-22744 System.err W at android.os.Handler.handleCallback(Handler.java:942) 2023-09-27 17:01:03.417 22744-22744 System.err W at android.os.Handler.dispatchMessage(Handler.java:99) 2023-09-27 17:01:03.417 22744-22744 System.err W at android.os.Looper.loopOnce(Looper.java:223) 2023-09-27 17:01:03.417 22744-22744 System.err W at android.os.Looper.loop(Looper.java:324) 2023-09-27 17:01:03.417 22744-22744 System.err W at android.app.ActivityThread.main(ActivityThread.java:8385) 2023-09-27 17:01:03.417 22744-22744 System.err W at java.lang.reflect.Method.invoke(Native Method) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:582) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1059) 2023-09-27 17:01:03.418 22744-22744 System.err W Caused by: com.google.gson.stream.MalformedJsonException: Unterminated object at line 1 column 118 path $[0].installersDetails[0].InstallerName 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.stream.JsonReader.syntaxError(JsonReader.java:1573) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:495) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.stream.JsonReader.hasNext(JsonReader.java:418) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.internal.bind.TypeAdapters$25.read(TypeAdapters.java:666) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.internal.bind.TypeAdapters$25.read(TypeAdapters.java:659) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.internal.bind.TypeAdapters$25.read(TypeAdapters.java:667) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.internal.bind.TypeAdapters$25.read(TypeAdapters.java:659) 2023-09-27 17:01:03.418 22744-22744 System.err W at com.google.gson.internal.bind.TypeAdapters$25.read(TypeAdapters.java:642) 2023-09-27 17:01:03.419 22744-22744 System.err W at com.google.gson.internal.Streams.parse(Streams.java:44) 2023-09-27 17:01:03.419 22744-22744 System.err W ... 17 more
核心原因
你日志里打印的API响应不是标准JSON格式:标准JSON要求所有键名、字符串值必须用双引号包裹,而当前响应里的attendanceWithTaskCount、InstallerName等键,以及abc- fjd这类字符串值都没有双引号,Gson无法识别这种非标准格式,才会抛出解析错误。
解决方法
方案1:修改API返回标准JSON
让后端返回符合规范的JSON,示例如下:
[{"attendanceWithTaskCount":[{"InstallerPresent":3.0,"TotalTaskDone":8.0}],"installersDetails":[{"InstallerName":"abc- fjd","JobType":"erret","TaskCount":6.0}]}]
修改后你的现有解析代码就能正常工作。
方案2:手动转换非标准格式为标准JSON
如果无法修改API,在解析前对响应字符串做正则替换,给键和字符串值补上双引号:
@Override public void onSuccess(Object data) { try { Gson gson = new Gson(); String rawResponse = String.valueOf(data); // 给键名加上双引号,匹配类似key=的模式 rawResponse = rawResponse.replaceAll("(\\w+)=([^\\[,\\]{}]+)", "\"$1\":\"$2\""); // 移除数值类型的多余引号(比如3.0不需要双引号) rawResponse = rawResponse.replaceAll(":\"(\\d+\\.\\d+)\"", ":$1"); JsonArray jsonArray = gson.fromJson(rawResponse, JsonArray.class); // 后续解析逻辑不变... } catch (Exception e) { e.printStackTrace(); } }
注意:这种正则适配是基础版,如果响应里包含特殊字符(比如字符串里的逗号、括号),需要调整正则表达式来覆盖更多场景。
方案3:使用实体类直接映射
定义对应的数据实体类,让Gson直接完成映射,避免手动解析的繁琐:
// 顶层响应实体 public class AttendanceResponse { private List<AttendanceTaskCount> attendanceWithTaskCount; private List<InstallerDetail> installersDetails; // getter、setter方法 public static class AttendanceTaskCount { private double InstallerPresent; private double TotalTaskDone; // getter、setter } public static class InstallerDetail { private String InstallerName; private String JobType; private double TaskCount; // getter、setter } }
然后在解析时直接转换:
List<AttendanceResponse> responseList = gson.fromJson(rawResponse, new TypeToken<List<AttendanceResponse>>(){}.getType()); // 从responseList中提取数据到你的列表 installerAttendanceWithTaskCountList = new ArrayList<>(); if (!responseList.isEmpty()) { for (InstallerDetail detail : responseList.get(0).getInstallersDetails()) { installerAttendanceWithTaskCountList.add(new installerAttendanceWithTaskCountModel( detail.getInstallerName(), detail.getJobType(), detail.getTaskCount() )); } } // 后续设置适配器逻辑不变
内容的提问来源于stack exchange,提问作者Moin Khan
相关产品推荐
相关产品推荐

