Valhalla Legends Archive

Programming => General Programming => Java Programming => Topic started by: iago on April 14, 2004, 10:10 AM

Title: Savable - Handy code
Post by: iago on April 14, 2004, 10:10 AM
Read the comments for more info on how this works/how to use it.

/*
* Savable.java
*
* Created on March 29, 2004, 11:43 AM
*/

package bot.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
* Any class that implements this can easily be saved and loaded.  Basically, you can
* call <PRE>this.save(filename)</PRE> and it will be saved to that file, or
* <PRE>MyClass c = MyClass.load(filename)</PRE> to load it.
* <P>
* Note that every instance variable in the class must be either a primitive type or
* a class that implements Serializable, otherwise, I'm told, something will blow up.
*
* @author  iago
*/
abstract public class Savable implements Serializable
{
   /** The class saves itself to the specified filename.
    * @param filename The file object to save the object as.
    * @throws IOException If there is a problem saving the file.
    */
   public void save(File filename) throws IOException
   {
       ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename));
       out.writeObject(this);
       out.close();
   }
   
   /** The class saves itself using a String for a filename rather than using a File object.
    * @param filename The path/name to save the file to.
    * @throws IOException If there is a problem saving the file.
    */
   public void save(String filename) throws IOException
   {
       save(new File(filename));
   }
   
   /**
    * Load and return an instance of the object.  If there's an error during the load,
    * an exception is thrown.
    * @param filename The file object representing the file to load.
    * @return An instance of the object, loaded from the file.
    * @throws IOException if the file isn't found or if the file is an invalid format.
    */
   public static Savable load(File filename) throws IOException
   {
       try
       {
           ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename));

           Savable ret = (Savable) in.readObject();
           in.close();

           return ret;
       }
       catch(ClassNotFoundException e)
       {
           throw new IOException("Unable to read the file: " + e.toString());
       }
   }
   /**
    * Load and return an instance of the object.  If there's an error during the load,
    * an exception is thrown.
    * @param filename A String object representing the full or relative path to the file.
    * @return An instance of the object, loaded from the file.
    * @throws IOException if the file isn't found or if the file is an invalid format.    
    */
   public static Savable load(String filename) throws IOException
   {
       return load(new File(filename));
   }
   
}
Title: Re:Savable - Handy code
Post by: Banana fanna fo fanna on April 14, 2004, 02:07 PM
Why is this better than Serializable?
Title: Re:Savable - Handy code
Post by: iago on April 14, 2004, 02:31 PM
Quote from: St0rm.iD on April 14, 2004, 02:07 PM
Why is this better than Serializable?

It uses serializable.  It just saves the effort of creating the ObjectOutputStream/ObjectInputStream and creating the File object.
Title: Re:Savable - Handy code
Post by: MyndFyre on April 14, 2004, 02:32 PM
Quote from: St0rm.iD on April 14, 2004, 02:07 PM
Why is this better than Serializable?

indeed, in fact I would say that Serializable is better.  No offense, iago, but here's the problem...

Say you have abstract class Car already made in a library.  You want to derive class HondaAccord as well as make it Savable; however, you can't do that, because Java doesn't support double inheritence.  You can have a ton of interfaces (such as Serializable) on a class, but you can't have:


package MyndFyre.Vehicles;

import Generics.Car;

public class HondaAccord extends Car, Savable
{
//...
}


but you can have:


package MyndFyre.Vehicles;

import Generics.Car;

public class HondaAccord extends Car implements Serializable
{
//...
}
Title: Re:Savable - Handy code
Post by: iago on April 14, 2004, 02:46 PM
If you need to extend something else, then your superclass can (probably) extends Savable.  If not, then just use serializable and write the extra code.

I found myself writing the same code over and over to do the same thing: save a serializable.  Mainly classes that I was using to store preferences, which wouldn't extend anything to begin with.  So I wrote a class to extend to save me time, and it has.  

So my point is, Savable can save you a little time, but if not go ahead and use Serializable :P
Title: Re:Savable - Handy code
Post by: Banana fanna fo fanna on April 15, 2004, 05:49 PM

import java.io.*;

public class Saver {
public static void save(String filename, Serializable o) throws IOException {
new ObjectOutputStream(new FileOutputStream(filename)).writeObject(o);
}
}
Title: Re:Savable - Handy code
Post by: iago on April 15, 2004, 06:06 PM
Quote from: St0rm.iD on April 15, 2004, 05:49 PM

import java.io.*;

public class Saver {
public static void save(String filename, Serializable o) throws IOException {
new ObjectOutputStream(new FileOutputStream(filename)).writeObject(o);
}
}


Ugh@* imports, clarity is more important than time.

That doesn't take care of loading.

Doesn't close the file (good coding practice).

I considered doing a static class before, but I found mine much more convenient for what I need.
Title: Re:Savable - Handy code
Post by: Banana fanna fo fanna on April 15, 2004, 06:37 PM
I'll bet you a cent that it does close the file.
Title: Re:Savable - Handy code
Post by: iago on April 15, 2004, 07:13 PM
It's better to close the file explicitly.

But, how does it know to?  There's no destructors in Java.
Title: Re:Savable - Handy code
Post by: MyndFyre on April 15, 2004, 08:04 PM
Quote from: iago on April 15, 2004, 07:13 PM
It's better to close the file explicitly.

But, how does it know to?  There's no destructors in Java.

OK iago, here:


// just for you, even though * syntax doesn't do anything bad...
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class IOer {
public static void save(String filename, Serializable o) throws IOException
{
 FileOutputStream fos = new FileOutputStream(filename);
 ObjectOutputStream oos = new ObjectOutputStream(fos);
 oos.writeObject(o);
 oos.close();
 fos.close();
}
public static Object load(String filename) throws IOException
{
 FileInputStream fos = new FileInputStream(filename);
 ObjectInputStream oos = new ObjectInputStream(fos);
 Object o = oos.readObject();
 oos.close();
 fos.close();
 return o;
}
}
Title: Re:Savable - Handy code
Post by: iago on April 15, 2004, 08:26 PM
You're right, * imports don't hurt anything programatically, but it clarifies code.  If I see a class I don't know, say, for instance, file, I can look at the imports and know to look up "java.io.file".

As for the rest of it, a static class would be ok too, but it doesn't matter :)