I was wondering if there was an easy way to save arrays of objects, without having to go through and save each aspect of the the objects. In my example I have two arrays, one a single array and the other a 2D array, that contain objects referring to a custom class. Each object has specific details like x and y ints, booleans, strings, ect. attached to them (block[0].x, block[0].canWalk, block[0].name) and I was wondering if there is an easy way of saving these arrays to a file without having to use a for loop and save each part. The multidimensional array is simply an array of saved arrays identical to the first one (savedBlock[0][0].x ...)
What I have so far (throwing NotSerializableException):
public class Save
{
static File f;
static ObjectOutputStream os;
public static void openFile()
{
try
{
if(!new File("c:\\IDsGame").exists())
{
new File("c:\\IDsGame").mkdirs();
}
f = new File("c:\\IDsGame\\data.bin");
os = new ObjectOutputStream(new FileOutputStream(f));
writeFile();
}
catch(Exception e)
{
System.err.println("creating file");
}
}
public static void writeFile()
{
try
{
ArrayList<Object> map = new ArrayList<Object>(Arrays.asList(Map.block));
ArrayList<Object> savedMaps = new ArrayList<Object>(Arrays.asList(Map.savedMaps));
os.writeObject(map);
os.writeObject(savedMaps);
os.close();
}
catch (IOException e) {System.out.println(e);}
}
}
Within my map class I initialize block (Blocks[]) and savedMaps(Blocks[][]). My Blocks class holds this:
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public Image img = null, imgBack = null;
public final Image (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Obviously I change the certain parts different arrays within the Map class, and I was wondering if there was any easier way (at all) to save the arrays of Blocks Objects.
Thanks for taking your time to help and if you need any more specific just let me know.
I.D.
Image is not serializable, so you receive a NotSerializableException when the Blocks class is serialized. ImageIcon can be serialized, so wrapping Image instances in ImageIcons will solve that issue.
public class Blocks implements Serializable
{
public boolean canWalk, onTop, itemTaken;
public ImageIcon img = null, imgBack = null;
public final ImageIcon (a ton of different images)
public String name, item, message, title;
public char initMap, initEx, initIt;
public int x, y, height, width;
public Blocks()
{
canWalk = true;
onTop = false;
itemTaken = false;
img = null;
// img = new ImageIcon(someImageInstance)
name = null;
item = null;
message = null;
x = 0;
y = 0;
height = 0;
width = 0;
}
}
Just making a class implement Serializable is not enough: All the fields must be Serializable too.
Your Block class may have a problem. All the usual java classes are Serializable, but Block also has fields of type Image. If Image isn't Serializable, then attempting to serialize Block will throw NotSerializableException.
Related
This question already has answers here:
Clone JavaFX Node?
(2 answers)
Closed 3 years ago.
I'm trying to deep copy an array of my custom object "Space", which extends javafx Pane.
I've tried using Kryo libraries, and implementing clonable. I could use work arounds that don't actually deep copy, but that will make my code 100x more janky.
Currently I have the class Space:
public class Space extends Pane {
private boolean available = true;
private boolean light;
private int x;
private int y;
private Peice peice;
private Label peiceImage;
private Rectangle border;
public Space() {}
public Space(int x, int y, boolean light) {
border = new Rectangle(80,80);
if (!light) {
border.setFill(Color.DARKGREEN);
border.setStroke(Color.DARKGREEN);
} else {
border.setFill(null);
border.setStroke(null);
}
peiceImage = new Label();
peiceImage.setTranslateX(16);
peiceImage.setTranslateY(16);
getChildren().addAll(border,peiceImage);
this.x = x;
this.y = y;
this.peice = null;
this.light = light;
}
//other unimportant methods.
}
I then try to copy in another file:
public Space[][] copyBoard(Space[][] thisBoard) {
Kryo kryo = new Kryo();
Space[][] copy = new Space[8][8];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
Space thisSpace = thisBoard[x][y];
try {
kryo.setRegistrationRequired(false);
copy[x][y] = kryo.copy(thisSpace); //TODO This causes exception, dosent work
} catch (Exception e) {
System.out.println(e);
}
}
}
return copy;
}
Trying to use the kryo library I get this error:
com.esotericsoftware.kryo.KryoException: Class cannot be created (missing no-arg constructor): javafx.scene.layout.Region$3
But I'm not in any way commited to using kryo.
Thanks.
You can do deep copy using serialization and afterward deserialization. There are nice utils to do so on the web. For example SerializationUtils from Apache.
You can do something like the following:
Space clonedSpace = SerializationUtils.clone(space);
Docs
I am working on a program that is supposed to implement an electronic store. I had to create 3 classes (desktop, laptop and fridge) with specific defined functionality which I did. I am stuck on how to create the Electronic store class in which the constructor for this class
must create three instances of each of the previous three classes (9 items in total, using the
constructors defined in those classes) and store them within the ElectronicStore instance being created. I am unsure on how to do the above and would appreciate assistance. Below is what I have gotten so far.
// Desktop class
public class Desktop{
double speed = 0;
int ram, storage = 0;
boolean storageType;
public Desktop(double s, int r, int p, boolean t){
speed = s;
ram = r;
storage = p;
storageType = false;
}
// This is a String representation of the Desktop object
//#Override
public String toString(){
return "#"+speed+"#"+ram+"#"+storage;
}
}
// Laptop class
public class Laptop{
double CPU;
int RAM, storage, size;
boolean storeType;
public Laptop(double C, int R, int st, int si){
CPU = C;
RAM = R;
storage = st;
size = si;
storeType = false;
}
// This is a String representation of the Desktop object
public String toString(){
return "#"+CPU+"#"+RAM+"#"+storage+"#"+size;
}
}
// Fridge class
public class Fridge{
double fridge;
boolean freezer;
String color;
public String toString(){
return "#"+fridge+"#"+color;
}
}
// ElectronicStore class (which i am stuck with)
public class ElectronicStore{
public ElectronicStore()
{}
}
You create an instance of a class like so:
Desktop desktopOne = new Desktop(x, y, z);
To store them you can either have class variables (like you have for speed, ram) etc., or you could use a data structure like a list. Further clarification needed on that point.
I think it should be something like this
public class ElectronicStore{
private ArrayList<Fridge> fridges = new ArrayList<>();
public ElectronicStore()
{
Fridge fridge1 = new Fridge();
Fridge fridge2 = new Fridge();
Fridge frigde3 = new Fridge();
fridges.add(fridge1);
fridges.add(fridge2);
fridges.add(fridge3);
...
}
}
And you have to do the same thing to create the other objects.
I have a base class named Train:
public abstract class Train {
String serialNo;
float weight;
final String label;
public Train(String serialNo, float weight, String label) {
this.serialNo = serialNo;
this.weight = weight;
this.label = label;
}
public abstract float getCapacity();
}
And I have 2 classes implementing the abstract class(I will not include getters and setters in the code):
public class FreightTrain extends Train implements Cloneable {
private float capacityKg;
Vector<String> freightVector = new Vector<String>();
public FreightTrain(String serialNo, float weight, String label) throws Exception{
super(serialNo, weight, label);
if (weight < 0)
throw new Exception();
}
#Override
public float getCapacity() {
return this.capacityKg;
}
}
And the PassengerTrain class:
public class PassengerTrain extends Train implements Cloneable {
private float seatNo;
Vector<String> passengerId = new Vector<String>();
public PassengerTrain(String serialNo, float weight, String label) throws Exception{
super(serialNo, weight, label);
if (weight < 0)
throw new Exception();
}
#Override
public float getCapacity() {
return this.seatNo;
}
}
Next I have an array list ArrayList<Train> arr; which contains both: the PassengerTrain and FreightTrain. I want to create methods to write the items from arr to a file and read the data from file
Here is my attempt:
public void writeObjectInTextFile(ArrayList<Train> array) {
Formatter f = null;
try {
f = new Formatter(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
for(Train train: array) {
if(train instanceof PassengerTrain) {
String label = train.getLabel();
String serialNo = train.getSerialNo();
float capacity = train.getCapacity();
float weight = train.getWeight();
float seatNo = ((PassengerTrain) train).getSeatNo();
String passId = "";
for(String id:((PassengerTrain) train).getPassengerId()) {
passId += id;
}
f.format("%s %f %s %f %f %s", serialNo, weight, label, capacity, seatNo, passId);
} else if(train instanceof FreightTrain) {
String label = train.getLabel();
String serialNo = train.getSerialNo();
float capacity = train.getCapacity();
float weight = train.getWeight();
float capacityKg = ((FreightTrain) train).getCapacityKg();
String freightVector = "";
for(String freight: ((FreightTrain) train).getFreightVector()) {
freightVector += freight;
}
f.format("%s %f %s %f %f %s", serialNo, weight, label, capacityKg, capacity, freightVector);
}
}
f.close();
}
But I have a problem: I am unable to create a function that will read this data from the file, and return the correct ArrayList with the initial data.
What is the best and fastest way to write the array of 2 different classes deriving from a single class to a file?
And how it could be recreated?
Thank you!
Please don't my question as duplicate. I have searched for similar questions and my question is different from the ones available.
I don't know how to convert back the objects from file to their respective types. What If I have n deriving classes?
Simply have your classes implement Serializable and you'll be ready to write your objects to files (and read them back, of course) whenever you want! This includes arrays of your objects, too.
That's the 10000-foot answer above. Implementing Serializable correctly (in a way that won't come back around to bite you) is a somewhat daunting subject. However, there is plenty of literature out there that can teach you how to do it and how to avoid common pitfalls. I recommend Joshua Bloch's "Effective Java" for this, personally; he's dedicated a whole chapter or two to the subject.
if(train instanceof PassengerTrain) This is bad. You are completely throwing the whole purpose of inheritance and polymorphism away. Your code shouldn't care about what type the trains are.
You should use the Object serialization features of Java. Implement Serializable in your Train class and use ObjectOutputStream to write and ObjectInputStream to read the objects.
Write:
public void writeTrainsToFile(ArrayList<Train> array, String file) {
FileOutputStream fileOutputStream = new FileOutputStream(file);
try(ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream)){
objectOutputStream.writeInt(array.size());
for(Train train: array) {
objectOutputStream.writeObject(train);
}
}
}
Read:
public void readTrainsFromFile(ArrayList<Train> array, String file) {
FileInputStream fileInputStream = new FileInputStream(file);
try(ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)){
int trainCount = objectInputStream.readInt();
for (int i = 0; i < trainCount; i++) {
array.add((Train)objectInputStream.readObject());
}
}
}
I am currently making a terrain generator, everything works fine in one class but I am going to be expanding my application.
Currently I have a JFrame class which holds everything, generating the terrain, painting the terrain, finding locations etc.
I want to add another class that will generate the terrain but when I create this class I need to access fields from the main JFrame class and when I do I get a stack overflow error - here is my code.
public class Simulator extends Applet
{
//fields
public Simulator()
{
grid = new int[100][100];
inhabGrid = new boolean[grid.length][grid.length];
gridSize = grid.length - 1;
dist = grid.length;
TerrainGenerator gen = new TerrainGenerator();
setSize(dist,dist);
seedGrid();
findInhabLocation();
printGridToConsole();
}
public void paint(Graphics g)
{
//panting the grid
}
public void seedGrid()
{
//seeding
}
public boolean generateTerrain(int x1,int y1, int x2, int y2)
{
//terrain generator
}
public boolean mouseUp(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public boolean keyEvents(Event evt, int x, int y)
{
seedGrid(); //Create a new map
findInhabLocation();
repaint();
printGridToConsole();
return true;
}
public void findInhabLocation()
{
//find best inhabitant location
}
public int locateWater(int x, int y)
{
//finding closest water
}
public int locateJungle(int x, int y)
{
//finding closest jungle
}
}
}
That works fine in its own class but when I create a class for example:
public class TerrainGenerator
{
Simulator sim = new Simulator();
}
I know this has something to do with the constructor and it's something silly I am doing, what would be the best way of splitting up this app into classes, for example terrain generator, inhabitants etc
For example I want to be able to call a method from the 'TerrainGenerator' class and call i.e. terrainGenerator.generateTerrain
Your TerrainGenerator creates a Simulator object and vice versa, hence you'll end up with infinitely many objects (but at some point the stack is full and a stack overflow exception is thrown instead...)
Instead of creating a new Simulator in your TerrainGenerator, you should pass a reference to your current Simulator (well, actually, that is not a great design either, but I'm not gonna confuse you with the problems of circular references).
Heuster answer is correct, furthermore, I think you could take look at MVC to help you organize your classes.
Depending which should be the parent, you can pass in the instantiated class to the other, ie;
private final TerrainGenerator gen; //if you need to save this.
public Simulator(TerrainGenerator terrainGenerator)
{
this.gen = terrainGenerator;
....etc
}
public class TerrainGenerator
{
Simulator sim = new Simulator(this);
}
or
private final TerrainGenerator gen; //if you need to save this.
public Simulator()
{
this.gen = new TerrainGenerator(this);
....etc
}
private final Simulator sim; //If you need to save it.
public class TerrainGenerator
{
public TerrainGenerator(Simulator simulator) {
this.sim = simulator;
}
}
I'm trying to serialize my model inside my program. The model is named "ImageModel" and it implements Serializable. This model also contains another custom object named "Perspective" which is also implementing Serializable. I have a static utility class that serializes my model and reads it. This code has been tested in the main method with an "ImageModel" and everything is working perfectly.
But when I try to use it in the actual program I'm running into an issue. The "ImageModel" class is declared in my system class, named "MainWindow" which extends JFrame and is the link between most of the different classes. For some reason, I can't serialize the model doing something like MainWindow.getModel(). The compiler argues that my "EventFactory" is not serializable. This class is also declared in "MainWindow", but I'm not even understanding why Java wants to serialize it, I'm under the impression that java is not just trying to serialize the model, but also the GUI.
Here are segments of code :
My model:
public class ImageModel extends Observable implements Cloneable, Serializable {
private String path;
private ArrayList<Observer> observers;
private ArrayList<Perspective> perspectives;
private int numPerspectives;
private Perspective selectedPerspective;
...
}
The perspective class:
public class Perspective implements Serializable {
private ImageModel image;
private int degreeOfRotation;
private Point topLeftPoint;
private int zoomPercentage;
private int height;
private int width;
...
}
The actual GUI that declares the model and other elements:
public class MainWindow extends JFrame {
private final int GRID_ROWS = 0;
private final int GRID_COLUMNS = 2;
private final int NUM_PERSPECTIVE = 3;
private JPanel mainPane;
private ArrayList<View> perspectiveList;
private ImageModel imageModel;
private EventFactory eventFactory;
private JMenu menu;
private JToolBar toolBar;
...
}
The main method:
MainWindow mw = new MainWindow();
/*
* Does NOT work:
* ImageModel imageModel= mw.getImageModel();
* Utility.serializeModel(imageModel); //Crashes
*
* Works:
*
* ImageModel imageModel= new ImageModel();
* Utility.serializeModel(imageModel);
*
*/
Here are my two utility functions in case you need them :
public static void serializeModel(ImageModel imageModel)
{
String filename = "TEST.ser";
FileOutputStream fos = null;
ObjectOutputStream out = null;
try
{
fos = new FileOutputStream(filename);
out = new ObjectOutputStream(fos);
out.writeObject(imageModel);
out.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
public static ImageModel restoreModel(String filename)
{
ImageModel imageModel = null;
FileInputStream fis = null;
ObjectInputStream in = null;
try
{
fis = new FileInputStream(filename);
in = new ObjectInputStream(fis);
imageModel = (ImageModel)in.readObject();
in.close();
}
catch(IOException ex)
{
ex.printStackTrace();
}
catch(ClassNotFoundException ex)
{
ex.printStackTrace();
}
return imageModel;
}
Here's the STACK_TRACE of the error I'm receiving when working on the actual use case:
http://pastie.org/3008549
So yeah, like I'm saying, it's like if Java was trying to serialize other stuff around the model.
I'm guessing EventFactory is somehow making it's way into ImageModel's fields. Maybe indirectly linked from an Observer. Perhaps you should clear that list before attempting to serialise or set that field as transient.