I am new to Java and encountered this problem: I am learning how to save object state to a file and I got stuck with passing an array to the constructor. I believe that the problem is the base class with the constructor but I am not sure.
here is my Hero class:
import java.io.Serializable;
public class Hero implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int power;
private String type;
private String[] wepons;
public int getPower() {
return power;
}
public void setPower(int power) {
this.power = power;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String[] getWepons() {
return wepons;
}
public void setWepons(String[] wepons) {
this.wepons = wepons;
}
public Hero(int powerH, String typeH, String[] weponsH) {
this.power = powerH;
this.type = typeH;
this.wepons = weponsH;
}
}
and here is class which I try to use to save the object state:
import java.io.*;
public class SaveGame {
public static void main(String[] args) {
Hero hero1 = new Hero(50, "Elf", new String[] {"bow", "short sword", "powder"});
try{
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("Game.ser"));
os.writeObject(hero1);
os.close();
} catch (IOException ex) {
ex.printStackTrace();
}
ObjectInputStream is;
try {
is = new ObjectInputStream(new FileInputStream("Game.ser"));
Hero p1N = (Hero) is.readObject();
System.out.println(p1N.getPower() + " " + p1N.getType() + " " + p1N.getWepons());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Can you tell me and explain what am I doing wrong. Do I really need setters and getters in my Hero class and I have the feeling that I am using them incorrectly.
My problem was that when I tried to print out the Hero's parameters I got content of the array instead of string representation of the array. Thanks to user2336315 I know now that i should use Arrays.toString method when printing content of an array
I ran your code and everything seems to be fine. The only problem is that you want to print the content of the array itself, not the string representation of the array itself. So use Arrays.toString :
System.out.println(p1N.getPower() + " " + p1N.getType() + " " + Arrays.toString(p1N.getWepons()));
Output :
50 Elf [bow, short sword, powder]
Deserialization mechanism creates the class using its meta data. It does not depend on the access levels of the members of the target class, inclusing constructors. (Your code will work even Hero class has private default constructor.)
Related
I'm still quite new to Java and need a hand working out how to get around my problem.
I'm attempting to write a method to deserialize an object that I have called Student. The method is as follows:
public void readStudentInfo() {
// Desrializes the student objects into an ArrayList for you to compare against
try{
FileInputStream fis = new FileInputStream("student.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
deserializedStudents = (ArrayList) ois.readObject();
ois.close();
fis.close();
}
catch(IOException ioe){
ioe.printStackTrace();
return;
} catch(ClassNotFoundException c){
System.out.println("Class not found");
c.printStackTrace();
return;
}
for(Student student : deserializedStudents){
System.out.println(student.toString());
}
}
The class Student that it works with is as follows:
import java.io.Serializable;
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
// Class Attributes
private String studentID;
private String rankings;
private char personalityType;
private String conflict;
private String preferences;
// Class Constructor
public Student(String ID){
this.studentID = ID;
}
public Student(String ID, String grades) {
this.studentID = ID;
grades = grades.trim();
this.rankings = grades;
}
public Student(String ID, String ranking,char personality){
this.studentID = ID;
this.rankings = ranking;
this.personalityType = personality;
}
// Accessor Methods
public String getStudentID() {
return this.studentID;
}
public String getRankings(){
return this.rankings;
}
public String getPreferences(){
return this.preferences;
}
public char getPersonalityType(){
return this.personalityType;
}
public String getConflict(){
return this.conflict;
}
//Modifier Methods
public boolean setPreferences(String pref){
this.preferences = pref;
return true;
}
public boolean setGrades(String grades){
this.rankings = grades;
return true;
}
public boolean setPersonalityType(char pers){
this.personalityType = Character.toUpperCase(pers);
return true;
}
public boolean setConflict(String ids){
this.conflict = ids;
return true;
}
#Override
public String toString(){
return studentID + ";" + rankings + ";" + personalityType + ";" + conflict + ";" + preferences;
}
}
The ArrayList deserializedStudents is initiated at the top of the class like so: ArrayList<Student> deserializedStudents = new ArrayList<>();
For some reason the following line of readStudentInfo() gives this warning : Type safety: The expression of type ArrayList needs unchecked conversion to conform to ArrayListJava(16777748)
If I ignore it and run the program regardless, the readStudentInfo() method gives the following error: Exception in thread "main" java.lang.ClassCastException: class Student cannot be cast to class java.util.ArrayList (Student is in unnamed module of loader 'app'; java.util.ArrayList is in module java.base of loader 'bootstrap')
Can someone please help me to understand why this is happening? I've tried changing the cast in the following line a few times: deserializedStudents = (ArrayList) ois.readObject();. I've also tried changing things around a little where I initiate the ArrayList at the start of the program, but no luck yet.
Clarification: The basic idea here is that I'm trying to deserialize a bunch of Student type objects into an ArrayList so that I can use them again.
Please help!
It seems like you did not serialize a list of Students (which is an own object) but Students one by one. Therefore you should either serialize a list or you should deserialize the Students one by one (by continously calling readObject()).
Try this (using try-with-resources):
public void readStudentInfo() {
try (FileInputStream fis = new FileInputStream("student.ser");
ObjectInputStream ois = new ObjectInputStream(fis)) {
List<Student> deserializedStudents = new ArrayList<>();
while (fis.available() > 0) {
deserializedStudents.add((Student) ois.readObject());
}
deserializedStudents.foreach(student -> System.out.println(student));
} catch(IOException | ClassNotFoundException exc){
exc.printStackTrace();
}
}
Here's an article on Dozer: https://www.baeldung.com/dozer. It's a mapper that uses reflection to map same-name fields from one object to another (of a completely unrelated class).
I was wondering if this works flexibly with private fields, getters, and setters. That is,
Will private String a map to another object's private String a without either having any getters or setters?
What if only one side has a getter or setter (and the private field is named something different to make sure it's not directly accessing private fields)?
What if one has a getter and the other has a setter for totally mismatching private fields? (But the getter and setter names match.)
I wrote a test program to run in https://www.jdoodle.com/online-java-compiler:
import org.dozer.DozerBeanMapper;
public class Main {
public static class MySource {
// a -> a
private String a;
// getB() -> b
private String hidden_b;
public String getB() { return hidden_b; }
// c -> setC(c)
private String c;
// getD() -> setD(d)
private String hidden_d;
// proper getters and setters on both sides
private String proper;
public String getProper() { return proper; }
// public void setProper(String proper_) { proper = proper_; }
public MySource() {
a = "A Room with a View";
hidden_b = "The Bridge of San Luis Rey";
c = "Civilwarland in Bad Decline";
hidden_d = "Darkness at Noon";
proper = "This should copy, at minimum.";
}
public void print() {
System.out.println("Source");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("hidden_b = " + hidden_b);
System.out.println("c = " + c);
System.out.println("hidden_d = " + hidden_d);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static class MyTarget {
private String a;
private String b;
private String hidden_c;
private String hidden_e;
public void setC(String param) { hidden_c = param; }
public void setD(String param) { hidden_e = param; }
private String proper;
// public String getProper() { return proper; }
public void setProper(String proper_) { proper = proper_; }
public MyTarget() {}
public void print() {
System.out.println("Target");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("hidden_c = " + hidden_c);
System.out.println("hidden_e = " + hidden_e);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static void main(String args[]) {
MySource s = new MySource();
s.print();
System.out.println("Now dozing...");
System.out.println("");
MyTarget t = new DozerBeanMapper().map(s, MyTarget.class);
t.print();
}
}
Note that to run the above code you must add a maven dependency:
Group ID: net.sf.dozer
Artifact ID: dozer
Version: 5.5.1
And also you must try executing a few times because of random timeouts depending on whether the dependency loads fast enough.
Anyway, my output was:
Source
================================
a = A Room with a View
hidden_b = The Bridge of San Luis Rey
c = Civilwarland in Bad Decline
hidden_d = Darkness at Noon
--------------------------------
proper = This should copy, at minimum.
Now dozing...
Target
================================
a = null
b = null
hidden_c = null
hidden_e = null
--------------------------------
proper = This should copy, at minimum.
So, it appears Dozer only works through a getter on the source and a setter on the target, which is disappointing. Or, I'm not using it correctly!
Is there a way to make Dozer more flexible? Or, another mapper library that can achieve this?
Okay, here are my findings. Hopefully this helps someone.
Dozer 5.5.1 was supposed to be able to do this via "class-level is-accessible." However, there was a bug. It was fixed for future releases, e.g. Dozer 6.1+. (The package moved to a new group, org.github.dozermapper.) The steps were a little complicated though, and eventually I gave up to try ModelMapper, which was much nicer. So here's my code.
Include this package:
Group ID: org.modelmapper
Artifact ID: modelmapper
Version: 2.3.2
Here's how to use it:
import org.modelmapper.ModelMapper;
import org.modelmapper.config.Configuration;
public class Main {
public static class MySource {
// a -> a
private String a;
// getB() -> b
private String hidden_b;
public String getB() { return hidden_b; }
// c -> setC(c)
private String c;
// getD() -> setD(d)
private String hidden_d;
// proper getters and setters on both sides
private String proper;
public String getProper() { return proper; }
// public void setProper(String proper_) { proper = proper_; }
public MySource() {
a = "A Room with a View";
hidden_b = "The Bridge of San Luis Rey";
c = "Civilwarland in Bad Decline";
hidden_d = "Darkness at Noon";
proper = "This should copy, at minimum.";
}
public void print() {
System.out.println("Source");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("hidden_b = " + hidden_b);
System.out.println("c = " + c);
System.out.println("hidden_d = " + hidden_d);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static class MyTarget {
private String a;
private String b;
private String hidden_c;
private String hidden_e;
public void setC(String param) { hidden_c = param; }
public void setD(String param) { hidden_e = param; }
private String proper;
// public String getProper() { return proper; }
public void setProper(String proper_) { proper = proper_; }
public MyTarget() {}
public void print() {
System.out.println("Target");
System.out.println("================================");
System.out.println("a = " + a);
System.out.println("b = " + b);
System.out.println("hidden_c = " + hidden_c);
System.out.println("hidden_e = " + hidden_e);
System.out.println("--------------------------------");
System.out.println("proper = " + proper);
System.out.println("");
}
}
public static void main(String args[]) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration()
.setFieldMatchingEnabled(true)
.setFieldAccessLevel(Configuration.AccessLevel.PRIVATE);
MySource s = new MySource();
s.print();
System.out.println("Now dozing...");
System.out.println("");
MyTarget t = modelMapper.map(s, MyTarget.class);
t.print();
}
}
Here's my output:
Source
================================
a = A Room with a View
hidden_b = The Bridge of San Luis Rey
c = Civilwarland in Bad Decline
hidden_d = Darkness at Noon
--------------------------------
proper = This should copy, at minimum.
Now dozing...
Target
================================
a = A Room with a View
b = The Bridge of San Luis Rey
hidden_c = Civilwarland in Bad Decline
hidden_e = null
--------------------------------
proper = This should copy, at minimum.
The fourth case didn't copy over but I don't really care about that case. I think it can easily achieved with a different ModelMapper configuration though. Maybe try LOOSE copying. Or worst case, manually bind the getter and setter methods in the config.
Dozer by default uses getters and setters, however you can tell Dozer (via mapping) to access the fields directly
http://dozer.sourceforge.net/documentation/custommethods.html
BTW, Dozer 5 and 6 contains an API based mapping as well.
Edited the getTypeString method in the Flowers class now I just get the pointer to the object
I'm working on a project for one of my classes. I haven't worked with HashMap before and I need to use one. In this java class I'm trying to print out the full description that I have set. But it wont print the HashMap value from the key. I have tried to use some code from my book, but with no luck.
This is the class that is calling the class that has the HashMap:
public class Garden
{
private Gardener gardener;
private Tools tools;
private Flowers flowers;
/**
* Constructor for objects of class Garden
*/
public Garden()
{
gardener = new Gardener();
tools = new Tools();
Flowers rose;
rose = new Flowers("a beautiful red flower");
rose.setFlower("red", rose);
System.out.println(rose.fullDescription());
}
}
Edited the getTypeString method
This is the class that is using the HashMap:
import java.util.Set;
import java.util.HashMap;
public class Flowers
{
private String fDescription;
private HashMap<String, Flowers> flowers;
/**
* Constructor for objects of class Flowers
*/
public Flowers(String fDescription)
{
this.fDescription = fDescription;
flowers = new HashMap<String, Flowers>();
}
public void setFlower(String color, Flowers type)
{
flowers.put(color, type);
}
public String flowerDescription()
{
return fDescription;
}
public String fullDescription()
{
return "The "+ getTypeString() + " is " + fDescription;
}
private String getTypeString()
{
String des = "";
Collection<Flowers> vals = flowers.values();
for(Flowers f : vals){
des += f;
}
return des;
}
}
The problem, I think, is in the getTypeString() function. Can anyone point me in the right direction?
Edit
I removed the getTypeString method and edited the fullDescription method:
public String fullDescription()
{
return "The "+ type + " is " + fDescription;
}
now I'm trying to get the 'HashMap' to print the objects like so:
"Flower [type= type, description= Description "]"
using thes methods:
public static void printHashMap()
{
System.out.println("hashmap: " + flowers);
}
#Override
public String toString()
{
return "Flower [type=" + type + ", description=" + fDescription ]";
}
From your post, what I have understood is that you want to print the description of flowers. So I think you can try something like:
private String getTypeString(){
String des = "";
Collection<String> vals = flowers.values();
for(String f : vals){
des = des + f.flowerDescription();
}
return des;
}
Override the toString method in your class
Declare a toString method with the following modifiers and return type:
#Override
public String toString() {
return this.fDescription;
}
Implement the method so that it returns a string.
Ok so I'm trying to get a better understanding of how to return a private variable from a class that I have created. I've only provided a small snippet of my main program to explain my question, so if more information is needed please let me know. My goal is to return a string from the class (working great), but also be able to return the private variables individually as needed (example used below is "flight_number").
public class Flights {
private String dest_city, dest_state, departureDate, departureTime;
private int flight_number;
public Flights(String city, String state, String dDate, String dTime, int flightNumber) {
dest_city = city;
dest_state = state;
departureDate = dDate;
departureTime = dTime;
flight_number = flightNumber;
}
public String toString() {
return "Flight number: " + flight_number + " Destination: " + dest_city + "," + dest_state + " Departing on:" + departureDate + " at" + departureTime + ".";
}
}
public class dummy {
public static void main(String[] args) {
// Uses the constructor to set values
Flights flight1 = new Flights("Houston", "Texas", "12/20/2014", "12:40 pm", 100);
System.out.println(flight1);
System.out.println(flight_number); // Error: `flight_number` cannot be resolved to a variable.
}
}
You need to add a public getter in Flights and call it from main:
public class Flights {
// all the private fields
public int getFlightNumber() {
return this.flight_number;
}
}
In Main:
public static void main(String[] args) {
Flights flight1 = new Flights("Houston", "Texas"); //...
System.out.println(flight1);
System.out.println(flight1.getFlightNumber()); // call the getter
}
You should start with an editor like eclipse and that should help you get started quickly. Getters and Setters is what you need, but start with Eclipse and you should do better.
I have a class called Flight
The Flight class when instantiated, instantiates another class called SeatingChart, and SeatingChart also instantiates another class and so on and so forth.
public class Flight implements Serializable
{
SeatingChart sc = new SeatingChart(); seating
//WaitingList wl = new WaitingList();
}
public class SeatingChart extends ListAndChart implements PassengerList, Serializable
{
public static final int NOT_FOUND = 42;
Passenger [] pass = new Passenger[40];
}
public class Passenger implements Serializable
{
private String firstName, lastName, fullName;
public String getName()
{
fullName = firstName + " " + lastName;
return fullName;
}
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
public void setLastName(String lastName)
{
this.lastName = lastName;
}
}
I have another method in another class that deserializes the object saved in the disk
public void actionPerformed(ActionEvent evt)
{
Serialization.deserialize(sw101); <--- sw101 is a Flight object
.
.
.
}
//code for deserialization
public static void deserialize(Flight sw101)
{
String filename = "serialized.ser";
sw101 = null;
FileInputStream fis = null;
ObjectInputStream in = null;
try
{
fis = new FileInputStream(filename);
in = new ObjectInputStream(fis);
sw101 = (Flight)in.readObject();
System.out.println("sw101" + sw101.toString());
in.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(ClassNotFoundException ex)
{
ex.printStackTrace();
}
}
my question is when I assign sw101 the serialized object, everything sw101 instantiated in the beginning like the SeatingChart sc object also get whatever is saved in the file without me doing anything as long as those objects all implement the Serializable interface? If so why is my code not working? what am I doing wrong?
It looks like you're trying to return through a reference parameter (C/C++ background?)
That never works in Java. All parameters (including references) are passed by value. Once you do
sw101=null;
you lose the reference to the object that was passed in.
Your deserialize function should return the flight object instead.
(Technically there is a way to simulate returning through the arguments in Java by using an array, but it leads to unnecessarily complicated code)
In java, all parameters are passed as values.. so the answer to your last question is no. sw101 is a reference to a copy.
As said, you have to return your deserialized object to make it work.
check this article: parameter passing in java