I have a program that adds PanelFurniture objects to an ArrayList. When i try to save the data in a file, it is giving me the exception java.io.NotSerializableException: PanelFurniture$1. PanelFurniture is the name of the class, and it implements Serializable already, so I don't understand what the problem might be.
This is my code for writing the ArrayList to the file
if(ae.getSource() == commandButtons[5]) {
int x = 5 , y = 11;
File confidential = new File("secrets.txt");
PrintWriter output = null;
try {
saveFile = new FileOutputStream("myFile.dat");
save = new ObjectOutputStream(saveFile);
save.writeObject(orderList);
save.close();
System.out.println(orderList);
}
catch (Exception e){
e.printStackTrace();
}
}
}
PanelFurniture$1 refers to an anonymous inner class, which apparently does not implement Serializable. So you should qualify the corresponding class member with transient (or make it a local variable instead), as anonymous classes are not supposed to contain serializable data. If yours does, you should turn into a normal (named) inner class and have it implement Serializable.
Your PanelFurniture class, which is the content of your ArrayList, needs to implement the Serializable interface, as well as any anonymous inner classes (like PanelFurniture$1), so Java doesn't know how to read/write this data to disk.
If you don't want to use serialization, you are probably wanting to do something like this... (psuedocode)
Create a FileOutputStream
for (each item in the ArrayList){
get the properties of the PanelFurniture object, and write them to the FileOutputStream.
eg. fos.writeLine(panelFurniture.getName() + "," + panelFurniture.getValue());
}
Close the FileOutputStream.
Taking a look at the JavaDoc for the writeObject() method:
Throws:
NotSerializableException - Some object to be serialized does not implement the java.io.Serializable interface.
Are you sure that the elements making up your ArrayList implement the Serializable Interface?
Your issue is linked to the subModel incluyed on your arraylist
For each model on your object, you must add "implements Serializable" and include the autogenerated "private static final long serialVersionUID "
by that way you can save and entire list without any exceptions
Related
I have a game that runs on a similar system to games like terraria or minecraft, at least in the aspect of being blocky.
I have constructed it in a way where each block is an Object, and there is a specific class (extends a BlockObject archetype) for each type of block.
I have the game save the blocks in a file like following
I get the name of the instance of the Object i am saving, and store it in a string
I start writing the information of the given Object in a string that has the Name of the Class(signifieing what type of block it is Ex. a block that is an object of BlockGrass.java would be stored as BlockGrass).
Normally when reading information from a save file I am reading the save file, when it gets to the info of the blocks it first saves the Block type in a local string (BlockGrass in this case), also saves the positions (x cordinate, and y cordinate). Then it would run through a series of if statements like the following
if(blockType.equals("BlockGrass"))
{
blocksArray.add(new BlockGrass(...));
}
else if(blockType.equals("BlockStone"))
{
blocksArray.add(new BlockStone(...));
}
etc
now I want to make my game vary dynamic, and want it so that if someone decides to make a new Block class (Modding the game) they do not have to modifiey the MapReader class. so instead of running through a series of if statements as shown above (where everytime a new block class is created, a new if statement must be placed for that block), i want it so that it make a new object of a class that has the same name as the BlockType. to give you a better idea look at the following
BlocksArray.add(new blockType(...));
the reason what is shown above does not work is because blockType is a string that holds the name of the class i want to use. not a Class Name
How could i do something like that?, without using if-statements.
What you are trying to do is to take advantage of polymorphic behaviours from your BlockObject hierarchy. Therefore using class.forName is the good approach. Once you have invoked newInstance()on the Class variable you will need to cast it to the base class (the archetype as you called it) of your hierarchy of BlockObject class. We have guarantee that since the real class is extending BlockObject, it is a BlockObject according to the definition of inheritance.
Here is an example
public class GameLoader {
private List<BlockObject> blocksArray = new ArrayList<BlockObject>();
public Object getNewBlock(String blockClassName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class blockClass = Class.forName(blockClassName);
return blockClass.newInstance();
}
public void addNewBlockType(String typeName) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
BlockObject castedType = (BlockObject)getNewBlock(typeName);
blocksArray.add(castedType);
}
}
Any method of the base class invoked on such object will display polymorphic behaviours.
This is not compiled and checked but it is just to indicate what must be done.
// first get the class
Class<?> rawclass = Class.forName(String);
// then check an object will fit where you want it.
if (BlockObject.class.isAssignableFrom(rawclass)){
// create the object, cast it to the correct type and add it
BlockObject object = (BlockObject) rawclass.newInstance();
blockArray.add(object);
}
There will be some exceptions to catch out of the forName and newInstance methods.
I have a problem with trying to equate an interface to a class that implements that class.
I have an interface called SortedSetADTx.java
I have a class called BstSetKTUx.java
Now in the my main class I have two variables
private static SortedSetADTx<Automobilis> autoSet;
private static BstSetKTUx<Automobilis> autoSetBst;
and in one of my function I want to do this:
autoSet = new BstSetKTUx(new Automobilis());
autoSetBst = autoSet;
And I get an error that those two are incompatible types.
The reason I am doing that, I want to use a function that BstSetKTUx class has.
I hope you can understand my question, it's really hard to explain.
You may want to try typecasting autoset since it isn't of type BstSetKTUx... you can only equate objects that are from the same class.
i.e. autoSetBst = (BstSetKTUx<Automobilis>)autoset;
Granted that BstSetKTUx implements SortedSetADTx, you can simply try this chunk of code:
autoSet = new BstSetKTUx<Automobilis>(new Automobilis());
autoSetBst = (BstSetKTUx<Automobilis>) autoSet;
The major change I did here is a cast to BstSetKTUx<Automobilis>. Since we know that autoSet contains a BstSetKTUx<Automobilis> (see first line of my snippet), we can cast without having to check for autoSet's class first.
If you happen to not know what autoSet contains before you try to cast to BstSetKTUx<Automobilis>, I recommend using the instanceof operator.
// given we don't know if autoSet contains a BstSetKTUx instance or not
if(autoSet instanceof BstSetKTUx) {
// we can cast to BstSetKTUx without any problems
autoSetBst = (BstSetKTUx<Automobilis>) autoSet;
} else {
// autoSet does not contain an instance of BstSetKTUx
}
Besides that, it's good programming practice that you always specify the type arguments of a class (<Automobilis>), even when you're calling a constructor. ;)
You have the following variables:
SortedSetADTx<Automobilis> autoSet;
BstSetKTUx<Automobilis> autoSetBst;
Note that autoSet is of type SortedSetADTx but not BstSetKTUx. However, autoSetBst is of type BstSetKTUx, and also of type SortedSetADTx, since BstSetKTUx implements SortedSetADTx.
Therefore, you can't assign autoSet to autoSetBst, but you can do it the other way round:
autoSetBst = new BstSetKTUx(new Automobilis());
autoSet = autoSetBst;
Let's say we have 3 Classes:
class foo { // not a singleton
String s;
}
class bar {
foo f;
int i;
}
class baz {
foo sameF;
}
Now we create instances
foo onlyFoo = new foo("the only one");
bar theBar = new bar(onlyFoo, 123);
baz theBaz = new baz(onlyFoo);
After that we want to store them serilazed in a file.
If we deserialze theBaz, modify onlyFoo and deserialize theBaz to the file again, theBar still contains the original onlyFoo, so there are two different versions of onlyFoo.
What I want instead is that I store theBaz and theBar without onlyFoo, store the three objects separately and once someone deserialize theBaz I want to give him onlyFoo, too. If he deserializes the changed onlyFoo again, theBaz and theBar will have the same modified onlyFoo, so if someone requests an object (for example theBar) he gets the full serialized object with all the referenced objects (onlyFoo) like the normal serialization process would return.
I know that I have to store the objects and keep the references manually and separately because the default serialization cannot handle this problem. What I don't know is how do I partially serialize/deserialize Java objects? I need to separate the primitives and their wrappers from the 'higher' objects and store this objects separately.
Update
I cannot modify the classes.
I don't know all classes. It should work with all serializable objects I maybe never heard about (they may or may not be final)
If you want more controll you could overwrite writeObject() and readObject()
and serialize yourself.
class bar {
...
private void writeObject(ObjectOutputStream stream) throws IOException {
// let version 1, later when you need to have versioning.
stream.writeInt(version);
stream.writeInt(i);
// leave out
// stream.writeObject(foo);
}
}
// read object the analog, see
http://docs.oracle.com/javase/6/docs/platform/serialization/spec/output.html#861
Mark references you don't want serialized with transient keyword.
You can make foo transient as below.
class bar {
transient foo f;
int i;
}
I would like to know how to save an ArrayList of abstract Objects to a file.
So far I only save primitive types or ArrayLists of primitive types by converting them to a comma separated String and storing this with a buffered reader.
But now I have got an ArrayList of Game Elements, which have really different properties and Constructors, so my normal approach won't work. There has to be something nicer than storing each to a file or each type of Object to a file or add plenty of seperator levels.
How do I do this in a nice way?
Have a look at Serialization, there are plenty of tutorials out there so I am not going to post any code:
http://www.tutorialspoint.com/java/java_serialization.htm
You can not instantiate Abstract Objects so you will need a child class which extends it. Also Abstract class should implement Serialize. Then using ObjectOutputStream you can directly write ArrayList using writeObject() method.
Below is the sample application
public abstract class Parent implements Serializable {
public abstract String getValue(); //Just to show value persist
}
public class Child extends Parent {
String value = null;
Child(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
// No throws clause here
public static void main(String[] args) throws FileNotFoundException,
IOException, ClassNotFoundException {
//create Arraylist
ArrayList<Parent> parents = new ArrayList<Parent>();
parents.add(new Child("test"));
//store
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
new FileOutputStream("test.txt"));
objectOutputStream.writeObject(parents);
objectOutputStream.close();
//Read back
ObjectInputStream objectInputStream = new ObjectInputStream(
new FileInputStream("test.txt"));
ArrayList<Parent> readObjects = (ArrayList<Parent>)objectInputStream.readObject();
System.out.println(readObjects.get(0).getValue());
}
The answer could be two.
Depending on what is the usage of the file later.
ANS 1: It you want the object values to be saved temporarily in the file and reload it again from the file, then serialization is the best options.
ANS 2: If the file is output of the program and then you try the below
option#1: Start each line in the file with the unique object name
OBJECT1, blue, pink, yellow....
OBJECT2, rose, dairy, sunflower, cauliflower..
option#2 instead of the flat file(txt) you can use an apache poi framework to write
the object in more organised way.
Say, I have a class X which has a field value, that is,
class X implements Serializable {
private int value;
// ...
}
Further it has getters and setters not displayed here. This class is serialized.
At the deserialzation, end same class has value field and access specifier is public. Further, this class does not have getters and setters. So, my questions are:
Does deserialization fail in case the access specifier of the field changes OR some or all of the methods go missing in the class at the deserialization end?
What is the mechanism by which fields are assigned their values during deserialization?
Some good links The Java serialization algorithm revealed
1) does deserialization fail in case the access specifier of the field
changes OR some or all of the methods go missing in the class at the
deserialization end ?
Serialization happens using Using Reflection
Java Detects the changes to a class using the
private static final long serialVersionUID
The default involves a hashcode. Serialization creates a single hashcode, of type long, from the following information:
The class name and modifiers
The names of any interfaces the class implements
Descriptions of all methods and constructors except private methods and constructors
Descriptions of all fields except private, static, and private transient
The default behavior for the serialization mechanism is a classic "better safe than sorry" strategy. The serialization mechanism uses the suid, which defaults to an extremely sensitive index, to tell when a class has changed. If so, the serialization mechanism refuses to create instances of the new class using data that was serialized with the old classes.
2) what is the mechanism by which fields are assigned their values
during deserialization ?
The real details can be read in the Java Object Serialization Specification.
To answer your questions:
Serialization has a basic sanity check to see if the serialization ends use the same version of a class: the serialVersionUID member must be equal. Read the section Stream Unique Identifiers to know more about it. Basically, it's a static value which you can either manage yourself by declaring it on your class, or let the compiler generate one for you. If the compiler generates it, ANY change to a class will result in a change of serialVersionUID and hence will make the deserialization fail if the ends do not have exactly the same classes. If you want to avoid this, declare the variable yourself and update it manually when a change to the class' member variables does make classes incompatible.
The Java Virtual Machine does a lot of the magic here, it can access all internal state directly without the need for getters (fields marked transient or static aren't serialized though). Also, while the Serializable interface doesn't specify any methods to implement, there are a number of 'magic methods' which you can declare to influence the serialization process. Read section "The writeObject Method" and onwards to know more. Be aware though that you should use these sparingly as they might confuse any maintenance developers!
You don't need to have getters/setter to serialize/deserialize using java serialization, for example, check this code:
public class Main {
public static class Q implements Serializable {
private int x;
public Q() {
x = 10;
}
public void printValue() {
System.out.println(x);
}
}
public static void main(String[] args) throws Exception {
Q q = new Q();
FileOutputStream fos = new FileOutputStream("c:\\temp.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(q);
fos.close();
FileInputStream fis = new FileInputStream("c:\\temp.out");
ObjectInputStream oin = new ObjectInputStream(fis);
Q q2 = (Q)oin.readObject();
fis.close();
q2.printValue();
}
}
I don't really know how you get this results, but what you tell is not the default behaviour of serialisation. So, I guess you are using it wrong. Here is some sample code:
public class X implements Serializable
{
private int value;
public int getValue() { return value; }
}
Here the serialisation/deserialisation process:
X x = new X();
x.setValue(4);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputSteam(buffer);
oos.writeObject(x);
oos.flush();
oos.close();
ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
Object obj = ois.readObject();
if (obj instanceof X)
{
X readObject = (X) obj;
System.out.println(readObject.getValue());
}
You probably used Java Reflection to get your results. Make sure you use getDeclaredFields(); and getDeclaredMethods(); instead of the variants without Declared in the method name.
Does deserialization fail in case the access specifier of the field changes
No.
OR some or all of the methods go missing in the class at the deserialization end?
Yes, unless the receiving class has a serialVersionUID member whose value equals the value encoded in the stream.
what is the mechanism by which fields are assigned their values during deserialization?
Too broad, but:
Reflection, and
name matching (rather than matching by position in the class and stream).