It’s a long time, I didn’t write a post in my blog. I just had a really heavy workload period.
Last week, I spent my whole sunday chasing a really nasty bug related to the XmlEncoder running an JVM 1.5 AIX 64bits
The symptoms where the followings, after a certain amount of time, a XML dump done using the XmlEncoder was throwing StackOverflowException. What was really strange is that the dumped object was correctly dumped a few second before and that a new dump was throwing the exception.o After some investigations, I came to the conclusion that the problem was due the PersistentDelegate used for the class (aka java_lang_Class_PersistentDelegate). I tried to bypass this default PersistentDelegate of the java.lang.Class object but then I got InvalidClassChangeError.
Eventually, I decided to rewrite the XmlEncoder and I found the issue.
In the java_lang_Class_PersistenceDelegate, there is the following code:
protected Expression instantiate(Object oldInstance, Encoder out) { Class c = (Class)oldInstance; // As of 1.3 it is not possible to call Class.forName("int"), // so we have to generate different code for primitive types. // This is needed for arrays whose subtype may be primitive. if (c.isPrimitive()) { Field field = null; try { field = ReflectionUtils.typeToClass(c).getDeclaredField("TYPE"); } catch (NoSuchFieldException ex) { System.err.println("Unknown primitive type: " + c); } return new Expression(oldInstance, field, "get", new Object[]{null}); } else if (oldInstance == String.class) { return new Expression(oldInstance, "", "getClass", new Object[]{}); } else if (oldInstance == Class.class) { return new Expression(oldInstance, String.class, "getClass", new Object[]{}); } else { return new Expression(oldInstance, Class.class, "forName", new Object[]{c.getName()}); } }
The issue was due to the code:
else if (oldInstance == Class.class) {
Before calling instantiate, oldInstance.toString() was returning class org.acme.Foo. However, within the instantiate method oldInstance == Class.class was returning true which for me is totally wrong.
As a workaround, I rewrited a PersistentDelegate and replace the if statement by:
else if (((Class) oldInstance).getName().equals(Class.class.getName())) {
And now it’s working properly.
It was a Sunday, I would have prefer to spend outside.