如何读取JSON文件中API返回数组内enrollments下的user_id?
解决Gson读取JSON数组提取user_id的问题
问题场景
已通过FileWriter和com.google.gson包将API返回数据保存到Courses.json文件,需要提取enrollments下的user_id数据,但编写的读取代码报错。
精简后的Courses.json内容
[ { "access_restricted_by_date":true, "id":3155 }, { "access_restricted_by_date":true, "id":4604 }, { "access_restricted_by_date":true, "id":4655 }, { "root_account_id":1, "storage_quota_mb":50000, "template":false, "end_at":null, "public_syllabus_to_auth":false, "public_syllabus":false, "created_at":"2022-08-11T18:00:41Z", "start_at":null, "enrollment_term_id":180, "uuid":"MC24SbWdGDjeKTalLT5T5V41Foh0jD4EybOFG8xY", "course_code":"Study Hall", "course_color":null, "grading_standard_id":null, "workflow_state":"available", "id":6312, "homeroom_course":false, "default_view":"assignments", "is_public_to_auth_users":false, "grade_passback_setting":null, "enrollments":[ { "role":"StudentEnrollment", "enrollment_state":"active", "role_id":3, "user_id":9999, "type":"student", "limit_privileges_to_course_section":false } ], "blueprint":false, "license":"private", "is_public":false } ]
错误代码及报错信息
尝试读取id的代码:
import java.io.*; import com.google.gson.*; import com.google.gson.stream.*; import java.io.IOException; public class CourseGradeReader { public static void main(String args[]) { JsonReader reader; try { reader = new JsonReader(new FileReader("Courses.json")); reader.beginArray(); while(reader.hasNext()) { String name = reader.nextName(); if(name.equals("id")) { System.out.println(reader.nextString()); reader.endArray(); } else { reader.skipValue(); } } reader.endObject(); reader.close(); } catch(Exception e) { e.printStackTrace(); } } }
运行后报错:
java.lang.IllegalStateException: 预期是名称但实际是BEGIN_OBJECT,位于第1行第3列路径$[0] at com.google.gson.stream.JsonReader.nextName(JsonReader.java:790) at org.example.CourseGradeReader.main(CourseGradeReader.java:12)
错误原因
代码逻辑错误:JSON最外层是数组,数组内的每个元素是对象,调用reader.beginArray()后,当前指针指向数组的第一个对象起始位置(BEGIN_OBJECT),此时直接调用nextName()会报错,因为nextName()只能在对象的键名位置调用。另外,id是数字类型,用nextString()也会导致类型不匹配。
解决方案
方案1:修正流式JsonReader代码
按照JSON的层级结构,嵌套处理数组和对象:
import java.io.FileReader; import com.google.gson.stream.JsonReader; public class CourseGradeReader { public static void main(String args[]) { try (JsonReader reader = new JsonReader(new FileReader("Courses.json"))) { reader.beginArray(); while (reader.hasNext()) { reader.beginObject(); // 开始处理数组中的单个课程对象 while (reader.hasNext()) { String name = reader.nextName(); if (name.equals("id")) { // id是数字类型,使用nextLong()/nextInt()读取 System.out.println("课程ID: " + reader.nextLong()); } else if (name.equals("enrollments")) { // 处理enrollments数组 reader.beginArray(); while (reader.hasNext()) { reader.beginObject(); while (reader.hasNext()) { String enrollName = reader.nextName(); if (enrollName.equals("user_id")) { System.out.println("用户ID: " + reader.nextLong()); } else { reader.skipValue(); // 跳过不需要的字段 } } reader.endObject(); } reader.endArray(); } else { reader.skipValue(); // 跳过课程对象中其他不需要的字段 } } reader.endObject(); } reader.endArray(); } catch (Exception e) { e.printStackTrace(); } } }
方案2:使用Gson对象映射(更简洁)
定义与JSON结构对应的实体类,让Gson自动完成映射,代码可读性更高:
import java.io.FileReader; import java.util.List; import com.google.gson.Gson; import com.google.gson.annotations.SerializedName; // 课程实体类,仅定义需要的字段 class Course { private long id; @SerializedName("enrollments") private List<Enrollment> enrollments; public long getId() { return id; } public List<Enrollment> getEnrollments() { return enrollments; } } // 选课实体类 class Enrollment { @SerializedName("user_id") private long userId; public long getUserId() { return userId; } } public class CourseGradeReader { public static void main(String args[]) { try (FileReader reader = new FileReader("Courses.json")) { Gson gson = new Gson(); // 将JSON数组直接转换为Course对象数组 Course[] courses = gson.fromJson(reader, Course[].class); for (Course course : courses) { System.out.println("课程ID: " + course.getId()); if (course.getEnrollments() != null) { for (Enrollment enrollment : course.getEnrollments()) { System.out.println("用户ID: " + enrollment.getUserId()); } } } } catch (Exception e) { e.printStackTrace(); } } }
说明
- 方案1适合处理超大JSON文件,内存占用低;
- 方案2代码简洁,维护成本低,适合大多数场景。
内容的提问来源于stack exchange,提问作者Evan Sakryd
相关产品推荐
相关产品推荐

