Support for setObject getObject in PropertiesGameSettings


It struck me as strange that PropertiesGameSettings didnt support setObject.  My argument for adding it is that:


  • PropertiesGameSettings is the default (and most widely used I imagine) game settings.

  • GameControlManger.save() needs get/set object support to work.



Note: The code uses com.sun.org.apache.xerces.internal.impl.dv.util.Base64; for its Base64 encoding, which is an internal Sun library.  Libraries of this kind are used in other places in the code base, but if need be I can write a quick base64 encoder.


Index: PropertiesGameSettings.java
===================================================================
--- PropertiesGameSettings.java   (revision 4879)
+++ PropertiesGameSettings.java   (working copy)
@@ -36,11 +36,16 @@
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.File;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.IOException;
 import java.util.Properties;
 import java.util.logging.Logger;
 import java.util.logging.Level;
 
+import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
 
 /**
  * <code>PropertiesGameSettings</code> handles loading and saving a properties
@@ -490,11 +495,34 @@
     }
 
     /**
+     * Retruns an object stored inside a properties file by base64 decoding
+     * it and then deserialzing it.  If the requested setting isn't an object
+     * stored this way, the default value is returned.
      * @see GameSettings#getObject(String, Object)
      */
     public Object getObject(String name, Object defaultValue) {
+
         String stringValue = get(name);
-        return (stringValue == null) ? defaultValue : stringValue;
+        if(stringValue == null) {
+            return defaultValue;
+        }
+        Object out;
+        try {
+            byte[] data = Base64.decode(stringValue);
+            ByteArrayInputStream s = new ByteArrayInputStream(data);
+            ObjectInputStream is = new ObjectInputStream(s);
+            out = is.readObject();
+            is.close();
+            s.close();
+           
+        } catch (IOException ex) {
+            logger.log(Level.WARNING, "Problem deserializing object in settings.", ex);
+            return defaultValue;
+        } catch (ClassNotFoundException ex) {
+            logger.log(Level.WARNING, "Could find class for object in settings.", ex);
+            return defaultValue;
+        }
+        return out;
     }
 
     /**
@@ -584,20 +612,26 @@
     }
 
     /**
-     * Not implemented.
-     * Properties can not store an arbitrary Object in human-readable format.
-     * Use set(String, String) instead.
+     * Stores an object in a properties file by first serializing it and
+     * then converting it into base64.  If an object can be stored as a
+     * string it is often better to use set(String, String) instead.
      *
      * @see PreferencesGameSettings#setObject(String, boolean)
      * @see #set(String, String)
-     * @throws InternalError in all cases
      */
     public void setObject(String name, Object value) {
-        throw new InternalError(getClass().getName()
-                + " Can't store arbitrary objects.  "
-                + "If there is a toString() method for your Object, and it is "
-                + "Properties-compatible, use " + getClass().getName()
-                + ".set(String, String).");
+        ByteArrayOutputStream s = new ByteArrayOutputStream();
+        try {
+            ObjectOutputStream os = new ObjectOutputStream(s);
+            os.writeObject(value);
+            os.close();
+            s.close();
+        } catch (IOException ex) {
+            logger.log(Level.WARNING, "Problem serializing object in settings.", ex);
+        }
+
+        String out = Base64.encode(s.toByteArray());
+        this.set(name, out);
     }
 
     /**

I think it might be better to avoid those internal com.sun libs, i think some linux distro come with a JRE which didn't support these out of the Box.



But as those libs are already used in other parts it doesn't matter too much.