提问人:Markus helbæk 提问时间:9/19/2023 最后编辑:JensMarkus helbæk 更新时间:9/19/2023 访问量:33
类型安全:从 JSONArray 到 ArrayList<HashMap<String、Object 的未经检查的强制转换>>
Type safety: Unchecked cast from JSONArray to ArrayList<HashMap<String, Object>>
问:
在我的一门编程课程中,我的任务是创建一个类,该类将 json 读取并将 json 写入文件。
我使用了 json.simple 库,但很快意识到几乎所有行都收到了“类型安全警告”?
然后我尝试尽可能多地使用 ArrayList 和 HashMap,因为 JSONObject 和 JSONArray 扩展了这些。据我了解,这是一个问题。
我对编程很陌生,非常感谢能提供一些提示,包括我如何解决任务。
如何摆脱这些类型的安全警告?
我的代码:
`
//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;
我尝试使用 ArrayList 和 HashMap 而不是 JSONArray 和 JSONObject
答:
1赞
M. Pour
9/19/2023
#1
您遇到的类型安全警告是因为您正在使用 HashMap<String 和 Object 的集合>并尝试将它们转换为更具体的类型。虽然可以进行这种强制转换,但它不是类型安全的,因为集合的泛型类型未显式定义,从而导致未经检查的类型转换。
为了摆脱这些类型安全警告,你应该考虑使用JSON库,这些库允许你直接使用Java对象,比如谷歌的Gson或Jackson。这些库将允许您将 JSON 数据直接映射到 Java 类,并避免强制转换问题。
以下是使用 Gson 库重构代码的方法:
- 将 Gson 依赖项添加到项目中(如果尚未添加)
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version> <!-- Use the latest version -->
</dependency>
- 重构 ReadAndWrite 类以使用 Gson:
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
public class ReadAndWrite {
private static String dummyName = "dummyName";
private static String fileLocation = System.getProperty("user.home") + System.getProperty("file.separator") + "loftUserData.json";
private Gson gson = new Gson();
// ...
public void writeWorkoutToUser(Workout workout) {
List<User> existingData = readDataFromFile();
List<User> users = new ArrayList<>();
User user;
if (existingData == null || existingData.isEmpty()) {
user = new User(dummyName);
} else {
user = existingData.get(0);
}
user.addWorkout(workout);
users.add(user);
String jsonFormat = gson.toJson(users);
try (FileWriter file = new FileWriter(fileLocation)) {
file.write(jsonFormat);
file.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
private List<User> readDataFromFile() {
try (FileReader reader = new FileReader(fileLocation)) {
if (reader.ready()) {
List<User> users = gson.fromJson(reader, new TypeToken<List<User>>() {}.getType());
return users;
} else {
// The file can be empty; this is not an error.
}
} 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();
}
return null;
}
public User returnUserClassFromFile() {
List<User> users = readDataFromFile();
if (users == null || users.isEmpty()) {
return new User(dummyName);
}
return users.get(0);
}
}
通过此重构,您不再需要在 JSON 集合和 Java 对象之间进行转换,从而使您的代码更安全、更易于维护。
评论
0赞
Markus helbæk
9/19/2023
哇!非常感谢。这是一种更好的解决方案:)。但是,您对如何将 gson 添加到我们的模块有任何建议吗?我们的模块-info.java : 这是对模块化如何工作的完全误解吗?ReadAndWrite.java 的包是核心。module ui { requires javafx.controls; requires javafx.fxml; requires gson; opens ui.controllers to javafx.graphics, javafx.fxml; opens ui to javafx.graphics, javafx.fxml; }
1赞
Markus helbæk
9/19/2023
算了,我想通了。再次感谢!
评论