So I am trying to create a feature where two current objects can be saved so next time they can be loaded instead of being created again. I have a problem with following class:
public class Investor implements Serializable {
private String investorName;
private double investorCapital;
private ArrayList<Share> shareOwned;
private ArrayList<Integer> numberOwned;
public Investor(String name, double capital) {
investorName = name;
investorCapital = capital;
shareOwned = new ArrayList<Share>();
numberOwned = new ArrayList<Integer>();
}
P.S. I removed function just to show structure. Then I execute following code:
File investorData = new File("inv1.ser");
if(investorData.exists()) {
try {
FileInputStream loadData = new FileInputStream(investorData);
ObjectInputStream ois = new ObjectInputStream(loadData);
inv1 = (Investor) ois.readObject();
loadData.close();
ois.close();
} catch (Exception exc) {
JOptionPane.showMessageDialog(null, "An error occurred", "Error", JOptionPane.ERROR_MESSAGE);
}
}
else {
try {
String name = JOptionPane.showInputDialog(null, "What is your name?", "Creating new investor", JOptionPane.QUESTION_MESSAGE);
double capital = Double.parseDouble(JOptionPane.showInputDialog(null, "What is your investor capital?", "Creating new investor", JOptionPane.QUESTION_MESSAGE));
inv1 = new Investor(name, capital);
}
catch(NullPointerException exc) {
JOptionPane.showMessageDialog(null, "You must enter details in order to proceed", "File Not Found", JOptionPane.ERROR_MESSAGE);
}
JOptionPane.showMessageDialog(null, "New investor " + inv1.getInvestorName() + " with balance: " + inv1.getInvestorCapital() + " has been successfully created!", "Investor Created", JOptionPane.INFORMATION_MESSAGE);
try {
FileOutputStream saveFile = new FileOutputStream(investorData);
ObjectOutputStream oos = new ObjectOutputStream(saveFile);
oos.writeObject(inv1);
saveFile.close();
oos.close();
}
catch(Exception exc) {
JOptionPane.showMessageDialog(null, "An error occurred", "Error", JOptionPane.ERROR_MESSAGE);
}
}
When I launch program first time it prompts me to create new Investor object which it does successfully and saves in appropriate location and so on. After that I can use program: buy/sell shares etc, but once I close it, and open again, it doesn't recognize shares that were bought before. So for example if when I closed I had Gold - 100, then when I open program again it will show Gold - 100 and will try to buy 10 more, it will add new Gold object to shareOwned and I will have Gold - 100, Gold - 10. So as I understand it cannot recognize old Gold object and added new one (as was intended if it never existed).
I cannot upload a whole program because it is quite big, there is buyShare method in investor class:
public void buyShare(double price, int amount, Share stock) {
investorCapital -= price * amount;
if(shareOwned.contains(stock)) {
numberOwned.add(shareOwned.indexOf(stock), numberOwned.get(shareOwned.indexOf(stock)) + amount);
}
else {
shareOwned.add(stock);
numberOwned.add(amount);
}
}
Share class(without functions):
public class Share implements Serializable {
private String shareName;
private double shareValue;
private int shareAvailable;
private final double SHARE_PURE_VALUE;
public Share(String name, double value, int available) {
shareName = name;
SHARE_PURE_VALUE = value;
shareValue = value / available;
shareValue = Math.round(shareValue * 10) / 10;
shareAvailable = available;
}
You can see where I check for "contains" it should return just add numberOwned, but instead it creates new one, so it cannot find previous Gold that was saved before. Sorry for explaining so badly, I can send a program if that will be more convenient.
If I understood your problem, you expect to have "Gold - 110", not "Gold - 100, Gold - 10", right?
So, I think you have to implement equals and hashCode methods on Share class. When "shareOwned.contains(stock)" is called, never returns true, correct?
That's why you always have a new stock object in your list.
Add commons-lang3 to your project and put this code on your Share class:
#Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}
#Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
Should work.
Thank you so much! I solved the problem. As it was mentioned I had to override equals() and hashCode() methods in Share class and now everything working (seems at least) perfectly. I was trying to use loops to check names instead but this solution is much simpler!
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Share share = (Share) o;
if (!shareName.equals(share.shareName)) return false;
return true;
}
#Override
public int hashCode() {
return 1;
}
public void setMarketValue() {
shareValue = SHARE_PURE_VALUE / shareAvailable;
shareValue = Math.round(shareValue * 10) / 10;
}
Related
I have created a clone of Atari Breakout game using the ACM graphics library and just finished adding a highscore interface and functionality. The player's name and score should be displayed on the GUI window (it is successfully) and also be written to a .dat binary file.
However, when the code attempts to load the existing file I get the following error.
writing aborted; java.io.NotSerializableException: acm.graphics.GCanvasListener
I've researched this error online and it seems it can be solved by editing the class to implement Serializable. However, the class throwing this error is not one of my own but rather a class that belongs to the third-party ACM graphics library. How do I solve this?
I'm not even sure why this error is being caused in the first place since the data I'm attempting to serialize is only a name and score, I'm not trying to serialize a canvas of objects or anything like that.
Main class (called Breakout)
public class Breakout extends GraphicsProgram {
... // game variables
public void run() {
... // this if clause runs when game ends
if (brickCounter > 0) {
removeAll(); // clears screen
printGameOver(); // displays game over message
HighscoreManager hm = new HighscoreManager();
String name = getHighScoreName();
hm.addScore(name, score);
hm.displayHighscores();
}
}
... // game functionality methods
private String getHighScoreName(){
IODialog dialog = new IODialog();
String name = dialog.readLine("Enter your name: ");
return name;
}
Score class
private class Score implements Serializable {
private int score;
private String name;
public Score(String name, int score) {
this.score = score;
this.name = name;
}
public int getScore() { return score; }
public String getName() { return name; }
}
ScoreComparator class
private class ScoreComparator implements Comparator<Score> {
public int compare(Score score1, Score score2) {
int sc1 = score1.getScore();
int sc2 = score2.getScore();
if (sc1 > sc2) {
return -1;
} else if (sc1 < sc2) {
return 1;
} else {
return 0;
}
}
}
HighscoreManager class
private class HighscoreManager {
private ArrayList<Score> scores;
private static final String HIGHSCORE_FILE = ".//bin//scores.dat";
ObjectOutputStream outputStream = null;
ObjectInputStream inputStream = null;
public HighscoreManager() {
scores = new ArrayList<Score>(10);
}
public ArrayList<Score> getScores() {
loadScoreFile();
sort();
return scores;
}
private void sort() {
ScoreComparator comparator = new ScoreComparator();
Collections.sort(scores, comparator);
}
public void addScore(String name, int score) {
loadScoreFile();
scores.add(new Score(name, score));
updateScoreFile();
}
public void loadScoreFile() {
try {
inputStream = new ObjectInputStream(new FileInputStream(HIGHSCORE_FILE));
scores = (ArrayList<Score>) inputStream.readObject();
}
catch (FileNotFoundException e) {
System.out.println("[Load] File Not Found Error: " + e.getMessage());
}
catch (IOException e) {
System.out.println("[Load] Input/Output Error: " + e.getMessage());
}
catch (ClassNotFoundException e) {
throw new RuntimeException("[Load] Class Not Found Error: " + e.getMessage());
}
finally {
try {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
} catch (IOException e) {
System.out.println("[Load] Input/Output Error: " + e.getMessage());
}
}
}
public void updateScoreFile() {
try {
outputStream = new ObjectOutputStream(new FileOutputStream(HIGHSCORE_FILE));
outputStream.writeObject(scores);
}
catch (FileNotFoundException e) {
System.out.println("[Update] File Not Found Error: " + e.getMessage());
}
catch (IOException e) {
System.out.println("[Update] Input/Output Error: " + e.getMessage());
}
finally {
try {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
} catch (IOException e) {
System.out.println("[Update] Input/Output Error: " + e.getMessage());
}
}
}
public void displayHighscores() {
int max = 10;
ArrayList<Score> scores;
scores = getScores();
int x = scores.size();
if (x > max) {
x = max;
}
removeAll(); // clears screen
int npos = 160;
int spos = 160;
for (int i = 0; i < x; i++) {
GLabel showName = new GLabel(scores.get(i).getName(), (getWidth() / 2.0) - 100, (getHeight() / 2.0) - npos);
showName.move(-showName.getWidth() / 2, -showName.getHeight());
showName.setColor(Color.WHITE);
add(showName);
npos -= 40;
}
for (int i = 0; i < x; i++) {
GLabel showScore = new GLabel(Integer.toString(scores.get(i).getScore()), (getWidth() / 2.0) + 100, (getHeight() / 2.0) - spos);
showScore.move(-showScore.getWidth() / 2, -showScore.getHeight());
showScore.setColor(Color.WHITE);
add(showScore);
spos -= 40;
}
}
After running the application:
[Load] Input/Output Error: writing aborted; java.io.NotSerializableException: acm.graphics.GCanvasListener
[Update] Input/Output Error: acm.graphics.GCanvasListener
[Load] Input/Output Error: writing aborted; java.io.NotSerializableException: acm.graphics.GCanvasListener
Your task will be to find a hidden reference from your name and score structure to the UI components. Many GUI applications use a lot of inner classes, and this might be the missing link.
When you have a class something like this:
class MyGame {
private SomeUIWidget widget;
class TopScore implements Serializable {
String name;
int score;
...
}
...
}
There is a hidden member in TopScore that references the "enclosing instance" of MyGame, including its SomeUIWidget member. When you try to serialize a TopScore instance, all the rest gets dragged in with it.
You could simply declare TopScore as a static nested class. This means that there is no enclosing instance, and serves only to hide the TopScore class from other code. But, I would suggest just making TopScore a top-level class, in its own file, because it's likely that other objects will want to use those objects in different ways—that is, it seems like a likely candidate for part of your public API.
This is an educated guess, in the absence of any actual code. To get a better answer, reduce your code to the minimum required to demonstrate the problem, and include that in your question.
You should go to the class where the fields name and score are, and add for example public class nameclass implements Serializable. I hope it works for you.
I try to serialize and deserialize an ArrayList with some Objects. The first time I run the program, everything works, but the next times it doesn't work:
public class Test {
private static final String FILE_NAME = "Objects.ser";
public static void main(String[] args) {
ArrayList<CustomObject> customObjects = getCustomObjects();
System.out.println("CustomObjects count: "+customObjects.size());
System.out.println("Adding 5 CustomObjects");
Random rand = new Random();
for(int i=0; i<5; i++){
CustomObject obj = new CustomObject();
obj.setIntValue(rand.nextInt());
customObjects.add(obj);
}
System.out.println("CustomObjects count: "+customObjects.size());
System.out.println("Save and load CustomObjects");
saveCustomObjects(customObjects);
customObjects = getCustomObjects();
System.out.println("CustomObjects count: "+customObjects.size());
}
public static ArrayList<CustomObject> getCustomObjects(){
try (
FileInputStream fin = new FileInputStream(FILE_NAME);
ObjectInputStream ois = new ObjectInputStream(fin);
){
return (ArrayList<CustomObject>) ois.readObject();
} catch (Exception ex) {
return new ArrayList<>();
}
}
public static void saveCustomObjects(ArrayList<CustomObject> strategies) {
try(
FileOutputStream fout = new FileOutputStream(FILE_NAME, true);
ObjectOutputStream oos = new ObjectOutputStream(fout);
){
oos.writeObject(strategies);
//tried also with oos.flush();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
public class CustomObject implements Serializable{
static final long serialVersionUID = 42L;
private int intValue=0;
private EnumTypes enumType=EnumTypes.ENUM_TYPE_ONE;
public enum EnumTypes{
ENUM_TYPE_ONE, ENUM_TYPE_TWO
}
public int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
this.intValue = intValue;
}
public EnumTypes getEnumTypes() {
return enumType;
}
public void setEnumTypes(EnumTypes enumTypes) {
this.enumType = enumTypes;
}
#Override
public int hashCode() {
int hash = 3;
hash = 97 * hash + this.intValue;
hash = 97 * hash + Objects.hashCode(this.enumType);
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final CustomObject other = (CustomObject) obj;
if (this.intValue != other.intValue) {
return false;
}
if (this.enumType != other.enumType) {
return false;
}
return true;
}
#Override
public String toString() {
return "CustomObject{" + "intValue=" + intValue + ", enumTypes=" + enumType + '}';
}
}
The output of the first run of the app shows everything like expected:
CustomObjects count: 0
Adding 5 CustomObjects
CustomObjects count: 5
Save and load CustomObjects
CustomObjects count: 5
But after the next runs, the output looks always like the file with the objects in the serialized ArrayList could not be overwritten:
CustomObjects count: 5
Adding 5 CustomObjects
CustomObjects count: 10
Save and load CustomObjects
CustomObjects count: 5
I tested in netbeans and console on mac. Does anyone know what the problem is?
That's exactly that, nothing is overwritten, since you explicitely chose to append rather than overwrite when writing to the file:
new FileOutputStream(FILE_NAME, true);
So the first run reads nothing, and appends a list of 5 elements to the file. The second run reads the unique list and appends another list of 10 elements to the file. The third run reads the first list of in the file, and appends yet another list of 10 elements, etc.
Remove the second argument, or set it to false.
As a part of my assignment I had to store objects of an array in a flat-file and retrieve them when certain criteria was met. I can save the objects fine but when retrieving them I have an issue with getting more than one value, I understand what is going wrong but I am struggling to find a solution. Here is the concept of whats happening.
Button no 10,A (R1S10 in the code)is my testing button, When I click it it creates an event that I will show below.
Click event for button 10A -
private void R1S10ActionPerformed(java.awt.event.ActionEvent evt) {
seats.add(seat1);
if (R1S10.getBackground().equals(Color.red) &&(IsSeatBooked().equals("true"))){
Component frame = null;
JOptionPane.showMessageDialog(frame, "Seat UnBooked");
seat1.setBooked("false");
seat1.setName("");
R1S10.setBackground(Color.yellow);
try {
reader();
writer();
//String booked = "true";
//Pass String booked into csv file
} catch (IOException ex) {
Logger.getLogger(SeatingPlan.class.getName()).log(Level.SEVERE, null, ex);
}
}
else{
Component frame = null;
String name = JOptionPane.showInputDialog(frame, "Please enter name of Customer booking");
if (name.isEmpty()) {
JOptionPane.showMessageDialog(frame, "No value entered");
} else if (name != null) {
seat1.setName(name);
seat1.setBooked("true");
R1S10.setBackground(Color.red);
JOptionPane.showMessageDialog(frame, "Your Booking has been placed");
try {
writer();
reader();
//String booked = "true";
//Pass String booked into csv file
} catch (IOException ex) {
Logger.getLogger(SeatingPlan.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
Followed by the screen below -
Outcome -
And when the button is pressed again -
I am using three methods in this SeatingPlan.java - writer(),reader() and IsSeatBooked().
SeatingPlan -
public class SeatingPlan extends javax.swing.JFrame {
/**
* Creates new form SeatingPlan
*/
String seatNo, name, bookedSeat;
FileWriter fileWriter = null;
List<Seat> seats = new ArrayList<Seat>();
//Seat Object Declaration
Seat seat1 = new Seat("R1S10","","false");
Seat seat2 = new Seat("R1S9", "", "false");
String fileName = "seat.csv";
writer -
public void writer() throws IOException {
//Delimiter used in CSV file
final String NEW_LINE_SEPARATOR = "\n", COMMA_DELIMITER = ",";
//CSV file header
final String FILE_HEADER = "seatID,name,booked";
//fileName = System.getProperty("user.home") + "/seat.csv";
try {
fileWriter = new FileWriter(fileName);
//Write the CSV file header
fileWriter.append(FILE_HEADER.toString());
//Add a new line separator after the header
fileWriter.append(NEW_LINE_SEPARATOR);
//Write a new student object list to the CSV file
for (Seat seat : seats) {
fileWriter.append(String.valueOf(seat.getSeatID()));
fileWriter.append(COMMA_DELIMITER);
fileWriter.append(seat.getName());
fileWriter.append(COMMA_DELIMITER);
fileWriter.append(seat.isBooked());
fileWriter.append(NEW_LINE_SEPARATOR);
}
System.out.println("CSV file was created successfully !!!");
} catch (Exception e) {
System.out.println("Error in CsvFileWriter !!!");
e.printStackTrace();
} finally {
fileWriter.flush();
fileWriter.close();
}
}
reader -
public void reader() {
//Delimiter used in CSV file
final String COMMA_DELIMITER = ",";
//Student attributes index
final int SEAT_ID_IDX = 0;
final int SEAT_NAME_IDX = 1;
final int SEAT_BOOKED = 2;
//private static final int STUDENT_LNAME_IDX = 2;
BufferedReader fileReader = null;
try {
//Create a new list of student to be filled by CSV file data
List<Seat> seats = new ArrayList<>();
String line = "";
//Create the file reader
fileReader = new BufferedReader(new FileReader(fileName));
//Read the CSV file header to skip it
fileReader.readLine();
//Read the file line by line starting from the second line
while ((line = fileReader.readLine()) != null) {
//Get all tokens available in line
String[] tokens = line.split(COMMA_DELIMITER);
if (tokens.length > 0) {
//Create a new seat object and fill his data
Seat seat = new Seat(tokens[SEAT_ID_IDX],
tokens[SEAT_NAME_IDX], tokens[SEAT_BOOKED]);
seats.add(seat);
seatNo = tokens[SEAT_ID_IDX];
//System.out.println("Seat Number: " + seatNo);
bookedSeat = tokens[SEAT_BOOKED];
}
}
//Print the new student list
for (Seat seat : seats) {
System.out.println(seat.toString());
}
} catch (Exception e) {
System.out.println("Error in CsvFileReader !!!");
e.printStackTrace();
} finally {
try {
fileReader.close();
} catch (IOException e) {
System.out.println("Error while closing fileReader !!!");
e.printStackTrace();
}
}
}//end reader
SeatingPlan - This if where I have tried to have the arguments controlling the outcome but IsBooked is colliding when multiple seats are selected.
public SeatingPlan() throws IOException {
setVisible(true);
initComponents();
//reader();
ColourSectionGold();
ColourSectionBronze();
reader();
if(R1S10.getBackground().equals(Color.yellow) && (IsSeatBooked().equals("true"))){ R1S10.setBackground(Color.red);}
//if(R1S9.getBackground().equals(Color.yellow) && (IsSeatBooked().equals("true2"))){ R1S9.setBackground(Color.red);}
}
IsSeatBooked -
public String IsSeatBooked(){
return bookedSeat;
}//end IsSeatBooked
Im using the method above as my argument to see whether a seat is booked or not, but when a new seat is click it sets the whole value of 'bookedSeat' - which leaves the system not working correctly. I understand the code is not very efficient but is there any temporary fix for this problem, if I have explained it correctly.
Also I will include my class for Seat -
public class Seat {
private String seatID;
private String booked;
private String name;
private int price;
public Seat(String seatID,String name,String booked){
this.seatID = seatID;
this.booked = "";
this.name = name;
this.price = price;
}
public String getSeatID() {
return seatID;
}
public void setSeatID(String seatID) {
this.seatID = seatID;
}
public String isBooked() {
return booked;
}
public void setBooked(String booked) {
this.booked = booked;
}
public String getStatus(){
return booked;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPrice() {
this.price = price;
}}//end class Seat
And a look at the CSV file that is created -
I wish to be able to click more than one button and save its state, Button 10 works fine at the moment, but as IsBooked only has one value at a time it clashes.
If you took the time to check this out, I appreciate it. Any constructive criticism is helpful and any ideas would be great!
Thanks,
Paddy.
Too much code to look at to see exactly what you are doing.
Instead of using your csv file, you could create a Properties file. The Propertiesfile will store the data in the form of:
key:data
So in your case the key would be the id: A1, A2... and the data would be the name of the person who booked the seat.
So the file would start out as empty. When you create the GUI you would create a loop that checks each id to see if an entry is found in the Properties field. If it is found then you display the seat as taken, otherwise it is empty.
Then whenever you want to book a seat you just use the setProperty(...) method.
The Properties class has load(...) and store(...) methods.
So the Properties class allows you to easily manage a flat file database with minimal effort.
Note, you would never have variable names like R1S10. That would requirement 100 different variables with if/else statements. Instead you would extend JButton and pass in the row and seat as parameters the button. Then in the ActionListener for the button you can access the row/seat information to built the ID used as the key for the properties file.
Edit:
Couldn't quite make the loop that checks if the ID is in the properties file.
If the property is null, the seath is empty.
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Properties properties = new Properties();
properties.setProperty("A2", "Smith");
properties.setProperty("C3", "Jones");
String[] rows = { "A", "B", "C", "D" };
int seats = 4;
for (int row = 0; row < rows.length; row++)
{
for (int seat = 1; seat <= seats; seat++)
{
String key = rows[row] + seat;
String property = properties.getProperty( key );
System.out.println(key + " : " + property);
}
}
}
}
My program has 6 classes so I'm going to try and only post the methods involved with the issue I'm having. I'm trying to add donation objects that get their attributes from reading information from a file. My program wasn't printing out any of the donationList related information so I did a System.out.println(donationList.size()); and it's telling me that there are 0 objects in the list. I've been looking at this for a while and can't figure out where in the process the donation object is failing to be created correctly or added to the arraylist correctly.
This is where I call the method that starts the process.
public static void main(String[] args) {
readAndProcess();
This is the method that starts the process.
public static void readAndProcess() {
final String INPUT_FILENAME = "input/assn2input.txt";
File dataFile = new File(INPUT_FILENAME);
Scanner fileScanner = null;
try {
fileScanner = new Scanner(dataFile);
}catch (FileNotFoundException e) {
System.out.println("File not found exception for file " + e);
System.exit(0);
}
String oneLine;
String [] lineValues;
while(fileScanner.hasNextLine()) {
oneLine = fileScanner.nextLine();
lineValues = oneLine.split(",");
if(lineValues[0].equals("DONOR")) {
if (lineValues[1].equals("ADD") ) {
addDonor(lineValues);
}
else if (lineValues[1].equals("DEL")) {
// call method to delete
}
}
else if ( lineValues[0].equals("Donation")) {
if (lineValues[1].equals("ADD")) {
addDonation(lineValues);
}
else if (lineValues[1].equals("DEL")) {
// call method to delete
}
}
}
}
This is the addDonation method which happens after the readAndProcess method.
public static void addDonation(String [] lineValues) {
Donation donation = new Donation();
setDonationAttributes(donation, lineValues);
if (donorImpl.isIDUnique(donation.getDonorID()) == false &&
donationImpl.isIDUnique(donation.getDonationID()) == true) {
donationImpl.add(donation);
}
else {
System.out.println("ERROR: The Donation either had a non-unique"
+ " donation ID or a unique Donor ID. Was not "
+ "added to list." + donation.toString());
}
}
This is the method that sets the donation object's attributes.
public static Donation setDonationAttributes (Donation donation,
String [] lineValues) {
donation.setDonationID(Integer.parseInt(lineValues[2]));
donation.setDonorID(Integer.parseInt(lineValues[3]));
donation.setDonationDescription(lineValues[4]);
if (donation.checkDescriptionLength() == false) {
System.out.println("ERROR: Donation description is longer "
+ "than 25 characters");
}
donation.setDonationAmount(Double.parseDouble(lineValues[5]));
donation.setDonationDate(lineValues[6]);
if (lineValues[7].equalsIgnoreCase("Y") ) {
donation.setTaxDeductible(true);
}
else {
donation.setTaxDeductible(false);
}
donation.setCheckNumber(Integer.parseInt(lineValues[8]));
if (donation.checkNumberCheck()== false) {
System.out.println("ERROR: Invalid check number is not between 100 "
+ "and 5000: " + lineValues[8]);
}
return donation;
}
This is the method that checks for unique ID for donationID.
public boolean isIDUnique(int donationID) {
int index;
for (index = 0; index < donationList.size(); ++index) {
if (donationID == donationList.get(index).getDonationID() ) {
return false;
}
}
return true;
}
This is the method for checking unique donorID.
public boolean isIDUnique(int donorID) {
int index;
for (index = 0; index < donorList.size(); ++index) {
if (donorID == donorList.get(index).getDonorID() ) {
return false;
}
}
return true;
}
This is the method in the DonationImpl class that adds the object to the arraylist. The instructions for this method told me to set it up as a boolean for whatever reason, I'm not exactly sure why.
public boolean add (Donation donation) {
if (donationList.add(donation)) {
return true;
}
return false;
}
The donationImpl class to show what the arrayList creation looks like.
public class DonationImpl {
// Data Field
private ArrayList<Donation> donationList = new ArrayList<Donation>();
//Getter
public ArrayList<Donation> getDonationList() {return donationList;}
The 1 and 3 in the following examples refer to a donorID. My donorID methods and creation are all working correctly.
Example lines of text:
DONATION,ADD,101,1,Payroll deduction,22.22,07/04/1776,Y,1001
DONATION,ADD,303,3,Anniversary contribution,111.00,07/04/1777,N,2244
You have a typo
else if ( lineValues[0].equals("Donation")) {
should be
else if ( lineValues[0].equals("DONATION")) {
The following code is two methods, one for saving to a file using object serialization and one for loading and deserializing the saved file for the user to read:
private void SaveDeck() throws Exception {
ObjectOutputStream oos = null;
FileOutputStream fout = null;
try{
fout = new FileOutputStream(filePath, true);
oos = new ObjectOutputStream(fout);
oos.writeObject(theDeck);
} catch (Exception ex) {
ex.printStackTrace();
}finally {
if(oos != null){
oos.close();
}
}
}
private FlashCardDeck[] loadDeck(){
user.setDeckMade(true);
try {
FileInputStream fis = new FileInputStream(filePath);
ObjectInputStream in = new ObjectInputStream(fis);
this.theDeck = (FlashCardDeck[])in.readObject();
in.close();
}
catch (Exception e) {
System.out.println(e);
}
return theDeck;
}
The error I'm getting is on the load method:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: myPackage.UserInterface
Saving works fine; I've opened up the .ser file after the SaveDeck method has executed and everything seemed to check out properly.
My question is if the problem is with the file itself, the save method, or external methods? I have made sure that everything not serializable (Namely, the Scanner class) is transient.
package myPackage.FlashCards;
import java.io.Serializable;
public class FlashCardDeck implements Serializable{
private static final long serialVersionUID = -1176413113990886560L;
public FlashCard[] theDeck;
public String deckName;
public FlashCardDeck(int cards, String name) {
this.deckName = name;
theDeck = new FlashCard[cards];
for (int i = 0; i < theDeck.length; i++) {
theDeck[i] = new FlashCard(i);
}
}
public String getQuestion(int i) {
return theDeck[i].QuestionToString();
}
public String getAnswer(int i ) {
return theDeck[i].AnswerToString();
}
public String getName() {
return deckName;
}
public int getDeckSize() {
return theDeck.length;
}
}
package myPackage.FlashCards;
import java.io.Serializable;
import java.util.Scanner;
public class FlashCard implements Serializable{
private static final long serialVersionUID = -8880816241107858648L;
private transient Scanner in = new Scanner(System.in);
String question;
String answer;
public FlashCard(int i) {
setCard(i);
}
public void setCard(int cards) {
System.out.println("What is the question for number " + (cards + 1) + "?");
question = in.nextLine();
System.out.println("What is the answer for number " + (cards + 1) + "?");
answer = in.nextLine();
}
public String QuestionToString() {
return "Question: " + question;
}
public String AnswerToString() {
return "Answer: " + answer;
}
}
package myPackage.FlashCards;
import java.io.Serializable;
import java.util.InputMismatchException;
import java.util.Scanner;
public class UserInterface implements Serializable{
private static final long serialVersionUID = 7755668511730129821L;
private int moreThanOnce = 0;
boolean deckMade = false;
private transient Scanner in = new Scanner(System.in);
public int AmountOfDecks() {
int decks;
System.out.println("How many decks will you be creating? (Type the number,
not the word. Ex: 2)");
decks = in.nextInt();
while (decks <= 0) {
System.out.println("You can't have less than one deck! Try again.");
decks = in.nextInt();
}
return decks;
}
public int StartMenu() {
int choice = 0;
moreThanOnce++;
if (moreThanOnce > 1) {
choice = SecondMenu();
} else {
System.out.println("\nFlash Card Creation Engine Ver. 2.5 ALPHA");
System.out.println("Press the cooresponding number for your
choice.");
System.out.println("1. Make a deck of flash cards");
System.out.println("2. Play flash cards");
System.out.println("3. Quit \n");
try { choice = in.nextInt(); } catch (InputMismatchException ime) {}
}
return choice;
}
public int AmountOfCards(int cards) {
int catchMe;
deckMade = true;
System.out.println("How many cards would you like? (Type the number, not the
word. Ex: 2)");
try {
catchMe = in.nextInt();
while (catchMe <= 0) {
System.out.println("You can't have less than one card! Try
again!");
catchMe = in.nextInt();
}
} catch (Exception ime) {
System.out.println("Uh-oh, you did that wrong! Let's try that again.
Try typing: 3");
cards = 0;
catchMe = in.nextInt();
}
cards = catchMe;
return cards;
}
public boolean getDeckMade() {
return deckMade;
}
public void setDeckMade(boolean makeDeckMade) {
this.deckMade = makeDeckMade;
}
public String NameOfDeck() {
String name;
System.out.println("What would you like to name this deck?");
name = in.next();
return name;
}
private int SecondMenu() {
int choice = 0;
System.out.println("Now what would you like to do?");
if (deckMade) {
System.out.println("1. Make or load a deck of flash cards -- DONE");
} else {
System.out.println("1. Make a deck of flash cards.");
}
System.out.println("2. Play flash cards");
System.out.println("3. Quit \n");
try { choice = in.nextInt(); } catch (InputMismatchException ime) {}
return choice;
}
public boolean SetMode() {
boolean timed = false;
int userChoice = 0;
while (userChoice < 1 || userChoice > 2) {
System.out.println("What mode are you selecting?");
System.out.println("1. Timed");
System.out.println("2. Normal");
System.out.println("3. Help");
System.out.println("4. Quit");
userChoice = in.nextInt();
if (userChoice == 1) {
timed = true;
} else if (userChoice == 3) {
System.out.println("Timed: Answers to a flash card will
appear after a set amount of seconds, then show the next
question after the same amount of seconds, which are set by
the user (that's you!)");
System.out.println("Normal: Answers to a flash card will
appear when the user (also you!) presses enter, and wait for
enter to be pressed before showing the next question.");
} else if (userChoice == 4) {
System.out.println("Have a good day.");
System.exit(0);
} else {
System.out.println("Choose from the proivded list -- 1 for
Timed mode, 2 for Normal mode, 3 to show the Help menu, 4 to
quit.");
System.out.println();
}
}
return timed;
}
public String setQuestion(int cards) {
String question = "";
return question;
}
public String setAnswer(int cards) {
String answer = "";
return answer;
}
}
The class you're trying to serialize (and any non-transient objects referenced by that class) must implement the Serializable interface.
judging by the error you have a UserInterface class referenced there which is not serializable.
Edit:
Also
new FileOutputStream(filePath, true);
always appends to the end of the file instead of clearing the file. You may have older data in the file that is not deserialized correctly. You could try removing the file and trying again.
In general - appending different objects to a file may be a bad choice considering data corruption. If different files for each deck are not an option, I might go for a separate DeckStore object that holds all the decks and gets serialized as a whole.
Class that you want to serialize should implement Serializable interface
public class FlashCardDeck implements Serializable {
// Fields and methods of the class ...
}
The serialization interface has no methods or fields and serves only to identify the semantics of being serializable.