Issue Details (XML | Word | Printable)

Key: WICKET-265
Type: Improvement Improvement
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Eelco Hillenius
Reporter: Eelco Hillenius
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
Wicket

Improve diagnostics on serialization exceptions

Created: 08/Feb/07 01:07 AM   Updated: 17/Feb/07 11:33 PM
Return to search
Component/s: None
Affects Version/s: 1.3.0-beta1, 2.0 branch (discontinued)
Fix Version/s: 1.3.0-beta1, 2.0 branch (discontinued)

Time Tracking:
Not Specified

Resolution Date: 17/Feb/07 11:33 PM


 Description  « Hide
The JDK's default serialization exception doesn't give a whole lot of information other than the object that didn't implement serializable. We can try to improve on this by giving more info of the object tree that was being serialized

 All   Comments   Work Log   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Eelco Hillenius added a comment - 08/Feb/07 01:09 AM
Al provides this test:

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;
 
public class Foo extends ObjectOutputStream {
 
private static final long serialVersionUID = 1L;
 
private LinkedList stack = new LinkedList();
private HashSet set = new HashSet();
 
public static void main(String[] args) throws Exception
{
new Foo().writeObject(new A());
}
 
public Foo() throws IOException {}
 
@Override
protected final void writeObjectOverride(Object obj) throws IOException
{
// 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().getFields();
for (int i = 0; i < fields.length; i++)
{
StringBuffer buffer = new StringBuffer();
Field f = fields[i];
int m = f.getModifiers();
if (fields[i].getType().isPrimitive() || Modifier.isTransient(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());
stack.add(buffer.toString());
if (Serializable.class.isAssignableFrom(fields[i].getType()))
{
try
{
writeObjectOverride(fields[i].get(obj));
}
catch (IllegalAccessException e)
{
throw new RuntimeException(getPrettyPrintedStack(), e);
}
}
else
{
throw new RuntimeException(getPrettyPrintedStack().toString(), new NotSerializableException(fields[i].getType().getName()));
}
stack.removeLast();
}
if (stack.size() == 1)
{
set.clear();
}
}
 
private String getPrettyPrintedStack()
{
StringBuffer result = new StringBuffer("Unable to serialise class.\nField hierarchy is:");
StringBuffer spaces = new StringBuffer();
while (!stack.isEmpty()) {
spaces.append(" ");
result.append("\n").append(spaces).append(stack.removeFirst());
}
return result.toString();
}
}
 
class A implements Serializable
{
private static final long serialVersionUID = 1L;
public B myFieldForB = new B();
public D myFieldForD = new D();
}
 
class B implements Serializable
{
private static final long serialVersionUID = 1L;
public C myFieldForC = new C();
}
 
class C
{
private static final long serialVersionUID = 1L;
public int foo = 1;
}
 
class D implements Serializable
{
public int bar = 2;
}

Alastair Maw added a comment - 08/Feb/07 01:19 AM
An ObjectOutputStream implementation that produces a nice pretty tree. Note that it's pretty expensive running this - only do it when you know something is broken.

Eelco Hillenius added a comment - 08/Feb/07 06:56 AM
Improved version

Eelco Hillenius added a comment - 08/Feb/07 06:59 AM
Agh. Still not there. Gotta filter out static and transient fields.

Eelco Hillenius added a comment - 08/Feb/07 06:59 AM
correction, only static

Eelco Hillenius added a comment - 08/Feb/07 07:01 AM
3rd try

Eelco Hillenius added a comment - 08/Feb/07 08:51 AM
On second thought: that ObjectOutputStream didn't really make sense. Rewrote it to a static method in wicket.util.Objects (that in turn uses internal classes).

Eelco Hillenius added a comment - 10/Feb/07 08:23 AM
Ok, that didn't actually work at all. Turned out to be a pretty naive approach. We have to rewrite it to make it resemble actual serialization more closely.

Eelco Hillenius added a comment - 12/Feb/07 07:33 AM
wicket.util.io.SerializableChecker does the job. Currently implemented for 1.3. I'll port later this week.