Permalink
Browse files

Fixed Issue #64, support for Externalizable

  • Loading branch information...
1 parent 7621c12 commit c4bebaf3202ca5b6796cdd08d8c7153493a143e3 @dan-g dan-g committed Apr 29, 2012
@@ -1,8 +1,6 @@
package net.kotek.jdbm;
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
+import java.io.*;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -12,7 +10,7 @@
*
* @author Jan Kotek
*/
-class DataInputOutput implements DataInput, DataOutput {
+class DataInputOutput implements DataInput, DataOutput, ObjectInput, ObjectOutput {
private int pos = 0;
private int count = 0;
@@ -156,6 +154,7 @@ private void ensureAvail(int n) {
}
+
public void write(int b) throws IOException {
ensureAvail(1);
buf[pos++] = (byte) b;
@@ -242,4 +241,57 @@ public void writeFromByteBuffer(ByteBuffer b, int offset, int length) {
b.get(buf,pos,length);
pos+=length;
}
+
+
+ //temp var used for Externalizable
+ SerialClassInfo serializer;
+ //temp var used for Externalizable
+ Serialization.FastArrayList objectStack;
+
+ public Object readObject() throws ClassNotFoundException, IOException {
+ //is here just to implement ObjectInput
+ //Fake method which reads data from serializer.
+ //We could probably implement separate wrapper for this, but I want to safe class space
+ return serializer.deserialize(this, objectStack);
+ }
+
+ public int read() throws IOException {
+ //is here just to implement ObjectInput
+ return readUnsignedByte();
+ }
+
+ public int read(byte[] b) throws IOException {
+ //is here just to implement ObjectInput
+ readFully(b);
+ return b.length;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ //is here just to implement ObjectInput
+ readFully(b,off,len);
+ return len;
+ }
+
+ public long skip(long n) throws IOException {
+ //is here just to implement ObjectInput
+ pos += n;
+ return n;
+ }
+
+ public void close() throws IOException {
+ //is here just to implement ObjectInput
+ //do nothing
+ }
+
+ public void writeObject(Object obj) throws IOException {
+ //is here just to implement ObjectOutput
+ serializer.serialize(this,obj,objectStack);
+ }
+
+
+ public void flush() throws IOException {
+ //is here just to implement ObjectOutput
+ //do nothing
+ }
+
}
@@ -22,6 +22,10 @@ public void serialize(DataOutput out, ArrayList<ClassInfo> obj) throws IOExcepti
LongPacker.packInt(out, obj.size());
for (ClassInfo ci : obj) {
out.writeUTF(ci.getName());
+ out.writeBoolean(ci.isEnum);
+ out.writeBoolean(ci.isExternalizable);
+ if(ci.isExternalizable) continue; //no fields
+
LongPacker.packInt(out, ci.fields.size());
for (FieldInfo fi : ci.fields) {
out.writeUTF(fi.getName());
@@ -32,17 +36,21 @@ public void serialize(DataOutput out, ArrayList<ClassInfo> obj) throws IOExcepti
}
public ArrayList<ClassInfo> deserialize(DataInput in) throws IOException, ClassNotFoundException {
+
int size = LongPacker.unpackInt(in);
ArrayList<ClassInfo> ret = new ArrayList<ClassInfo>(size);
for (int i = 0; i < size; i++) {
String className = in.readUTF();
- int fieldsNum = LongPacker.unpackInt(in);
+ boolean isEnum = in.readBoolean();
+ boolean isExternalizable = in.readBoolean();
+
+ int fieldsNum = isExternalizable? 0 : LongPacker.unpackInt(in);
FieldInfo[] fields = new FieldInfo[fieldsNum];
for (int j = 0; j < fieldsNum; j++) {
fields[j] = new FieldInfo(in.readUTF(), in.readBoolean(), in.readUTF(), Class.forName(className));
}
- ret.add(new ClassInfo(className, fields));
+ ret.add(new ClassInfo(className, fields,isEnum,isExternalizable));
}
return ret;
}
@@ -68,12 +76,16 @@ public SerialClassInfo(DBAbstract db, long serialClassInfoRecid, ArrayList<Class
private final Map<String, FieldInfo> name2fieldInfo = new HashMap<String, FieldInfo>();
private final Map<String, Integer> name2fieldId = new HashMap<String, Integer>();
private ObjectStreamField[] objectStreamFields;
- // Is this class an enumeration?
- // 0 - if it is not an enum, 1 - if it is an enum, <0 if not initialized yet
- private int isEnum = -1;
+
+ final boolean isEnum;
+
+ final boolean isExternalizable;
- ClassInfo(String name, FieldInfo[] fields) {
+ ClassInfo(final String name, final FieldInfo[] fields, final boolean isEnum, final boolean isExternalizable) {
this.name = name;
+ this.isEnum = isEnum;
+ this.isExternalizable = isExternalizable;
+
for (FieldInfo f : fields) {
this.name2fieldId.put(f.getName(), this.fields.size());
this.fields.add(f);
@@ -119,13 +131,7 @@ public void setObjectStreamFields(ObjectStreamField[] objectStreamFields) {
this.objectStreamFields = objectStreamFields;
}
- public int getEnum() {
- return isEnum;
- }
- public void setEnum(boolean isEnum) {
- this.isEnum = isEnum?1:0;
- }
}
/**
@@ -273,11 +279,11 @@ public void registerClass(Class clazz) throws IOException {
fields[i] = new FieldInfo(sf, clazz);
}
- ClassInfo i = new ClassInfo(clazz.getName(), fields);
+ ClassInfo i = new ClassInfo(clazz.getName(), fields,clazz.isEnum(), Externalizable.class.isAssignableFrom(clazz));
class2classId.put(clazz, registered.size());
classId2class.put(registered.size(), clazz);
registered.add(i);
- i.setEnum(clazz.isEnum());
+
if (db != null)
db.update(serialClassInfoRecid, (Serialization) this, db.defaultSerializationSerializer);
@@ -398,13 +404,27 @@ public void writeObject(DataOutput out, Object obj, FastArrayList objectStack) t
LongPacker.packInt(out, classId);
ClassInfo classInfo = registered.get(classId);
- ObjectStreamField[] fields = getFields(obj.getClass());
+ if(classInfo.isExternalizable){
+ Externalizable o = (Externalizable) obj;
+ DataInputOutput out2 = (DataInputOutput) out;
+ try{
+ out2.serializer = this;
+ out2.objectStack = objectStack;
+ o.writeExternal(out2);
+ }finally {
+ out2.serializer = null;
+ out2.objectStack = null;
+ }
+ return;
+ }
+
- if(classInfo.getEnum() > 0) {
+ if(classInfo.isEnum) {
int ordinal = ((Enum)obj).ordinal();
LongPacker.packInt(out, ordinal);
}
+ ObjectStreamField[] fields = getFields(obj.getClass());
LongPacker.packInt(out, fields.length);
for (ObjectStreamField f : fields) {
@@ -437,7 +457,7 @@ public Object readObject(DataInput in, FastArrayList objectStack) throws IOExcep
Object o;
- if(classInfo.getEnum() > 0) {
+ if(classInfo.isEnum) {
int ordinal = LongPacker.unpackInt(in);
o = clazz.getEnumConstants()[ordinal];
}
@@ -446,14 +466,27 @@ public Object readObject(DataInput in, FastArrayList objectStack) throws IOExcep
}
objectStack.add(o);
-
-
- int fieldCount = LongPacker.unpackInt(in);
- for (int i = 0; i < fieldCount; i++) {
- int fieldId = LongPacker.unpackInt(in);
- FieldInfo f = classInfo.getField(fieldId);
- Object fieldValue = deserialize(in, objectStack);
- setFieldValue(f, o, fieldValue);
+
+ if(classInfo.isExternalizable){
+ Externalizable oo = (Externalizable) o;
+ DataInputOutput in2 = (DataInputOutput) in;
+ try{
+ in2.serializer = this;
+ in2.objectStack = objectStack;
+ oo.readExternal(in2);
+ }finally {
+ in2.serializer = null;
+ in2.objectStack = null;
+ }
+
+ }else{
+ int fieldCount = LongPacker.unpackInt(in);
+ for (int i = 0; i < fieldCount; i++) {
+ int fieldId = LongPacker.unpackInt(in);
+ FieldInfo f = classInfo.getField(fieldId);
+ Object fieldValue = deserialize(in, objectStack);
+ setFieldValue(f, o, fieldValue);
+ }
}
return o;
} catch (Exception e) {
@@ -494,6 +527,7 @@ public Object readObject(DataInput in, FastArrayList objectStack) throws IOExcep
protected abstract Object deserialize(DataInput in, FastArrayList objectStack) throws IOException, ClassNotFoundException;
protected abstract void serialize(DataOutput out, Object fieldValue, FastArrayList objectStack) throws IOException;
+//
}
@@ -56,19 +56,18 @@
public Serialization() {
super(null,0L,new ArrayList<ClassInfo>());
// Add java.lang.Object as registered class
- registered.add(new ClassInfo(Object.class.getName(), new FieldInfo[]{}));
+ registered.add(new ClassInfo(Object.class.getName(), new FieldInfo[]{},false,false));
}
/**
* Serialize the object into a byte array.
*/
public byte[] serialize(Object obj)
throws IOException {
- ByteArrayOutputStream ba = new ByteArrayOutputStream();
- DataOutputStream da = new DataOutputStream(ba);
- serialize(da, obj);
+ DataInputOutput ba = new DataInputOutput();
+
+ serialize(ba, obj);
- da.close();
return ba.toByteArray();
}
@@ -592,9 +591,8 @@ else if (val > 0 && val < 255) {
* @throws ClassNotFoundException
*/
public Object deserialize(byte[] buf) throws ClassNotFoundException, IOException {
- ByteArrayInputStream bs = new ByteArrayInputStream(buf);
- DataInputStream das = new DataInputStream(bs);
- Object ret = deserialize(das);
+ DataInputOutput bs = new DataInputOutput(buf);
+ Object ret = deserialize(bs);
if (bs.available() != 0)
throw new InternalError("bytes left: " + bs.available());
@@ -315,7 +315,6 @@ public void testSerializationHeader() throws IOException {
assertEquals(header1, header2);
assertEquals(header1, SerializationHeader.JAVA_SERIALIZATION);
- System.out.println("serialization header: " + header1);
}
public void testPackedLongCollection() throws ClassNotFoundException, IOException {
@@ -430,5 +429,33 @@ public void testEnum() throws Exception{
}
+ static class Extr implements Externalizable{
+
+ int aaa = 11;
+ String l = "agfa";
+
+ public void writeExternal(ObjectOutput out) throws IOException {
+ out.writeObject(l);
+ out.writeInt(aaa);
+
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
+ l = (String) in.readObject();
+ aaa = in.readInt()+1;
+
+ }
+ }
+
+ public void testExternalizable() throws Exception{
+ Extr e = new Extr();
+ e.aaa = 15;
+ e.l = "pakla";
+
+ e = (Extr) ser.deserialize(ser.serialize(e));
+ assertEquals(e.aaa,16); //was incremented during serialization
+ assertEquals(e.l,"pakla");
+
+ }
}

0 comments on commit c4bebaf

Please sign in to comment.