views:

64

answers:

2

Hi everyone. I'm writing a little Java program (it's an ImageJ plugin, but the problem is not specifically ImageJ related) and I have some problem, most probably due to the fact that I never really programmed in Java before...

So, I have a Vector of Vectors and I'm trying to save it to a file and read it.

The variable is defined as:

Vector <Vector <myROI> > ROIs = new Vector <Vector <myROI> >();

where myROI is a class that I previously defined.

Now, to write the vector to a file I use:

void saveROIs()
    {
    SaveDialog save = new SaveDialog("Save ROIs...", imp.getTitle(), ".xroi");
    String name = save.getFileName();
    if (name == null)
        return;
    String dir = save.getDirectory();

    try
        {
        FileOutputStream fos = new FileOutputStream(dir+name);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(ROIs);
            oos.close();
        }
    catch (Exception e)
        {
        IJ.log(e.toString());
        }
    }

This correctly generates a binary file containing (I suppose) the object ROIs.

Now, I use a very similar code to read the file:

void loadROIs()
    {
    OpenDialog open = new OpenDialog("Load ROIs...", imp.getTitle(), ".xroi");

    String name = open.getFileName();
    if (name == null)
        return;
    String dir = open.getDirectory();

    try
        {
            FileInputStream fin = new FileInputStream(dir+name);
            ObjectInputStream ois = new ObjectInputStream(fin);
        ROIs = (Vector <Vector <myROI> >) ois.readObject(); // This gives error
            ois.close();
            }
    catch (Exception e)
        {
        IJ.log(e.toString());
        }
    }

But this function does not work.

First, I get a warning:

 warning: [unchecked] unchecked cast found   : java.lang.Object
 required: java.util.Vector<java.util.Vector<myROI>>
            ROIs = (Vector <Vector <myROI> >) ois.readObject();
                                                        ^

I Googled for that and see that I can suppress by prepending @SuppressWarnings("unchecked"), but this just makes things worst, as I get an error:

<identifier> expected
   ROIs = (Vector <Vector <myROI> >) ois.readObject();
        ^

In any case, if I omit @SuppressWarnings and ignore the warning, the object is not read and an exception is thrown

java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: myROI

Again Google tells me myROI needs to implements Serializable. I tried just adding implements Serializable to the class definition, but it is not sufficient. Can anyone give me some hints on how to procede in this case? Also, how to get rid of the typecast warning?

+1  A: 

Every attribute of myROI must implement Serializable or must be a simple datatype like int. Is this so?

Daniel Engmann
Ok, this seems to be a good point. Some of the members of myROI are ImageJ classes not defined by me. How would I implement `Serializable` on those?
nico
First you should check if you need to serialize this attributes. If not you can make them transient:"private transient ImageJClass myimg;"In this case they will not be serialized and so it doesn't matter that they are not Serializable.
Daniel Engmann
+1  A: 
warning: [unchecked] unchecked cast found

This is innocent and should indeed be fixed using @SuppressWarnings("unchecked") annotation.

<identifier> expected

This can impossibly be caused by adding the annotation. Probably you added it at the wrong place (should be right before method declaration), or you did something else which caused that the declaration of ROIs disappeared.

java.io.NotSerializableException: myROI

This means that the class identified by the given full qualified class name is not serializable. Expect from that it is not serializable, there's another serious problem: that class is not inside a package. This is not necessarily the cause of the current problem, but this may lead to future problems because packageless classes are invisible for classes inside a package.

To make a class serializable you need to let it implements Serializable and ensure that all fields are serializable as well. Primitives are by default serializable and String itself already implements it as you can read in its Javadoc. If a field really cannot be made serializable for some reason, then you need to declare it transient and if necessary override private void readObject() and private void writeObject() accordingly so that the unserializable object can be written/read to the steam anyway. To the point, you just need to save its state in some way that exactly the same state can be restored afterwards.

E.g.

public class SerializableObject implements Serializable {

    private transient UnserializableObject unserializableObject;

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        oos.writeObject(unserializableObject.getSerializableProperty());
        oos.writeObject(unserializableObject.getAnotherSerializableProperty());
        // ...
    }

    private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        unserializableObject = new UnserializableObject();
        unserializableObject.setSerializableProperty((SomeSerializableObject) ois.readObject());
        unserializableObject.setAnotherSerializableProperty((AnotherSerializableObject) ois.readObject());
        // ...
    }

}
BalusC
Thank you, I solved the `@SuppressWarnings` problem, was just a stupid typo on my part. :PI think I will need to override `readObject` and `writeObject` at this point. One thing that is not completely clear to me is: in read/writeObject do I have to call `writeObject` only on unserializable properties? `defaultWriteObject()` deals with the serializable ones, right?
nico
You're welcome. And no, unfortunately not, you really need to include **all** properties which needs to be serialized. Since the method is `private` and the serialization API is syntactic sugar, you cannot call something like `super.writeObject(oos)` to cover the missing but serializable properties.
BalusC
@BalusC: Thank you, seems to be working now.
nico