Search code examples
javaserializationdeserializationtreemap

Why am I getting a ClassCastException when deserializing an object that contains a treemap?


I'm getting a ClassCastException when I deserialize my object from a file. When I check the file the object is there, so I know it's being serialized correctly. For some reason the code breaks when trying to retrieve the object. The idea is to allow the user to check, by date, all the workouts they've recorded in their log. Also, I've tried implementing a comparator, but I kept getting the same error and I'm all out of ideas. Any help would be much appreciated.

Here is the code that is causing the trouble:

case Logger.CHECK_KEY:
            //TODO

            try {

                workoutLog = (WorkoutLog) SerializationUtil.deserialize(file);
                System.out.println("Deserializing from:..." + file.getName());



            }

Here is the workoutLog class:

public class WorkoutLog implements Serializable{


public TreeMap < String , Workout > mWorkoutLog;

// thia is the actual Workoutlog

public WorkoutLog(){
    mWorkoutLog = new TreeMap<>();
}
//the string key will be the workouts formatted date
public TreeMap < String, Workout> getWorkoutLog(){
    return mWorkoutLog;
}

I'm including the body of the code for context

package com.alejandro;


import com.alejandro.Utilities.SerializationUtil;
import com.alejandro.model.Exercise;
import com.alejandro.model.Workout;
import com.alejandro.model.WorkoutLog;
import com.sun.istack.internal.NotNull;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.TreeMap;

public class Logger {
public static final String COMPLETE_KEY = "COMPLETE";
public static final String INCOMPLETE_KEY = "INCOMPLETE";
public static final String ADD_KEY = "ADD";
public static final String CHECK_KEY = "CHECK";
public static final String EXIT_KEY = "EXIT";




public static void main(String[] args) throws IOException, ClassNotFoundException {
    Logger logger = new Logger();
    WorkoutLog workoutLog = new WorkoutLog();
    Workout workout = new Workout();
    File file = new File("workout.txt");

    //im going to need to ask if the user wants to add a workout, close the      program, or select a workout
    String userInput = checkUserIntention();

    //the switch statement goes through all the possible user inputs

    switch(userInput){
        case Logger.ADD_KEY:
            printInstructions();
            do{
                logger.promptForExerciseData(workout);

            }while(!checkIfUserIsDone());

            workoutLog.getWorkoutLog().put(workout.getDate(),workout);
            SerializationUtil.serialize(workoutLog,file);
            System.out.println("Workout saved in..." +file.getName());

            break;

        case Logger.CHECK_KEY:
            //TODO

            try {

                workoutLog = (WorkoutLog) SerializationUtil.deserialize(file);
                System.out.println("Deserializing from:..." + file.getName());
                System.out.println(workoutLog.getWorkoutLog().keySet()+"");


            } catch(EOFException e){
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }catch(ClassCastException E){
                E.printStackTrace();
            }
            break;


        case Logger.EXIT_KEY:
            System.out.println("\nExiting program...");
            break;

    }
}





//I'm using this method to explain to the user how to use the program
protected static void printInstructions(){

    System.out.println("\nWelcome to Mr.Strong!\n");
    System.out.println("This program was developed to help powerlifters keep a log of their lifts.\n");
    System.out.println("Because of this, the program will only recognize the following lifts:\n");
    System.out.println("Squat, Bench, Deadlift, Press.\n");
    System.out.println("The program is case-sensitive, make sure the information is entered as stated above.\n");

}



//this method asks the user for information about the lifts stores them in a workout object

//the methods used here are all organized throught the page, its just to keep things cleaner and separate
protected void promptForExerciseData(Workout workout){
    Exercise exercise = new Exercise();
    askForExerciseIdentity(exercise);
    askForNumsRelLifts(exercise);
    workout.getExerciseList().add(exercise);
}

//this will check to see if the user is done inputting the exercises he did, if he finished the program ends.
protected static boolean checkIfUserIsDone(){
    Scanner scanner = new Scanner(System.in);
    boolean isUserDone = false;
    System.out.println("\nEnter: 'complete'" + ", if you are done. " +
            "If not, enter:'incomplete " + ".\n");
    String answer = scanner.nextLine();
    if(answer.trim().toUpperCase().equals(Logger.COMPLETE_KEY)){
        isUserDone = true;
    } else if(answer.trim().toUpperCase().equals(Logger.INCOMPLETE_KEY)){
        isUserDone = false;
    } else{
        checkIfUserIsDone();
    }
    return isUserDone;
}

//check if user wants to add, review, or close


protected static String checkUserIntention(){
    String answer = "a";
    Scanner scanner = new Scanner(System.in);
    System.out.println("\nPlease choose an option:\n" +
            "1-) Add a workout. Enter 'Add'.\n" +
            "2-) Check a workout Enter 'Check'.\n" +
            "3-) Exit the program. Enter 'Exit'\n");
    answer = scanner.nextLine();
    if(answer.trim().toUpperCase().equals(Logger.ADD_KEY) ||
            answer.trim().toUpperCase().equals(Logger.CHECK_KEY)||
            answer.trim().toUpperCase().equals(Logger.EXIT_KEY)){
        return answer.toUpperCase();
    }else{
        System.out.println("Incorrect input.");
        checkUserIntention();
    }


    return answer;


}



//all of this part is asking for the exercise data



    //this is the part that asks for exercise id


protected void askForExerciseIdentity(Exercise exercise){
    Scanner scanner = new Scanner(System.in);
    do{
        System.out.println("\nEnter a lift:\n");
        String exerciseIdentity = scanner.nextLine();
        if(exerciseIdentity.equals(exercise.SQUAT_KEY)){
            exercise.setExerciseIdentity(exercise.SQUAT_KEY);
        }else if(exerciseIdentity.equals(exercise.PRESS_KEY)){
            exercise.setExerciseIdentity(exercise.PRESS_KEY);
        }else if(exerciseIdentity.equals(exercise.BENCH_KEY)){
            exercise.setExerciseIdentity(exercise.BENCH_KEY);
        }else if(exerciseIdentity.equals(exercise.DEADLIFT_KEY)){
            exercise.setExerciseIdentity(exercise.DEADLIFT_KEY);
        }else {
            exercise.setExerciseIdentity(null);
            System.out.println("Please enter a valid exercise.");
        }}while(exercise.getExerciseIdentity() == null);
}




    //this is the part that aks for numbers



protected void askForNumsRelLifts(Exercise exercise){
    exercise.setWeightUsed(askForWeightUsed());
    exercise.setNumOfReps(askForNumOfReps());
    exercise.setNumOfSets(askForNumOfSets());
}

protected double askForWeightUsed(){
    Scanner scanner = new Scanner(System.in);
    double weightUsed;
    do{
        try{
            System.out.println("\nEnter weight used:\n");

            weightUsed = Double.parseDouble(scanner.nextLine());

        }catch(NumberFormatException e){

            System.out.println("\nPlease enter a valid number\n");
            weightUsed = 0;

        }

    } while(weightUsed == 0);
    return weightUsed;
}

protected double askForNumOfSets(){
    Scanner scanner = new Scanner(System.in);
    double numOfSets;
    do{
        try{
            System.out.println("\nEnter sets done:\n");
            numOfSets = Double.parseDouble(scanner.nextLine());

        }catch(NumberFormatException e){
            System.out.println("\nPlease enter a valid number\n");
            numOfSets = 0;
        }

    }while(numOfSets == 0);
    return numOfSets;
}

protected double askForNumOfReps(){
    Scanner scanner = new Scanner(System.in);
    double reps;
    do{
        try{
            System.out.println("\nEnter reps done:\n");
            reps = Double.parseDouble(scanner.nextLine());
        } catch(NumberFormatException e){
            System.out.println("\nPlease enter a valid number\n");
            reps = 0;
        }

    }while(reps == 0);
    return reps;
}

}
Here is workout included:

public class Workout implements Serializable{
protected ArrayList<Exercise> mExerciseList;
protected Date mDateCreated;
public Workout(){
    mExerciseList = new ArrayList<>();
    mDateCreated = new Date();
}
public ArrayList<Exercise> getExerciseList(){
    return mExerciseList;
}
public String getDate(){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    return sdf.format(mDateCreated);
}}

Here is the seralizationutil:

import com.alejandro.model.WorkoutLog;

import java.io.*;


public class SerializationUtil{
public static Object deserialize(File filename) throws IOException, ClassNotFoundException{
    FileInputStream fis = new FileInputStream(filename);
    Object obj = new Object();
    BufferedInputStream bis = new BufferedInputStream(fis);
    ObjectInputStream ois = new ObjectInputStream(bis);
    while(fis.available()>0){
        obj = ois.readObject();

    }

    ois.close();
    return obj;

}
public static void serialize(Object object, File filename) throws IOException{
    FileOutputStream fos = new FileOutputStream(filename);
    BufferedOutputStream bos = new BufferedOutputStream(fos);
    ObjectOutputStream oos = new ObjectOutputStream(bos);
    oos.writeObject(object);
    oos.close();

}}

Here is what the compiler gives me:

java.lang.ClassCastException: java.lang.Object cannot be cast to com.alejandro.model.WorkoutLog
at com.alejandro.Logger.main(Logger.java:56)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Solution

  • just try this simple example, i have modified your code extensively

    one more thing, I dont know what implementation you have under SerializationUtil so i created my own implementation

    My example works without any issue

    package week4;
    

    import java.io.Serializable; import java.util.TreeMap;

    public class WorkoutLog implements Serializable { public TreeMap < String , Workout > mWorkoutLog;

    // thia is the actual Workoutlog
    
    public WorkoutLog(){
        mWorkoutLog = new TreeMap<>();
    }
    //the string key will be the workouts formatted date
    public TreeMap < String, Workout> getWorkoutLog(){
        return mWorkoutLog;
    }
    

    }

    package week4;
    

    import java.io.Serializable;

    public class Workout implements Serializable {

    String date = "2016-01-13";
    
    public String getDate() {
        return date;
    }
    
    public void setDate(String date) {
        this.date = date;
    }
    

    }

    package week4;
    

    import java.io.File; import java.io.IOException;

    public class TestWorkOut {

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        WorkoutLog workoutLog = new WorkoutLog();
        Workout workout = new Workout();
        /* I had path to workout.txt as D:\\workout.txt*/
        File file = new File("D:\\workout.txt");
    
        workoutLog.getWorkoutLog().put(workout.getDate(),workout);
        SerializationUtil.serialize(workoutLog,file);
        System.out.println("Workout saved in..." +file.getName());
    
        workoutLog = (WorkoutLog) SerializationUtil.deserialize(file);
        System.out.println("Deserializing from:..." + file.getName());
        System.out.println(workoutLog.getWorkoutLog().keySet()+"");
    
    }
    

    }

    package week4;
    

    import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream;

    public class SerializationUtil {

    public static void serialize(WorkoutLog workoutLog, File filename) {
    
        FileOutputStream fos = null;
        ObjectOutputStream out = null;
        try {
          fos = new FileOutputStream(filename);
          out = new ObjectOutputStream(fos);
          out.writeObject(workoutLog);
    
          out.close();
        } catch (Exception ex) {
          ex.printStackTrace();
        }
    
    }
    
    public static WorkoutLog deserialize(File filename) {
        FileInputStream fis = null;
        ObjectInputStream in = null;
        WorkoutLog workout = null;
        try {
          fis = new FileInputStream(filename);
          in = new ObjectInputStream(fis);
          workout = (WorkoutLog) in.readObject();
          in.close();
        } catch (Exception ex) {
          ex.printStackTrace();
        }
        return workout;
    }
    

    }

    Output

    Workout saved in...workout.txt

    Deserializing from:...workout.txt

    [2016-01-13]