In Java, Serialization makes reading and writing objects to streams REALLY easy. For instance, the following code snippet is mostly all it takes to write objects to a stream:
ObjectOutputStream oos = ... //Initialize your output stream
Object toWrite = ... //Initialize what you want to write here
oos.writeObject(toWrite); //Writes the object to the stream
oos.flush();
This will work just fine, provided that toWrite
's class implements the Serializable
interface, AND that all of toWrite
's non-transient
member variables are also Serializable
. In other words, the entire Object hierarchy you are trying to send via the toWrite
reference must be Serializable
. Assume that the only problem with this code is that something inside toWrite
isn't Serializable
.
If the hierarchy isn't completely Serializable
, the call to oos.writeObject(toWrite)
throws a java.io.NotSerializableException
. This is all fine and good, except that the Exception doesn't give you quite everything you need to fix the problem quickly. It will tell you what class couldn't be serialized. Your stack trace might look something like this:
java.io.NotSerializableException: some.package.and.ClassIDidntExplicitlyReference
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
...
at my.package.MyClass.codeThatWroteTheOffendingObject(MyClass.java:###)
This sort of points you in the right direction, but in cases that involve deep Object hierarchies referenced by toWrite
, it's not always clear where the offending class reference came from. Let's say I assign toWrite
to an instance of MyClass
and my instance of MyClass
has a member Object reference called nonSerializableReference
that has been set to an instance of ClassIDidntExplicitlyReference
, which is not Serializable
. I'd like to see something like the following printed out:
my.package.MyClass.nonSerializableReference instanceof some.package.and.ClassIDidntExplicitlyReference
I know this problem probably doesn't have a quick solution, and will likely involve using Reflections. Has anyone here on SO done this before and if so, would you mind sharing your insight?
Answer
I ended up using Reflection's Field
and Modifier
class to find the path. Unfortunately, I can't share my code (against company policy), but I can show you my output. Class A holds an instance of B, B holds an instance of C, and C holds an instance of D. All are Serializable
except for D. I ended up using Depth-First-Search to find the path:
A.b ->
B.c ->
C.d instanceof class D
If I make C.d
transient, the search yields no results. Pretty cool!
Pass the flag -Dsun.io.serialization.extendedDebugInfo=true
to the JVM and it should give you exactly the information you want, when a NotSerializableException
is thrown.
I had the same problem and I also implemented the crawler thing you talked about. If somebody is still interested in it, I presented the code here: A good way to find unserializable fields in Java
This is a strange question - you're wanting to determine at runtime what you should be doing at compile time. In theory, the path to the object shouldn't matter - you need to find the objects that reference things that aren't serializable to fix your code.
That said, you could write a simple recursive tree crawler using reflection. That said, you might be able to get away with implementing your own ObjectInputStream that logs the objects coming in appropriately. I recommend taking a look at the source for more detail
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With