commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From er...@apache.org
Subject svn commit: r1080231 - in /commons/proper/math/trunk/src: main/java/org/apache/commons/math/exception/MathRuntimeException.java test/java/org/apache/commons/math/exception/MathRuntimeExceptionTest.java
Date Thu, 10 Mar 2011 14:05:32 GMT
Author: erans
Date: Thu Mar 10 14:05:32 2011
New Revision: 1080231

URL: http://svn.apache.org/viewvc?rev=1080231&view=rev
Log:
MATH-542
Added custom "writeObject" and "readObject" so that serialization can
proceed even if non-"Serializable" objects are stored (in messages
arguments or context values).

Modified:
    commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathRuntimeException.java
    commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/MathRuntimeExceptionTest.java

Modified: commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathRuntimeException.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathRuntimeException.java?rev=1080231&r1=1080230&r2=1080231&view=diff
==============================================================================
--- commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathRuntimeException.java
(original)
+++ commons/proper/math/trunk/src/main/java/org/apache/commons/math/exception/MathRuntimeException.java
Thu Mar 10 14:05:32 2011
@@ -20,6 +20,10 @@ import java.util.List;
 import java.util.ArrayList;
 import java.util.Set;
 import java.util.Map;
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
 import java.util.HashMap;
 import java.text.MessageFormat;
 import java.util.Locale;
@@ -41,12 +45,12 @@ public class MathRuntimeException extend
     /**
      * Various informations that enrich the informative message.
      */
-    private final List<SerializablePair<Localizable, Object[]>> messages
+    private List<SerializablePair<Localizable, Object[]>> messages
         = new ArrayList<SerializablePair<Localizable, Object[]>>();
     /**
      * Arbitrary context information.
      */
-    private final Map<String, Object> context = new HashMap<String, Object>();
+    private Map<String, Object> context = new HashMap<String, Object>();
 
     /**
      * Builds an exception.
@@ -142,4 +146,147 @@ public class MathRuntimeException extend
 
         return sb.toString();
     }
+
+    /**
+     * Serialize this object to the given stream.
+     *
+     * @param out Stream.
+     * @throws IOException This should never happen.
+     */
+    private void writeObject(ObjectOutputStream out)
+        throws IOException {
+        serializeMessages(out);
+        serializeContext(out);
+    }
+    /**
+     * Deserialize this object from the given stream.
+     *
+     * @param in Stream.
+     * @throws IOException This should never happen.
+     * @throws ClassNotFoundException This should never happen.
+     */
+    private void readObject(ObjectInputStream in)
+        throws IOException,
+               ClassNotFoundException {
+        deSerializeMessages(in);
+        deSerializeContext(in);
+    }
+
+    /**
+     * Serialize {@link #messages}.
+     *
+     * @param out Stream.
+     * @throws IOException This should never happen.
+     */
+    private void serializeMessages(ObjectOutputStream out)
+        throws IOException {
+        // Step 1.
+        final int len = messages.size();
+        out.writeInt(len);
+        // Step 2.
+        for (int i = 0; i < len; i++) {
+            SerializablePair<Localizable, Object[]> pair = messages.get(i);
+            // Step 3.
+            out.writeObject(pair.getKey());
+            final Object[] args = pair.getValue();
+            final int aLen = args.length;
+            // Step 4.
+            out.writeInt(aLen);
+            for (int j = 0; j < aLen; j++) {
+                if (args[j] instanceof Serializable) {
+                    // Step 5a.
+                    out.writeObject(args[j]);
+                } else {
+                    // Step 5b.
+                    out.writeObject(nonSerializableReplacement(args[j]));
+                }
+            }
+        }
+    }
+
+    /**
+     * Deserialize {@link #messages}.
+     *
+     * @param in Stream.
+     * @throws IOException This should never happen.
+     * @throws ClassNotFoundException This should never happen.
+     */
+    private void deSerializeMessages(ObjectInputStream in)
+        throws IOException,
+               ClassNotFoundException {
+        // Step 1.
+        final int len = in.readInt();
+        messages = new ArrayList<SerializablePair<Localizable, Object[]>>(len);
+        // Step 2.
+        for (int i = 0; i < len; i++) {
+            // Step 3.
+            final Localizable key = (Localizable) in.readObject();
+            // Step 4.
+            final int aLen = in.readInt();
+            final Object[] args = new Object[aLen];
+            for (int j = 0; j < aLen; j++) {
+                // Step 5.
+                args[j] = in.readObject();
+            }
+            messages.add(new SerializablePair<Localizable, Object[]>(key, args));
+        }
+    }
+
+    /**
+     * Serialize {@link #context}.
+     *
+     * @param out Stream.
+     * @throws IOException This should never happen.
+     */
+    private void serializeContext(ObjectOutputStream out)
+        throws IOException {
+        // Step 1.
+        final int len = context.keySet().size();
+        out.writeInt(len);
+        for (String key : context.keySet()) {
+            // Step 2.
+            out.writeObject(key);
+            final Object value = context.get(key);
+            if (value instanceof Serializable) {
+                // Step 3a.
+                out.writeObject(value);
+            } else {
+                // Step 3b.
+                out.writeObject(nonSerializableReplacement(value));
+            }
+        }
+    }
+
+    /**
+     * Deserialize {@link #context}.
+     *
+     * @param in Stream.
+     * @throws IOException This should never happen.
+     * @throws ClassNotFoundException This should never happen.
+     */
+    private void deSerializeContext(ObjectInputStream in)
+        throws IOException,
+               ClassNotFoundException {
+        // Step 1.
+        final int len = in.readInt();
+        context = new HashMap<String, Object>();
+        for (int i = 0; i < len; i++) {
+            // Step 2.
+            final String key = (String) in.readObject();
+            // Step 3.
+            final Object value = in.readObject();
+            context.put(key, value);
+        }
+    }
+
+    /**
+     * Replaces a non-serializable object with an error message string.
+     *
+     * @param obj Object that does not implement the {@code Serializable
+     * interface
+     * @return a string that mentions which class could not be serialized.
+     */
+    private String nonSerializableReplacement(Object obj) {
+        return "[Object could not be serialized: " + obj.getClass().getName() + "]";
+    }
 }

Modified: commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/MathRuntimeExceptionTest.java
URL: http://svn.apache.org/viewvc/commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/MathRuntimeExceptionTest.java?rev=1080231&r1=1080230&r2=1080231&view=diff
==============================================================================
--- commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/MathRuntimeExceptionTest.java
(original)
+++ commons/proper/math/trunk/src/test/java/org/apache/commons/math/exception/MathRuntimeExceptionTest.java
Thu Mar 10 14:05:32 2011
@@ -18,6 +18,11 @@ package org.apache.commons.math.exceptio
 
 import java.util.Locale;
 import java.util.Arrays;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
 
 import org.apache.commons.math.exception.util.LocalizedFormats;
 
@@ -75,4 +80,61 @@ public class MathRuntimeExceptionTest {
         // Check behaviour on missing key.
         Assert.assertNull(mre.getContext("xyz"));
     }
+
+    @Test
+    public void testSerialize()
+        throws IOException,
+               ClassNotFoundException {
+        final MathRuntimeException mreOut = new MathRuntimeException();
+        mreOut.addMessage(LocalizedFormats.COLUMN_INDEX, 0);
+        mreOut.setContext("Key 1", Integer.valueOf(0));
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(bos);
+        oos.writeObject(mreOut);
+
+        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+        ObjectInputStream ois = new ObjectInputStream(bis);
+        MathRuntimeException mreIn = (MathRuntimeException) ois.readObject();
+
+        Assert.assertTrue(mreOut.getMessage().equals(mreIn.getMessage()));
+        for (String key : mreIn.getContextKeys()) {
+            Assert.assertTrue(mreOut.getContext(key).equals(mreIn.getContext(key)));
+        }
+    }
+
+    @Test
+    public void testSerializeUnserializable() {
+        final MathRuntimeException mreOut = new MathRuntimeException();
+        mreOut.addMessage(LocalizedFormats.SIMPLE_MESSAGE, "OK");
+        mreOut.addMessage(LocalizedFormats.SIMPLE_MESSAGE, new Unserializable(0));
+        String key = "Key 1";
+        mreOut.setContext(key, new Unserializable(1));
+
+        try {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(bos);
+            oos.writeObject(mreOut);
+
+            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+            ObjectInputStream ois = new ObjectInputStream(bis);
+            MathRuntimeException mreIn = (MathRuntimeException) ois.readObject();
+
+            String nsObjStr = (String) mreIn.getContext(key);
+            Assert.assertTrue(nsObjStr.matches(".*could not be serialized.*"));
+        } catch (Exception e) {
+            Assert.fail(e.toString());
+        }
+    }
+
+    /**
+     * Class used by {@link #testSerializeUnserializable()}.
+     */
+    private static class Unserializable {
+        private int k;
+
+        Unserializable(int k) {
+            this.k = k;
+        }
+    }
 }



Mime
View raw message