You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2008/08/27 10:40:51 UTC

svn commit: r689411 - /myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/lib/ObjectSerializationConverter.java

Author: skitching
Date: Wed Aug 27 01:40:50 2008
New Revision: 689411

URL: http://svn.apache.org/viewvc?rev=689411&view=rev
Log:
Add comments. Change char encoding to something clearer (but which
should make no actual difference).

Modified:
    myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/lib/ObjectSerializationConverter.java

Modified: myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/lib/ObjectSerializationConverter.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/lib/ObjectSerializationConverter.java?rev=689411&r1=689410&r2=689411&view=diff
==============================================================================
--- myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/lib/ObjectSerializationConverter.java (original)
+++ myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/lib/ObjectSerializationConverter.java Wed Aug 27 01:40:50 2008
@@ -32,14 +32,29 @@
 import java.io.Serializable;
 
 /**
- * This converter will be used to e.g. render a selection menu. <br />
- * It is responsible to convert a object to a string-identifier representation with which it is possible to
- * recreate the object again - aka serialization
+ * Converter that can map a Serializable object into a plain java String.
+ * <p>
+ * This works like the standard java Serializable process, except that the resulting byte-array is
+ * then base64-encoded, ie is a String containing only ascii characters. The resulting value can
+ * safely be passed around as the "value" of a select-list, or a value embedded in a hidden field etc.
+ * <p>
+ * In particular, this allows the value of a SelectItem to be an object rather than a String, and the
+ * serialized form of a <i>small</i> object (such as the key class of a persistent entity) to be passed
+ * as a url query parameter.
+ * <p>
+ * Of course the object should not be too complicated, otherwise the string representation will
+ * be rather large!
  */
 public class ObjectSerializationConverter implements Converter
 {
     public static final NullObject SELECT_NULL_OBJECT = new NullObject();
 
+    /**
+     * Given a String that was previously created by the getAsString method on this class,
+     * "deserialize" the content of the string into a new Object instance.
+     * <p>
+     * See method getAsString for more details.
+     */
     public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException
     {
         if (value == null || value.length() < 1 || SELECT_NULL_OBJECT.equals(value))
@@ -51,8 +66,16 @@
         Serializable objectIdent;
         try
         {
-            byte[] base64 = Base64.decodeBase64(value.getBytes("UTF-8"));
-            ois = new ObjectInputStream(new ByteArrayInputStream(base64));
+            // The string will have been created by getAsString. Therefore it will only ever
+            // contain 16-bit characters whose high 9 bits are zero. Every one of these chars
+            // will map fine to us-ascii, and will give us back the original base64-encoded
+            // byte-array form from the getAsString method. Note that UTF-8 should also work
+            // fine here; when the high 9 bits of a char are zero then the utf-8 representation
+            // of the char is a single byte that has its high bit set to zero, which is exactly
+            // what the original base64-encoded data had.
+            byte[] base64 = value.getBytes("US-ASCII");
+            byte[] rawData = Base64.decodeBase64(base64);
+            ois = new ObjectInputStream(new ByteArrayInputStream(rawData));
             objectIdent = (Serializable) ois.readObject();
             ois.close();
         }
@@ -82,6 +105,16 @@
         return objectIdent;
     }
 
+    /**
+     * Return a serialized representation of the provided value, as a String type.
+     * <p>
+     * The provided value is serialized into a byte-array using normal java serialization,
+     * and the array is then base64-encoded. The result is a String that is safe to pass
+     * around in places that expect a String. The returned value can later be passed to the
+     * getAsToObject method of this class to recreate the value passed here. 
+     * <p>
+     * The provided object must implement the Serializable interface.
+     */
     public String getAsString(FacesContext context, UIComponent component, Object value) throws ConverterException
     {
         if (value == null || SELECT_NULL_OBJECT.equals(value))
@@ -96,7 +129,30 @@
             oos = new ObjectOutputStream(baos);
             oos.writeObject(value);
             byte[] base64 = Base64.encodeBase64(baos.toByteArray());
-            String objectString = new String(base64, "UTF-8");
+
+            // It doesn't really matter what encoding we use to create a String here, as long as
+            // we use the same encoding to convert back to a byte-array later (and the encoding
+            // chosen is "symmetrical").
+            //
+            // Using UTF-16BE would give us a very dense string representation (essentially no change to the data).
+            // However it does mean that:
+            // * the result will be unreadable
+            // * any attempt to write the string out as utf-8 will waste space
+            // * trying to write it out in an 8-bit encoding will fail, as the string will certainly
+            //   hold 'chars' that are not representable in that encoding.
+            //
+            // Using UTF-8 and US-ASCII will result in the same String.
+            // * When interpreting as US-ASCII, the char conversion process will simply create a two-byte
+            // character (0<<8 |input) regardless of the input.
+            // * When interpreting as UTF-8, the char conversion process will look at each byte, and when the
+            // high bit is not set will simply create a two-byte character (0<<8 | input). Processing is
+            // more complicated when the high bit is set on a byte; however as the base64 encoding results
+            // in an array of bytes whose high bit is never set, the effect is identical to US-ASCII in this case.
+            //
+            // Because of this padding with zero bytes, the String takes up twice as much memory as the
+            // original byte array. So this method should only be used when simply passing around byte[]
+            // is not possible.
+            String objectString = new String(base64, "US-ASCII");
             return objectString;
         }
         catch (IOException e)