Author: ehillenius
Date: Wed Feb  7 23:13:57 2007
New Revision: 504809

URL: http://svn.apache.org/viewvc?view=rev&rev=504809
Log:
WICKET-265

Added:
    
incubator/wicket/trunk/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
Modified:
    
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
    
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java

Modified: 
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
URL: 
http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/FilePageStore.java?view=diff&rev=504809&r1=504808&r2=504809
==============================================================================
--- 
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
 (original)
+++ 
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/FilePageStore.java
 Wed Feb  7 23:13:57 2007
@@ -30,6 +30,7 @@
 import wicket.Application;
 import wicket.Page;
 import wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore;
+import wicket.util.io.DebuggingObjectOutputStream;
 import wicket.util.lang.Objects;
 
 /**
@@ -191,8 +192,17 @@
                }
                catch (Exception e)
                {
-                       log.error("Error saving page " + page.getId() + "," + 
page.getCurrentVersionNumber()
-                                       + " for the sessionid " + sessionId, e);
+                       // trigger serialization again, but this time gather 
some more info
+                       try
+                       {
+                               new 
DebuggingObjectOutputStream().writeObject(page);
+                       }
+                       catch (Exception e1)
+                       {
+                               log.error("Error saving page " + 
page.getClass() + "[" + page.getId() + ","
+                                               + 
page.getCurrentVersionNumber() + "] for the sessionid " + sessionId
+                                               + ": " + e1.getMessage(), e1);
+                       }
                }
                finally
                {

Modified: 
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java
URL: 
http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java?view=diff&rev=504809&r1=504808&r2=504809
==============================================================================
--- 
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java
 (original)
+++ 
incubator/wicket/trunk/wicket/src/main/java/wicket/protocol/http/HttpSessionStore.java
 Wed Feb  7 23:13:57 2007
@@ -17,6 +17,7 @@
 package wicket.protocol.http;
 
 import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.io.ObjectOutputStream;
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -31,6 +32,7 @@
 import wicket.Request;
 import wicket.Session;
 import wicket.WicketRuntimeException;
+import wicket.util.io.DebuggingObjectOutputStream;
 import wicket.util.lang.Bytes;
 
 /**
@@ -54,7 +56,7 @@
                {
                        if (value instanceof Page)
                        {
-                               ((Page)value).detach();
+                               ((Page<?>)value).detach();
                        }
                        String valueTypeName = (value != null ? 
value.getClass().getName() : "null");
                        try
@@ -66,9 +68,20 @@
                        }
                        catch (Exception e)
                        {
+                               // trigger serialization again, but this time 
gather some more info
+                               try
+                               {
+                                       new 
DebuggingObjectOutputStream().writeObject(value);
+                               }
+                               catch (IOException e1)
+                               {
+                                       throw new RuntimeException(e1);
+                               }
+                               // this should never happen
                                throw new WicketRuntimeException(
-                                               "Internal error cloning object. 
Make sure all dependent objects implement Serializable. Class="
-                                                               + valueTypeName 
+ ",attribute=" + name + ", value=" + value, e);
+                                               "first pass of serialization 
failed, but the second one "
+                                                               + "(that should 
gather extended information) passed? Please "
+                                                               + "report this 
error to the Wicket team", e);
                        }
                }
 

Added: 
incubator/wicket/trunk/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
URL: 
http://svn.apache.org/viewvc/incubator/wicket/trunk/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java?view=auto&rev=504809
==============================================================================
--- 
incubator/wicket/trunk/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
 (added)
+++ 
incubator/wicket/trunk/wicket/src/main/java/wicket/util/io/DebuggingObjectOutputStream.java
 Wed Feb  7 23:13:57 2007
@@ -0,0 +1,213 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package wicket.util.io;
+
+import java.io.IOException;
+import java.io.NotSerializableException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.LinkedList;
+
+import wicket.Component;
+import wicket.WicketRuntimeException;
+
+/**
+ * Captures information about what it is trying to stream with the sole purpose
+ * of finding out what the object hierarchy looks like of an object that can't
+ * be serialized.
+ * <p>
+ * If you have an object you want to analyze for this, call:
+ * <code>new DebuggingObjectOutputStream().writeObject(value);</code> and
+ * catch the [EMAIL PROTECTED] WicketRuntimeException}.
+ * </p>
+ * <p>
+ * There's no point using this class if you are not trying to diagnose a
+ * serialization issue.
+ * </p>
+ * 
+ * @author Al Maw
+ */
+public class DebuggingObjectOutputStream extends ObjectOutputStream
+{
+       private static final long serialVersionUID = 1L;
+
+       /** stack for string representations of objects that are handled. */
+       private final LinkedList<CharSequence> stack = new 
LinkedList<CharSequence>();
+
+       /** set for checking circular references. */
+       private final HashSet<Object> set = new HashSet<Object>();
+
+       /**
+        * Creates an ObjectOutputStream. Doesn't write anywhere
+        * 
+        * @throws IOException
+        *             IOException if an I/O error occurs while writing stream
+        *             header
+        */
+       public DebuggingObjectOutputStream() throws IOException
+       {
+               super();
+       }
+
+       /**
+        * Dump with identation.
+        * 
+        * @param type
+        *            the type that couldn't be serialized
+        * @return A very pretty dump
+        */
+       private String getPrettyPrintedStack(String type)
+       {
+               set.clear();
+               StringBuilder result = new StringBuilder();
+               StringBuilder spaces = new StringBuilder();
+               result.append("Unable to serialize class: ");
+               result.append(type);
+               result.append("\nField hierarchy is:");
+               while (!stack.isEmpty())
+               {
+                       spaces.append("  ");
+                       
result.append("\n").append(spaces).append(stack.removeFirst());
+               }
+               result.append(" <----- field that is not serializable");
+               return result.toString();
+       }
+
+       /**
+        * @see java.io.ObjectOutputStream#writeObjectOverride(java.lang.Object)
+        * @throws IOException
+        *             never actually happens
+        * @throws WicketRuntimeException
+        *             on a serialization exception
+        */
+       protected final void writeObjectOverride(Object obj) throws IOException
+       {
+               if (obj == null)
+               {
+                       return;
+               }
+               // Check for circular reference.
+               if (set.contains(obj))
+               {
+                       return;
+               }
+               if (stack.isEmpty())
+               {
+                       stack.add("Class " + obj.getClass().getName());
+               }
+               set.add(obj);
+               Field[] fields = obj.getClass().getDeclaredFields();
+               for (int i = 0; i < fields.length; i++)
+               {
+                       fields[i].setAccessible(true);
+                       StringBuilder buffer = new StringBuilder();
+                       Field f = fields[i];
+                       int m = f.getModifiers();
+                       if (fields[i].getType().isPrimitive() || 
Modifier.isTransient(m)
+                                       || Modifier.isStatic(m))
+                       {
+                               continue;
+                       }
+
+                       if (Modifier.isPrivate(m))
+                       {
+                               buffer.append("private ");
+                       }
+                       if (Modifier.isProtected(m))
+                       {
+                               buffer.append("protected ");
+                       }
+                       if (Modifier.isPublic(m))
+                       {
+                               buffer.append("public ");
+                       }
+                       if (Modifier.isAbstract(m))
+                       {
+                               buffer.append("abstract ");
+                       }
+                       if (Modifier.isFinal(m))
+                       {
+                               buffer.append("final ");
+                       }
+                       if (Modifier.isStatic(m))
+                       {
+                               buffer.append("static ");
+                       }
+                       if (Modifier.isVolatile(m))
+                       {
+                               buffer.append("volatile ");
+                       }
+                       buffer.append(f.getType().getName()).append("");
+                       buffer.append(" ").append(f.getName()).append(" => ");
+
+                       // now that we have the reference, try to get the 
actual value
+                       try
+                       {
+                               Object val = f.get(obj);
+                               if (val != null)
+                               {
+                                       buffer.append(val.getClass().getName());
+                                       if (val instanceof Component)
+                                       {
+                                               buffer.append(" 
[path=").append(((Component<?>)val).getPath()).append("]");
+                                       }
+                               }
+                               else
+                               {
+                                       buffer.append(" null");
+                               }
+                       }
+                       catch (IllegalArgumentException e)
+                       {
+                               buffer.append("? 
(").append(e.getMessage()).append(")");
+                       }
+                       catch (IllegalAccessException e)
+                       {
+                               buffer.append("? 
(").append(e.getMessage()).append(")");
+                       }
+
+                       stack.add(buffer.toString());
+                       if 
(Serializable.class.isAssignableFrom(fields[i].getType()))
+                       {
+                               try
+                               {
+                                       writeObjectOverride(fields[i].get(obj));
+                               }
+                               catch (IllegalAccessException e)
+                               {
+                                       throw new 
WicketRuntimeException(getPrettyPrintedStack(fields[i].getType()
+                                                       .getName()), e);
+                               }
+                       }
+                       else
+                       {
+                               throw new 
WicketRuntimeException(getPrettyPrintedStack(
+                                               
fields[i].getType().getName()).toString(), new NotSerializableException(
+                                               fields[i].getType().getName()));
+                       }
+                       stack.removeLast();
+               }
+               if (stack.size() == 1)
+               {
+                       set.clear();
+                       stack.removeLast();
+               }
+       }
+}
\ No newline at end of file


Reply via email to