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.

YAT_Archivista at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...
# 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?

BeCeKa at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...
# 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;

}

}

>

YAT_Archivista at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...
# 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?

BeCeKa at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...
# 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

BeCeKa at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...
# 6
j9 throws the same Exceptions.
BeCeKa at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...
# 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!

BeCeKa at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...
# 8
Not at all. Sorry that the tool didn't help - must have a bug in somewhere.
YAT_Archivista at 2007-7-12 9:14:01 > top of Java-index,Java Mobility Forums,Java ME Technologies...