final int idx = instanceCache.size();
instanceCache.add(UNRESOLVED);
final int size = readInt();
final Class<?> type = descriptor.getType();
if (! type.isArray()) {
throw new InvalidClassException(type.getName(), "Expected array type");
}
final Class<?> ct = type.getComponentType();
if (ct.isPrimitive()) {
if (ct == byte.class) {
final byte[] bytes = new byte[size];
readFully(bytes);
return replaceOrReturn(unshared, bytes, idx);
} else if (ct == short.class) {
final short[] shorts = new short[size];
for (int i = 0; i < shorts.length; i++) {
shorts[i] = readShort();
}
return replaceOrReturn(unshared, shorts, idx);
} else if (ct == int.class) {
final int[] ints = new int[size];
for (int i = 0; i < ints.length; i++) {
ints[i] = readInt();
}
return replaceOrReturn(unshared, ints, idx);
} else if (ct == long.class) {
final long[] longs = new long[size];
for (int i = 0; i < longs.length; i++) {
longs[i] = readLong();
}
return replaceOrReturn(unshared, longs, idx);
} else if (ct == float.class) {
final float[] floats = new float[size];
for (int i = 0; i < floats.length; i++) {
floats[i] = readFloat();
}
return replaceOrReturn(unshared, floats, idx);
} else if (ct == double.class) {
final double[] doubles = new double[size];
for (int i = 0; i < doubles.length; i++) {
doubles[i] = readDouble();
}
return replaceOrReturn(unshared, doubles, idx);
} else if (ct == boolean.class) {
final boolean[] booleans = new boolean[size];
for (int i = 0; i < booleans.length; i++) {
booleans[i] = readBoolean();
}
return replaceOrReturn(unshared, booleans, idx);
} else if (ct == char.class) {
final char[] chars = new char[size];
for (int i = 0; i < chars.length; i++) {
chars[i] = readChar();
}
return replaceOrReturn(unshared, chars, idx);
} else {
throw new InvalidClassException(type.getName(), "Invalid component type");
}
} else {
final Object[] objects = (Object[]) Array.newInstance(ct, size);
instanceCache.set(idx, objects);
for (int i = 0; i < objects.length; i++) {
objects[i] = doReadObject(false);
}
return replaceOrReturn(unshared, objects, idx);
}
}
case TC_ENUM: {
final Descriptor descriptor = readNonNullClassDescriptor();
final Class<? extends Enum> enumType;
try {
enumType = descriptor.getType().asSubclass(Enum.class);
} catch (ClassCastException e) {
throw new InvalidClassException("Expected an enum class descriptor");
}
final int idx = instanceCache.size();
instanceCache.add(UNRESOLVED);
final String constName = (String) doReadObject(false);
final Enum obj = Enum.valueOf(enumType, constName);
return replaceOrReturn(unshared, obj, idx);
}
case TC_OBJECT: {
final Descriptor descriptor = readNonNullClassDescriptor();
if ((descriptor.getFlags() & (SC_SERIALIZABLE | SC_EXTERNALIZABLE)) == 0) {
throw new NotSerializableException(descriptor.getClass().getName());
}
final Object obj;
final int idx;
final Class<?> objClass = descriptor.getType();
final SerializableClass sc = registry.lookup(objClass);
if ((descriptor.getFlags() & SC_EXTERNALIZABLE) != 0) {
if (sc.hasObjectInputConstructor()) {
obj = sc.callObjectInputConstructor(blockUnmarshaller);
} else if (sc.hasNoArgConstructor()) {
obj = sc.callNoArgConstructor();
} else {
throw new InvalidClassException(objClass.getName(), "Class is non-public or has no public no-arg constructor");
}
idx = instanceCache.size();
instanceCache.add(unshared ? UNSHARED : obj);
if (obj instanceof Externalizable) {
final Externalizable externalizable = (Externalizable) obj;