Merge "Adding typed Parcel read APIs for Serializable."

This commit is contained in:
Hao Ke
2021-11-02 02:08:29 +00:00
committed by Gerrit Code Review
2 changed files with 65 additions and 19 deletions

View File

@@ -31473,6 +31473,7 @@ package android.os {
method @Nullable public android.os.PersistableBundle readPersistableBundle();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
method @Nullable public java.io.Serializable readSerializable();
method @Nullable public <T extends java.io.Serializable> T readSerializable(@Nullable ClassLoader, @NonNull Class<T>);
method @NonNull public android.util.Size readSize();
method @NonNull public android.util.SizeF readSizeF();
method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);

View File

@@ -2448,9 +2448,9 @@ public final class Parcel {
writeByteArray(baos.toByteArray());
} catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " +
"IOException writing serializable object (name = " + name +
")", ioe);
throw new BadParcelableException("Parcelable encountered "
+ "IOException writing serializable object (name = "
+ name + ")", ioe);
}
}
@@ -3818,7 +3818,7 @@ public final class Parcel {
break;
case VAL_SERIALIZABLE:
object = readSerializable(loader);
object = readSerializableInternal(loader, clazz);
break;
case VAL_PARCELABLEARRAY:
@@ -4144,12 +4144,37 @@ public final class Parcel {
* wasn't found in the parcel.
*/
@Nullable
public final Serializable readSerializable() {
return readSerializable(null);
public Serializable readSerializable() {
return readSerializableInternal(/* loader */ null, /* clazz */ null);
}
/**
* Same as {@link #readSerializable()} but accepts {@code loader} parameter
* as the primary classLoader for resolving the Serializable class; and {@code clazz} parameter
* as the required type.
*
* @throws BadParcelableException Throws BadParcelableException if the item to be deserialized
* is not an instance of that class or any of its children class or there there was an error
* deserializing the object.
*/
@Nullable
private final Serializable readSerializable(@Nullable final ClassLoader loader) {
public <T extends Serializable> T readSerializable(@Nullable ClassLoader loader,
@NonNull Class<T> clazz) {
Objects.requireNonNull(clazz);
return readSerializableInternal(loader, clazz);
}
/**
* @param clazz The type of the serializable expected or {@code null} for performing no checks
*/
@Nullable
private <T> T readSerializableInternal(@Nullable final ClassLoader loader,
@Nullable Class<T> clazz) {
if (clazz != null && !Serializable.class.isAssignableFrom(clazz)) {
throw new BadParcelableException("About to unparcel a serializable object "
+ " but class required " + clazz.getName() + " is not Serializable");
}
String name = readString();
if (name == null) {
// For some reason we were unable to read the name of the Serializable (either there
@@ -4158,9 +4183,20 @@ public final class Parcel {
return null;
}
byte[] serializedData = createByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);
try {
if (clazz != null && loader != null) {
// If custom classloader is provided, resolve the type of serializable using the
// name, then check the type before deserialization. As in this case we can resolve
// the class the same way as ObjectInputStream, using the provided classloader.
Class<?> cl = Class.forName(name, false, loader);
if (!clazz.isAssignableFrom(cl)) {
throw new BadParcelableException("Serializable object "
+ cl.getName() + " is not a subclass of required class "
+ clazz.getName() + " provided in the parameter");
}
}
byte[] serializedData = createByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);
ObjectInputStream ois = new ObjectInputStream(bais) {
@Override
protected Class<?> resolveClass(ObjectStreamClass osClass)
@@ -4168,22 +4204,31 @@ public final class Parcel {
// try the custom classloader if provided
if (loader != null) {
Class<?> c = Class.forName(osClass.getName(), false, loader);
if (c != null) {
return c;
}
return Objects.requireNonNull(c);
}
return super.resolveClass(osClass);
}
};
return (Serializable) ois.readObject();
T object = (T) ois.readObject();
if (clazz != null && loader == null) {
// If custom classloader is not provided, check the type of the serializable using
// the deserialized object, as we cannot resolve the class the same way as
// ObjectInputStream.
if (!clazz.isAssignableFrom(object.getClass())) {
throw new BadParcelableException("Serializable object "
+ object.getClass().getName() + " is not a subclass of required class "
+ clazz.getName() + " provided in the parameter");
}
}
return object;
} catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " +
"IOException reading a Serializable object (name = " + name +
")", ioe);
throw new BadParcelableException("Parcelable encountered "
+ "IOException reading a Serializable object (name = "
+ name + ")", ioe);
} catch (ClassNotFoundException cnfe) {
throw new RuntimeException("Parcelable encountered " +
"ClassNotFoundException reading a Serializable object (name = "
+ name + ")", cnfe);
throw new BadParcelableException("Parcelable encountered "
+ "ClassNotFoundException reading a Serializable object (name = "
+ name + ")", cnfe);
}
}