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();
method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader); method @Nullable public android.os.PersistableBundle readPersistableBundle(@Nullable ClassLoader);
method @Nullable public java.io.Serializable readSerializable(); 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.Size readSize();
method @NonNull public android.util.SizeF readSizeF(); method @NonNull public android.util.SizeF readSizeF();
method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader); method @Nullable public <T> android.util.SparseArray<T> readSparseArray(@Nullable ClassLoader);

View File

@@ -2448,9 +2448,9 @@ public final class Parcel {
writeByteArray(baos.toByteArray()); writeByteArray(baos.toByteArray());
} catch (IOException ioe) { } catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " + throw new BadParcelableException("Parcelable encountered "
"IOException writing serializable object (name = " + name + + "IOException writing serializable object (name = "
")", ioe); + name + ")", ioe);
} }
} }
@@ -3818,7 +3818,7 @@ public final class Parcel {
break; break;
case VAL_SERIALIZABLE: case VAL_SERIALIZABLE:
object = readSerializable(loader); object = readSerializableInternal(loader, clazz);
break; break;
case VAL_PARCELABLEARRAY: case VAL_PARCELABLEARRAY:
@@ -4144,12 +4144,37 @@ public final class Parcel {
* wasn't found in the parcel. * wasn't found in the parcel.
*/ */
@Nullable @Nullable
public final Serializable readSerializable() { public Serializable readSerializable() {
return readSerializable(null); 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 @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(); String name = readString();
if (name == null) { if (name == null) {
// For some reason we were unable to read the name of the Serializable (either there // 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; return null;
} }
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(); byte[] serializedData = createByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); ByteArrayInputStream bais = new ByteArrayInputStream(serializedData);
try {
ObjectInputStream ois = new ObjectInputStream(bais) { ObjectInputStream ois = new ObjectInputStream(bais) {
@Override @Override
protected Class<?> resolveClass(ObjectStreamClass osClass) protected Class<?> resolveClass(ObjectStreamClass osClass)
@@ -4168,21 +4204,30 @@ public final class Parcel {
// try the custom classloader if provided // try the custom classloader if provided
if (loader != null) { if (loader != null) {
Class<?> c = Class.forName(osClass.getName(), false, loader); Class<?> c = Class.forName(osClass.getName(), false, loader);
if (c != null) { return Objects.requireNonNull(c);
return c;
}
} }
return super.resolveClass(osClass); 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) { } catch (IOException ioe) {
throw new RuntimeException("Parcelable encountered " + throw new BadParcelableException("Parcelable encountered "
"IOException reading a Serializable object (name = " + name + + "IOException reading a Serializable object (name = "
")", ioe); + name + ")", ioe);
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
throw new RuntimeException("Parcelable encountered " + throw new BadParcelableException("Parcelable encountered "
"ClassNotFoundException reading a Serializable object (name = " + "ClassNotFoundException reading a Serializable object (name = "
+ name + ")", cnfe); + name + ")", cnfe);
} }
} }