Serialization of object containing DB connection - how?
Hello everyone.
I develop CDC application for J9 on Pocket PC and have a problem
with serialization of an object containing database connection. I am
using hsqldb CDC version and database enabler for J9.
While serializing I get an exception
java.io.NotSerializableException:
org.hsqldb.jdbc.jdbcConnection
I am confused as I do not use this class excplicite in my project. I am using
org.hsqldb.jdbcDataSourceimplements javax.sql.DataSource.
More details follow here:
I've got an object of
class DBOntModelImplextends OntModelImplimplements DBOntModel
The class has a field
transientprivate Connection dbConnection;
The connection is created as
org.hsqldb.jdbcDataSource dataSource =new jdbcDataSource();
dbConnection = dataSource.getConnection(url);
Knowing that db connection cannot be serialized I did as it is written in the Sun's tutorial at
http://java.sun.com/developer/technicalArticles/Programming/serialization/
namely I set connection as transient, I implemented writeObject and readObject methods and tried to serialize DBOntModelImpl. What I get is:
java.io.NotSerializableException: org.hsqldb.jdbc.jdbcConnection
at
java.io.ObjectOutputStream.checkSerializable(Unknown Source)
at
java.io.ObjectOutputStream.writeNewObject(Unknown Source)
at
java.io.ObjectOutputStream.writeObjectInternal(Unknown Source)
at
java.io.ObjectOutputStream.writeObject(Unknown Source)
at
java.io.ObjectOutputStream.writeObject(Unknown Source)
at
java.io.ObjectOutputStream.writeFieldValues(Unknown Source)
etc.
The code for serializing method is following:
privatevoid writeObject(ObjectOutputStream out)throws IOException
{
this.closeDBConnection();
out.defaultWriteObject();
}
How should I serialize my model then if this does not work?
I have sources of hsqldb-cdc but have no sources for jdbc. I have search the internet but found no similar problem/solution.
Thanks for any clues and ask for details if you need.
[2565 byte] By [
BeCeKa] at [2007-11-27 4:08:39]

# 1
There are a couple of debugging steps you could take. The first is to use reflection to get a full list of all non-static fields (including those inherited from superclasses) to verify both that there aren't any other fields holding a jdbcConnection and that it's not a compilation/deployment issue which is resulting in the field becoming non-transient.
The second is to add a line to ensure that you can't write out that connection: private void writeObject(ObjectOutputStream out) throws IOException
{
this.closeDBConnection();
this.dbConnection=null;
out.defaultWriteObject();
}
If that fixes it then it's probably a J9 bug.
# 2
The program does not execute writeObject method. Looks like it does some kind of verification if object are serializable before getting to this method.
I have run my code on J2SE with exactly the same result, so it is not the matter of J9.
I would eagerly check if there is a jdbcConnection object somewhere in the project but I do not know how. Could you tell me how or tell me where to find it?
# 3
I've tested the following program and it works under J2SE 1.5.0: import java.io.*;
public class SerialisationTest implements Serializable
{
private Object foo=new Object();
private void writeObject(ObjectOutputStream out) throws IOException {
foo=null;
out.defaultWriteObject();
}
public static void main(String[] args) throws IOException {
ObjectOutputStream out=new ObjectOutputStream(new ByteArrayOutputStream());
out.writeObject(new SerialisationTest());
}
}
It's looking probable that you have another relevant field somewhere. The following may help find it, but comes with no guarantee. It's just something I threw together. import java.io.*;
import java.lang.reflect.*;
import java.util.*;
/**
* More aggressive than it needs to be in terms of not caching messages to ensure
* they're not repeated.
*/
public class SerialisationTool
{
public static void checkSerialisable(Object o) {
// The null reference can be serialised trivially.
if (o==null) return;
// Otherwise only serializable objects can.
if (!(o instanceof Serializable)) throw new RuntimeException(o.getClass()+" is not serialisable");
checkSerialisable(o,new LinkedList<String>(), new IdentityHashMap<Object, Void>());
}
private static void checkSerialisable(Object o, LinkedList<String> path, IdentityHashMap<Object, Void> visited) {
visited.put(o,null);
// Pre-condition: o implements serialisable
Class<?> c=o.getClass();
Method writeObject=checkMethod(c,"writeObject",ObjectOutputStream.class);
Method readObject=checkMethod(c,"readObject",ObjectInputStream.class);
if (writeObject==null ^ readObject==null) {
// Not necessarily an error per se, but mildly surprising.
System.err.println("Warning: "+c.getName()+" implements precisely one of writeObject and readObject");
}
// Handle arrays as a special case.
if (o instanceof Object[]) {
Class<?> type=c.getComponentType();
if (!Serializable.class.isAssignableFrom(type)) {
// If there's a writeObject method this is less of an issue.
// TODO Add paranoia level flags.
System.err.println("Warning: array has non-serialisable type "+type.getName()+"; path="+path);
}
Object[] arr=(Object[])o;
for (int i=0; i<arr.length; i++) {
Object val=arr[i];
if (val==null) continue;
if (val instanceof Serializable) {
// Avoid infinite loops.
if (!visited.containsKey(val)) {
path.addLast("["+i+"]");
checkSerialisable(val,path,visited);
path.removeLast();
}
}
else {
System.err.println("ERROR: non-serialisable array element of class "+val.getClass().getName()+"; path="+path);
}
}
}
// Now look for fields.
while (c!=null) {
for (Field field : c.getDeclaredFields()) {
// Static and transient fields aren't serialised.
int mod=field.getModifiers();
if ((mod&Modifier.STATIC)!=0) continue;
if ((mod&Modifier.TRANSIENT)!=0) continue;
Class<?> type=field.getType();
// Primitive types are serialisable.
if (type.equals(boolean.class) || type.equals(byte.class) || type.equals(short.class) ||
type.equals(char.class) || type.equals(int.class) || type.equals(long.class) ||
type.equals(float.class) || type.equals(double.class)) {
continue;
}
// Otherwise it depends on the value, although some things increase paranoia level.
if (!Serializable.class.isAssignableFrom(type)) {
// If there's a writeObject method this is less of an issue.
// TODO Add paranoia level flags.
System.err.println("Warning: field "+field.getName()+" of class "+c.getName()+" has type which is not per se serialisable; path="+path);
}
field.setAccessible(true);
Object val=null;
try {
val=field.get(o);
}
catch (IllegalAccessException iae) {
throw new InternalError("Accessible fields aren't always with this VM");
}
// The null reference is serialisable.
if (val==null) continue;
if (val instanceof Serializable) {
// Avoid infinite loops.
if (!visited.containsKey(val)) {
path.addLast(field.getDeclaringClass().getName()+"."+field.getName());
checkSerialisable(val,path,visited);
path.removeLast();
}
}
else {
System.err.println("ERROR: field "+field.getName()+" of class "+c.getName()+" has non-serialisable value of type "+val.getClass().getName()+"; path="+path);
}
}
c=c.getSuperclass();
}
}
private static Method checkMethod(Class<?> c, String methodName, Class... params) {
Method rv=null;
Class<?> clz=c;
while (clz!=null) {
try {
rv=c.getDeclaredMethod(methodName,params);
break;
}
catch (NoSuchMethodException e) {
clz=clz.getSuperclass();
// If we didn't find it, that's not necessarily a problem.
if (clz.equals(Object.class)) break;
}
}
if (rv!=null) {
// Check it matches signature.
int mod=rv.getModifiers();
if ((mod&Modifier.PRIVATE)==0) System.err.println("Warning: "+c.getName()+" incorrectly implements "+methodName);
// TODO Check exceptions, non-static.
}
return rv;
}
}
>
# 4
Hello again.
Thanks for this code. I used it, but it did not help much. Here is the result of serializing model NOT HAVING database connection reference
Loading model data...
Model loaded successfully
Classes: 59 Properties: 18 Individuals: 21
SerializationTool start
Warning: field classes of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field properties of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field otherResources of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field individuals of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field disjointWith of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field equivalentClasses of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field subClasses of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field superClasses of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field labels of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field comments of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field versionInfo of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field isDefinedBy of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field seeAlso of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field prefixes of class pl.edu.pw.tele.meag.lont.api.impl.PrefixMappingImpl has type which is not per se serialisable; path=[]
SerializationTool end
Serializing model to C:\Documents and Settings\Administrator\Desktop\test\testfile1.ser
Model serialized successfully
Here is the result of serializing model CONTAINING database connection reference
Loading model data...
Model loaded successfully
Classes: 59 Properties: 18 Individuals: 21
SerializationTool start
Warning: field classes of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field properties of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field otherResources of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field individuals of class pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl has type which is not per se serialisable; path=[]
Warning: field disjointWith of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field equivalentClasses of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field subClasses of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field superClasses of class pl.edu.pw.tele.meag.lont.api.impl.OntClassImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field labels of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field comments of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field versionInfo of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field isDefinedBy of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field seeAlso of class pl.edu.pw.tele.meag.lont.api.impl.OntResourceImpl has type which is not per se serialisable; path=[pl.edu.pw.tele.meag.lont.api.impl.OntModelImpl.Thing]
Warning: field prefixes of class pl.edu.pw.tele.meag.lont.api.impl.PrefixMappingImpl has type which is not per se serialisable; path=[]
SerializationTool end
Serializing model to C:\Documents and Settings\Administrator\Desktop\test\testfile1.ser
java.io.NotSerializableException: org.hsqldb.jdbc.jdbcConnection
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1081)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1375)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1347)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1290)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1079)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:302)
at java.util.ArrayList.writeObject(ArrayList.java:569)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:917)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1339)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1290)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1079)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:302)
at java.util.HashMap.writeObject(HashMap.java:985)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:917)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1339)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1290)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1079)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1375)
etc....
So the SerialisationTool did not found anything wrong in my objects. The Warnings issued by the tool are caused by inheritance - the objects returned by the tool extend Serializable objects.
Any other ideas?
# 5
I have removed transient keyword - the behaviour of application did not change. I also modified the code and added one println to be sure that I execute THIS code. I do.
I execute the application with jdk1.5.0_07\bin\javaw.exe
You can see also the other thread about his problem: http://forum.java.sun.com/thread.jspa?messageID=9684294
# 6
j9 throws the same Exceptions.
# 7
PROBLEM SOLVED!
I found bug in my source code. There was an object in the HashMap that had its own Connection, which was not marked as transient. Now when I had added transient keyword to all SQL objects (Connection, Statement, ResultSet) serialization and deserialization works fine. Thank you for help!
# 8
Not at all. Sorry that the tool didn't help - must have a bug in somewhere.