final int swizzle(ByteBuffer buf, int offs, Object obj) throws Exception {
		if (obj instanceof IPersistent || obj == null) {
			offs = buf.packI4(offs, swizzle(obj, buf.finalized));
		}
		else {
			Class t = obj.getClass();

			if (t == Boolean.class) {
				buf.extend(offs + 5);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpBoolean);
				buf.arr[offs + 4] = (byte) (((Boolean) obj).booleanValue() ? 1
						: 0);
				offs += 5;
			}
			else if (t == Character.class) {
				buf.extend(offs + 6);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpChar);
				Bytes.pack2(buf.arr, offs + 4,
						(short) ((Character) obj).charValue());
				offs += 6;
			}
			else if (t == Byte.class) {
				buf.extend(offs + 5);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpByte);
				buf.arr[offs + 4] = ((Byte) obj).byteValue();
				offs += 5;
			}
			else if (t == Short.class) {
				buf.extend(offs + 6);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpShort);
				Bytes.pack2(buf.arr, offs + 4, ((Short) obj).shortValue());
				offs += 6;
			}
			else if (t == Integer.class) {
				buf.extend(offs + 8);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpInt);
				Bytes.pack4(buf.arr, offs + 4, ((Integer) obj).intValue());
				offs += 8;
			}
			else if (t == Long.class) {
				buf.extend(offs + 12);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpLong);
				Bytes.pack8(buf.arr, offs + 4, ((Long) obj).longValue());
				offs += 12;
			}
			else if (t == Float.class) {
				buf.extend(offs + 8);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpFloat);
				Bytes.packF4(buf.arr, offs + 4, ((Float) obj).floatValue());
				offs += 8;
			}
			else if (t == Double.class) {
				buf.extend(offs + 12);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpDouble);
				Bytes.packF8(buf.arr, offs + 4, ((Double) obj).doubleValue());
				offs += 12;
			}
			else if (t == Date.class) {
				buf.extend(offs + 12);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpDate);
				Bytes.pack8(buf.arr, offs + 4, ((Date) obj).getTime());
				offs += 12;
			}
			else if (t == String.class) {
				offs = buf.packI4(offs, -1 - ClassDescriptor.tpString);
				offs = buf.packString(offs, (String) obj);
			}
			else if (t == Class.class) {
				offs = buf.packI4(offs, -1 - ClassDescriptor.tpClass);
				offs = buf.packString(offs,
						ClassDescriptor.getClassName((Class) obj));
			}
			else if (obj instanceof LinkImpl) {
				LinkImpl link = (LinkImpl) obj;
				link.owner = buf.parent;
				int len = link.size();
				buf.extend(offs + 8 + len * 4);
				Bytes.pack4(buf.arr, offs, -1 - ClassDescriptor.tpLink);
				offs += 4;
				Bytes.pack4(buf.arr, offs, len);
				offs += 4;

				for (int j = 0; j < len; j++) {
					Bytes.pack4(buf.arr, offs,
							swizzle(link.getRaw(j), buf.finalized));
					offs += 4;
				}
			}
			else if (obj instanceof Collection
					&& (!serializeSystemCollections || t.getName().startsWith(
							"java.util."))) {
				ClassDescriptor valueDesc = getClassDescriptor(obj.getClass());
				offs = buf.packI4(offs, -ClassDescriptor.tpValueTypeBias
						- valueDesc.getOid());
				Collection c = (Collection) obj;
				offs = buf.packI4(offs, c.size());

				for (Object elem : c) {
					offs = swizzle(buf, offs, elem);
				}
			}
			else if (obj instanceof Map
					&& (!serializeSystemCollections || t.getName().startsWith(
							"java.util."))) {
				ClassDescriptor valueDesc = getClassDescriptor(obj.getClass());
				offs = buf.packI4(offs, -ClassDescriptor.tpValueTypeBias
						- valueDesc.getOid());
				Map map = (Map) obj;
				offs = buf.packI4(offs, map.size());

				for (Object entry : map.entrySet()) {
					Map.Entry e = (Map.Entry) entry;
					offs = swizzle(buf, offs, e.getKey());
					offs = swizzle(buf, offs, e.getValue());
				}
			}
			else if (obj instanceof IValue) {
				ClassDescriptor valueDesc = getClassDescriptor(obj.getClass());
				offs = buf.packI4(offs, -ClassDescriptor.tpValueTypeBias
						- valueDesc.getOid());
				offs = packObject(obj, valueDesc, offs, buf);
			}
			else if (t.isArray()) {
				Class elemType = t.getComponentType();

				if (elemType == byte.class) {
					byte[] arr = (byte[]) obj;
					int len = arr.length;
					buf.extend(offs + len + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfByte);
					Bytes.pack4(buf.arr, offs + 4, len);
					System.arraycopy(arr, 0, buf.arr, offs + 8, len);
					offs += 8 + len;
				}
				else if (elemType == boolean.class) {
					boolean[] arr = (boolean[]) obj;
					int len = arr.length;
					buf.extend(offs + len + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfBoolean);
					offs += 4;
					Bytes.pack4(buf.arr, offs, len);
					offs += 4;

					for (int i = 0; i < len; i++) {
						buf.arr[offs++] = (byte) (arr[i] ? 1 : 0);
					}
				}
				else if (elemType == char.class) {
					char[] arr = (char[]) obj;
					int len = arr.length;
					buf.extend(offs + len * 2 + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfChar);
					offs += 4;
					Bytes.pack4(buf.arr, offs, len);
					offs += 4;

					for (int i = 0; i < len; i++) {
						Bytes.pack2(buf.arr, offs, (short) arr[i]);
						offs += 2;
					}
				}
				else if (elemType == short.class) {
					short[] arr = (short[]) obj;
					int len = arr.length;
					buf.extend(offs + len * 2 + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfShort);
					offs += 4;
					Bytes.pack4(buf.arr, offs, len);
					offs += 4;

					for (int i = 0; i < len; i++) {
						Bytes.pack2(buf.arr, offs, arr[i]);
						offs += 2;
					}
				}
				else if (elemType == int.class) {
					int[] arr = (int[]) obj;
					int len = arr.length;
					buf.extend(offs + len * 4 + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfInt);
					offs += 4;
					Bytes.pack4(buf.arr, offs, len);
					offs += 4;

					for (int i = 0; i < len; i++) {
						Bytes.pack4(buf.arr, offs, arr[i]);
						offs += 4;
					}
				}
				else if (elemType == long.class) {
					long[] arr = (long[]) obj;
					int len = arr.length;
					buf.extend(offs + len * 8 + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfLong);
					offs += 4;
					Bytes.pack4(buf.arr, offs, len);
					offs += 4;

					for (int i = 0; i < len; i++) {
						Bytes.pack8(buf.arr, offs, arr[i]);
						offs += 8;
					}
				}
				else if (elemType == float.class) {
					float[] arr = (float[]) obj;
					int len = arr.length;
					buf.extend(offs + len * 4 + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfFloat);
					offs += 4;
					Bytes.pack4(buf.arr, offs, len);
					offs += 4;

					for (int i = 0; i < len; i++) {
						Bytes.packF4(buf.arr, offs, arr[i]);
						offs += 4;
					}
				}
				else if (elemType == double.class) {
					double[] arr = (double[]) obj;
					int len = arr.length;
					buf.extend(offs + len * 8 + 8);
					Bytes.pack4(buf.arr, offs, -1
							- ClassDescriptor.tpArrayOfLong);
					offs += 4;
					Bytes.pack4(buf.arr, offs, len);
					offs += 4;

					for (int i = 0; i < len; i++) {
						Bytes.packF8(buf.arr, offs, arr[i]);
						offs += 8;
					}
				}
				else if (elemType == Object.class) {
					offs = buf.packI4(offs, -1
							- ClassDescriptor.tpArrayOfObject);
					Object[] arr = (Object[]) obj;
					int len = arr.length;
					offs = buf.packI4(offs, len);

					for (int i = 0; i < len; i++) {
						offs = swizzle(buf, offs, arr[i]);
					}
				}
				else {
					offs = buf.packI4(offs, -1 - ClassDescriptor.tpArrayOfRaw);
					int len = Array.getLength(obj);
					offs = buf.packI4(offs, len);
					
					if (elemType.equals(Comparable.class)) {
						offs = buf.packI4(offs, -1);
					}
					else {
						ClassDescriptor desc = getClassDescriptor(elemType);
						offs = buf.packI4(offs, desc.getOid());
					}

					for (int i = 0; i < len; i++) {
						offs = swizzle(buf, offs, Array.get(obj, i));
					}
				}
			}
			else if (serializer != null && serializer.isEmbedded(obj)) {
				buf.packI4(offs, -1 - ClassDescriptor.tpCustom);
				serializer.pack(obj, buf.getOutputStream());
				offs = buf.used;
			}
			else {
				offs = buf.packI4(offs, swizzle(obj, buf.finalized));
			}
		}

		return offs;
	}