Этот код должен служить моделью, поскольку он решает проблему переполнения стека при сериализации. Он использует память вместо рекурсии. Хотя он не подходит для универсального использования в качестве сериализатора, он сериализует и десериализует классы, с которыми он был протестирован.
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import android.util.*;
public class SequentialObjectInputStream extends DataInputStream implements ObjectInput
{
interface FieldPutAction
{
void put(Object obj, Field field) throws IllegalAccessException, IOException;
}
interface ArrayPutAction
{
void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException;
}
public HashMap<Class, FieldPutAction> Primatives;
public HashMap<Class, ArrayPutAction> ArrayPrimatives;
public SequentialObjectInputStream(InputStream stream)
{
super(stream);
Primatives = new HashMap<Class, FieldPutAction>();
try
{
Primatives.put(boolean.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
boolean x = readBoolean();
field.setBoolean(obj, x);
}
});
Primatives.put(byte.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
byte x = readByte();
field.setByte(obj, x);
}
});
Primatives.put(short.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
short x = readShort();
field.setShort(obj, x);
}
});
Primatives.put(int.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
int x = readInt();
field.setInt(obj, x);
}
});
Primatives.put(long.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
long x = readLong();
field.setLong(obj, x);
}
});
Primatives.put(char.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
char x = readChar();
field.setChar(obj, x);
}
});
Primatives.put(float.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
float x = readFloat();
field.setFloat(obj, x);
}
});
Primatives.put(double.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
double x = readDouble();
field.setDouble(obj, x);
}
});
Primatives.put(String.class,
new FieldPutAction()
{
public void put(Object obj, Field field) throws IllegalAccessException, IOException
{
String x = readUTF();
field.set(obj, x);
}
});
} catch(Exception e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
ArrayPrimatives = new HashMap<Class, ArrayPutAction>();
try
{
ArrayPrimatives.put(boolean.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
boolean x = readBoolean();
Array.setBoolean(obj, index, x);
}
});
ArrayPrimatives.put(byte.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
byte x = readByte();
Array.setByte(obj, index, x);
}
});
ArrayPrimatives.put(short.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
short x = readShort();
Array.setShort(obj, index, x);
}
});
ArrayPrimatives.put(int.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
int x = readInt();
Array.setInt(obj, index, x);
}
});
ArrayPrimatives.put(long.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
long x = readLong();
Array.setLong(obj, index, x);
}
});
ArrayPrimatives.put(char.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
char x = readChar();
Array.setChar(obj, index, x);
}
});
ArrayPrimatives.put(float.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
float x = readFloat();
Array.setFloat(obj, index, x);
}
});
ArrayPrimatives.put(double.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
double x = readDouble();
Array.setDouble(obj, index, x);
}
});
ArrayPrimatives.put(String.class,
new ArrayPutAction()
{
public void put(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
String x = readUTF();
Array.set(obj, index, x);
}
});
} catch(Exception e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
}
@Override
public Object readObject() throws ClassNotFoundException, IOException
{
long Total = readLong();
Log.i("SOb", "readObject : " + Long.toString(Total) + " objects in graph");
HashMap<Long, Object> References = new HashMap<Long, Object>();
long currentId = 1;
HashMap<Object, HashMap<Field, Long>> refCache =
new HashMap<Object, HashMap<Field, Long>>();
final HashMap<Object, HashMap<Integer, Long>> arefCache =
new HashMap<Object, HashMap<Integer,Long>>();
for (int I=0; I < Total; I++)
{
String Name = readUTF();
Class C = Class.forName(Name);
Log.i("SOb", "Object of "+C.getCanonicalName() +" on graph");
int adim = 0;
Object O = null;
if (C.isArray())
{
Class ComponentType = C.getComponentType();
int Size = readInt();
Log.i("SOb", "array of "+ComponentType.getCanonicalName() + ", " + Long.toString(Size) + " elements");
O = Array.newInstance(ComponentType, Size);
References.put(currentId, O);
currentId++;
ArrayPutAction action = null;
if (ArrayPrimatives.keySet().contains(ComponentType))
{
action = ArrayPrimatives.get(ComponentType);
} else
{
arefCache.put(O, new HashMap<Integer, Long>());
action = new ArrayPutAction()
{
public void put(Object O, int Index) throws ArrayIndexOutOfBoundsException , IOException
{
long Ref = readLong();
arefCache.get(O).put(Index, Ref);
}
};
}
for (int index=0; index< Size; index++)
{
action.put(O,index);
}
} else
{
try
{
O =
C.getConstructor(new Class[0]).newInstance(new Object[0]);
} catch(InstantiationException e)
{
Log.e("SOb", Log.getStackTraceString(e));
} catch(NoSuchMethodException e)
{
Log.e("SOb", Log.getStackTraceString(e));
} catch(IllegalAccessException e)
{
Log.e("SOb", Log.getStackTraceString(e));
} catch(InvocationTargetException e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
References.put(currentId, O);
currentId++;
refCache.put(O, new HashMap<Field, Long>());
for (Field F : C.getFields())
{
if (F.isAccessible())
{
Class T = F.getType();
if (Primatives.containsKey(T))
{
try
{
Primatives.get(T).put(O, F);
} catch (IllegalAccessException e)
{
}
} else
{
refCache.get(O).put(F, readLong());
}
}
}
}
}
for (long I=0; I < Total; I++)
{
Object O = References.get(I+1);
Class C = O.getClass();
//Log.i("SOb", "get reference "+Long.toString(I)+" "+C.getCanonicalName());
if (C.isArray())
{
HashMap<Integer,Long> aref_table = arefCache.get(O);
if (ArrayPrimatives.containsKey(C.getComponentType()) == false)
{
int len = Array.getLength(O);
for (int index=0; index<len; index++)
{
long r = aref_table.get(index);
Object ref = r == 0 ? null : References.get(r);
Array.set(O, index, ref);
}
}
} else
{
HashMap<Field, Long> ref_table = refCache.get(O);
for (Field F : C.getFields())
{
if (F.isAccessible())
{
Class T = F.getType();
if (Primatives.containsKey(T) == false)
{
try
{
long r = ref_table.get(F);
Object ref = r == 0 ? null : References.get(r);
F.set(O, ref);
} catch (IllegalAccessException e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
}
}
}
}
}
return References.get((Long) (long) 1);
}
}
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import android.util.*;
public class SequentialObjectOutputStream extends DataOutputStream
implements ObjectOutput
{
interface FieldGetAction
{
void get(Object obj, Field field) throws IllegalAccessException, IOException;
}
interface ArrayGetAction
{
void get(Object array, int Index) throws ArrayIndexOutOfBoundsException, IOException;
}
public HashMap<Class, FieldGetAction> Primatives;
public HashMap<Class, ArrayGetAction> ArrayPrimatives;
public SequentialObjectOutputStream(OutputStream stream)
{
super(stream);
Primatives = new HashMap<Class, FieldGetAction>();
try
{
Primatives.put(boolean.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
boolean x = field.getBoolean(obj);
writeBoolean(x);
}
});
Primatives.put(byte.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
byte x = field.getByte(obj);
writeByte(x);
}
});
Primatives.put(short.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
short x = field.getShort(obj);
writeShort(x);
}
});
Primatives.put(int.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
int x = field.getInt(obj);
writeInt(x);
}
});
Primatives.put(long.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
long x = field.getLong(obj);
writeLong(x);
}
});
Primatives.put(char.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
char x = field.getChar(obj);
writeChar(x);
}
});
Primatives.put(float.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
float x = field.getFloat(obj);
writeFloat(x);
}
});
Primatives.put(double.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
double x = field.getDouble(obj);
writeDouble(x);
}
});
Primatives.put(String.class,
new FieldGetAction()
{
public void get(Object obj, Field field) throws IllegalAccessException, IOException
{
String x = (String) field.get(obj);
writeUTF(x);
}
});
} catch(Exception e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
ArrayPrimatives = new HashMap<Class, ArrayGetAction>();
try
{
ArrayPrimatives.put(boolean.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
boolean x = Array.getBoolean(obj, index);
writeBoolean(x);
}
});
ArrayPrimatives.put(byte.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
byte x = Array.getByte(obj, index);
writeByte(x);
}
});
ArrayPrimatives.put(short.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
short x = Array.getShort(obj, index);
writeShort(x);
}
});
ArrayPrimatives.put(int.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
int x = Array.getInt(obj, index);
writeInt(x);
}
});
ArrayPrimatives.put(long.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
long x = Array.getLong(obj, index);
writeLong(x);
}
});
ArrayPrimatives.put(char.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
char x = Array.getChar(obj, index);
writeChar(x);
}
});
ArrayPrimatives.put(float.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
float x = Array.getFloat(obj, index);
writeFloat(x);
}
});
ArrayPrimatives.put(double.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
double x = Array.getDouble(obj, index);
writeDouble(x);
}
});
ArrayPrimatives.put(String.class,
new ArrayGetAction()
{
public void get(Object obj, int index) throws ArrayIndexOutOfBoundsException, IOException
{
String x = (String) Array.get(obj, index);
writeUTF(x);
}
});
} catch(Exception e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
}
class State
{
public ArrayList<Object> OStack = new ArrayList<Object>();
public long currentId = 1;
public HashMap<Object, Long> References = new HashMap<Object, Long>();
}
public void writeObject(Object A) throws IOException, NotSerializableException
{
final State state = new State();
state.OStack.add(0, A);
LinkedList<Object> ForStack = new LinkedList<Object>();
while (!(state.OStack.size() == 0))
{
Object Current = state.OStack.get(0);
state.OStack.remove(0);
if (((Serializable) Current) == null)
{
throw new NotSerializableException();
}
//Type C = Current.getClass();
Class C = Current.getClass();
Log.i("SOb", "placing #"+Long.toString(state.currentId)+" of "+C.getCanonicalName()+" on graph");
state.References.put(Current, state.currentId);
state.currentId++;
ForStack.add(Current);
if (C.isArray())
{
//Array array = (Array) Current;
Class Ctype = C.getComponentType();
if (ArrayPrimatives.keySet().contains(Ctype) == false)
{
for (int I=0; I<Array.getLength(Current); I++)
{
Object o = Array.get(Current, I);
if ((o != null) && (state.References.keySet().contains(o) == false))
{
if (state.OStack.contains(o) == false) state.OStack.add(state.OStack.size(), o);
}
}
}
} else
{
for (Class Cur = C; Cur != null; Cur = Cur.getSuperclass())
{
Field[] fields = Cur.getDeclaredFields();
for (Field f : fields)
{
if (Modifier.isStatic(f.getModifiers()))
{
continue;
}
f.setAccessible(true);
if (f.isAccessible() == false)
{
// Log.i("SOb", " isAccessible = false");
continue;
}
Class type = f.getType();
//Log.i("SOb", " field \""+f.getName()+"\" of "+type.getCanonicalName());
if (Primatives.keySet().contains(type) == false)
{
try
{
Object o = f.get(Current);
if ((o != null) && (state.References.keySet().contains(o) == false))
{
if (state.OStack.contains(o) == false) state.OStack.add(state.OStack.size(), o);
}
} catch (IllegalAccessException e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
}
}
}
}
}
writeLong(state.References.size());
for (Object O : ForStack )
{
Serializable s = (Serializable) O;
// if (s != null)
{
Class cl = O.getClass();
String name = cl.getName();
writeUTF(name);
if (cl.isArray())
{
Class components = cl.getComponentType();
ArrayGetAction action;
//Array array = (Array) O;
if (ArrayPrimatives.keySet().contains(components))
{
action = ArrayPrimatives.get(components);
} else
{
action = new ArrayGetAction()
{
public void get(Object array, int index) throws ArrayIndexOutOfBoundsException, IOException
{
Object O = Array.get(array, index);
if (O==null) writeLong(0);
else writeLong(state.References.get(O));
}
};
}
int length = Array.getLength(O);
writeInt(length);
for (int I=0; I<length; I++)
{
action.get(O, I);
}
} else
{
for (Class Cur = cl; Cur != null; Cur = Cur.getSuperclass())
{
Field[] fields = Cur.getDeclaredFields();
for (Field F : fields)
{
Class FieldType = F.getType();
F.setAccessible(true);
if (F.isAccessible() && (Modifier.isStatic(FieldType.getModifiers())))
{
FieldGetAction action;
//Array array = (Array) O;
if (Primatives.keySet().contains(FieldType))
{
action = Primatives.get(FieldType);
} else
{
action = new FieldGetAction()
{
public void get(Object obj, Field index) throws IllegalAccessException, IOException
{
Object O = index.get(obj);
if (O==null) writeLong(0);
else writeLong(state.References.get(O));
}
};
}
try
{
action.get(O, F);
} catch (IllegalAccessException e)
{
Log.e("SOb", Log.getStackTraceString(e));
}
}
}
}
}
}
}
}
}