使用json.simple库读写JSON时如何消除类型安全警告?
问题
编程课任务要求实现一个读写JSON文件的类,使用json.simple库后大量代码出现Type safety warning(类型安全警告)。尝试用ArrayList、HashMap替代JSONArray、JSONObject(二者继承自前者),但问题依旧。希望得到消除警告的方法和任务实现建议。
代码示例
//imports import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.JSONArray; import org.json.simple.parser.ParseException; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.time.LocalDate; import java.util.Collection; import java.util.HashMap; import java.util.ArrayList; import java.util.List; public class ReadAndWrite { /** * This is a class for reading and writing to the userData file stored in the users home directory. * The file is stored in json format. The classes are first converted to json format and then written to the file. * The classes are then read from the file and converted back to the classes. */ /** * For the first version of the application we will only have one user. * This is why we have a dummy name for the user. To parse the classes to json * we are using the json-simple library. JSONObjects */ private static String dummyName = "dummyName"; private static String fileLocation = System.getProperty("user.home") + System.getProperty("file.separator") + "loftUserData.json"; private JSONParser parser = new JSONParser(); private Collection<User> userClasses = new ArrayList<User>(); private Collection<Workout> workoutsClasses = new ArrayList<Workout>(); private Collection<Exercise> exercisesClasses = new ArrayList<Exercise>(); private Collection<Set> setsClasses = new ArrayList<Set>(); /** * Private method for setting up a set class to json format. * @param list of sets * @return ArrayList<HashMap<String, Object>> -> sets in json format */ private ArrayList<HashMap<String, Object>> setSetsJsonArray(List<Set> list) { ArrayList<HashMap<String, Object>> setsArray = new ArrayList<HashMap<String, Object>>(); int i = 0; for (Set set : list) { HashMap<String, Object> setJson = new HashMap<String, Object>(); setJson.put("setNumber", ++i); setJson.put("weight", set.getWeight()); setJson.put("reps", set.getReps()); setsArray.add(setJson); } return setsArray; } /** * Private method for setting up a exercise class to json format. * @param list of exercises * @return ArrayList<HashMap<String, Object>> -> exercises in json format */ private ArrayList<HashMap<String, Object>> setExercisesJsonArray(List<Exercise> list) { ArrayList<HashMap<String, Object>> exercisesArray = new ArrayList<HashMap<String, Object>>(); for (Exercise exercise : list) { HashMap<String, Object> exerciseJson = new HashMap<String, Object>(); exerciseJson.put("exerciseName", exercise.getName()); exerciseJson.put("sets", setSetsJsonArray(exercise.getSets())); exercisesArray.add(exerciseJson); } return exercisesArray; } /** * Private method for setting up a workout class to json format. * @param workout * @return HashMap<String, Object> -> workout in json format */ private HashMap<String, Object> formatWorkoutClassToJson(Workout workout) { HashMap<String, Object> workoutJson = new HashMap<String, Object>(); workoutJson.put("exercises", setExercisesJsonArray(workout.getExercises())); workoutJson.put("date", workout.getDate().toString()); return workoutJson; } //Writing a workout class to the userData file in json format /** * The method to be used for writing a workout class to the userData file in json format. * @param workout */ public void writeWorkoutToUser(Workout workout) { ArrayList<HashMap<String, Object>> existingData = readDataFromFile(); ArrayList<HashMap<String, Object>> users = new ArrayList<HashMap<String, Object>>(); HashMap<String, Object> user = new HashMap<String,Object>(); // Setting up user if (existingData == null) { user.put("name", dummyName); user.put("workouts", new ArrayList<HashMap<String, Object>>()); } else { HashMap<String, Object> userDummy = existingData.get(0); user = userDummy; } // Adding to user HashMap<String, Object> workoutInJSONFormat = this.formatWorkoutClassToJson(workout); ArrayList<HashMap<String, Object>> workoutsJsonArray = (ArrayList<HashMap<String, Object>>) user.get("workouts"); workoutsJsonArray.add(workoutInJSONFormat); users.add(user); JSONArray jsonFormat = new JSONArray(); jsonFormat.addAll(users); try (FileWriter file = new FileWriter(fileLocation)) { file.write(jsonFormat.toJSONString()); file.flush(); } catch (IOException e) { e.printStackTrace(); } } /** * Private method for reconstructing the user class from a JSONArray format. * @param users JSONArray of users * @return ArrayList of users, in our case there is only one user. */ private ArrayList<User> classReconstructor(JSONArray users) { for (Object userObject : users) { JSONObject user = (JSONObject) userObject; String name = (String) user.get("name"); JSONArray workouts = (JSONArray) user.get("workouts"); for (Object workoutObject : workouts) { JSONObject workout = (JSONObject) workoutObject; LocalDate date = LocalDate.parse((String) workout.get("date")); JSONArray exercises = (JSONArray) workout.get("exercises"); for (Object exerciseObject : exercises) { JSONObject exercise = (JSONObject) exerciseObject; String exerciseName = (String) exercise.get("exerciseName"); JSONArray sets = (JSONArray) exercise.get("sets"); for (Object setObject : sets) { JSONObject set = (JSONObject) setObject; int weight = ((Long) set.get("weight")).intValue(); int reps = ((Long) set.get("reps")).intValue(); Set newSet = new Set(weight, reps); setsClasses.add(newSet); } Exercise newExercise = new Exercise(exerciseName); for (Set set : setsClasses) { newExercise.addSet(set); } exercisesClasses.add(newExercise); } Workout newWorkout = new Workout(date); for (Exercise exercise : exercisesClasses) { newWorkout.addExercise(exercise); } workoutsClasses.add(newWorkout); } User newUser = new User(name); for (Workout workout : workoutsClasses) { newUser.addWorkout(workout); } userClasses.add(newUser); } return (ArrayList<User>) userClasses; } /** * Private method for reading data from the file. * @return JSONArray of all users. In our case there is only one user. */ private ArrayList<HashMap<String, Object>> readDataFromFile() { try (FileReader reader = new FileReader(fileLocation)){ if (reader.ready()) { Object obj = parser.parse(reader); JSONArray users = (JSONArray) obj; ArrayList<HashMap<String, Object>> usersList = (ArrayList<HashMap<String, Object>>) users; return usersList; } else { //The file can be empty this is not an error, it just means that there is no data to read. } } catch (FileNotFoundException e) { // If it is not found, it will be created at a later point, so this is fine return null; } catch (IOException e) { e.printStackTrace(); } catch (ParseException e){ e.printStackTrace(); } return null; } /** * The method to be used for getting the user class from the file. * @return User class */ public User returnUserClassFromFile() { ArrayList<HashMap<String, Object>> users = readDataFromFile(); if (users == null) { return new User(dummyName); } JSONArray usersJson = (JSONArray) users; ArrayList<User> user = this.classReconstructor(usersJson); User userClass = user.get(0); return userClass; } }
警告位置及信息
- 代码行:
ArrayList<HashMap<String, Object>> workoutsJsonArray = (ArrayList<HashMap<String, Object>>) user.get("workouts");
- 代码行:
jsonFormat.addAll(users);
- 代码行:
ArrayList<HashMap<String, Object>> usersList = (ArrayList<HashMap<String, Object>>) users;
警告信息:Type safety: Unchecked cast from JSONArray to ArrayList<HashMap<String, Object>>
已尝试用ArrayList和HashMap替代JSONArray和JSONObject,问题未解决。
解决方法与实现建议
一、消除当前警告的临时方案
json.simple是老旧的无泛型支持库,强制类型转换必然触发类型安全警告,可通过以下方式抑制警告:
- 在触发警告的方法上添加注解:
@SuppressWarnings("unchecked"),示例:
@SuppressWarnings("unchecked") public void writeWorkoutToUser(Workout workout) { // 方法内容 }
- 或在单个代码行前添加注解:
@SuppressWarnings("unchecked") ArrayList<HashMap<String, Object>> workoutsJsonArray = (ArrayList<HashMap<String, Object>>) user.get("workouts");
注意:此方法仅隐藏警告,未从根源解决类型不安全问题,适合临时应付课程要求。
二、更优的JSON库选择(推荐)
json.simple设计过时,缺乏泛型支持和对象映射能力,推荐使用现代JSON库从根源避免类型转换问题:
1. Jackson
Java生态主流JSON库,支持对象与JSON自动序列化/反序列化,无需手动处理HashMap和ArrayList转换。
- 核心依赖:
com.fasterxml.jackson.core:jackson-databind - 简化读写示例:
// 写入JSON ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(new File(fileLocation), user); // 直接将User对象写入文件 // 读取JSON User user = mapper.readValue(new File(fileLocation), User.class); // 直接将JSON转为User对象
2. Gson
Google出品的轻量JSON库,使用简单,同样支持对象自动映射。
- 核心依赖:
com.google.code.gson:gson - 简化读写示例:
// 写入JSON Gson gson = new Gson(); String json = gson.toJson(user); // 将json字符串写入文件 // 读取JSON String jsonStr = // 从文件读取字符串 User user = gson.fromJson(jsonStr, User.class);
使用这类库后,无需手动编写formatWorkoutClassToJson、classReconstructor等繁琐转换方法,直接操作实体类即可,完全避免类型转换警告。
三、现有代码的优化建议
若必须继续使用json.simple,除抑制警告外,还可优化以下点:
- 统一使用JSONArray/JSONObject:不要混用JSON结构类与集合类,json.simple的JSONArray继承自ArrayList、JSONObject继承自HashMap,但泛型均为
Object,来回转换本质不安全。建议readDataFromFile直接返回JSONArray:private JSONArray readDataFromFile() { try (FileReader reader = new FileReader(fileLocation)){ if (reader.ready()) { Object obj = parser.parse(reader); return (JSONArray) obj; } } catch (Exception e) { e.printStackTrace(); } return null; } - 避免成员变量数据累积:
userClasses、workoutsClasses等类级成员变量会在多次调用classReconstructor时累积旧数据,应改为方法内局部变量,每次重建时重新初始化:private ArrayList<User> classReconstructor(JSONArray users) { Collection<User> userClasses = new ArrayList<>(); Collection<Workout> workoutsClasses = new ArrayList<>(); // ... 后续逻辑 }
内容的提问来源于stack exchange,提问作者Markus helbæk
相关产品推荐
相关产品推荐

