Parcelable: Use ClassLoader from the container class to load Parcelable (KT-20027)
When the parameter type is just "Parcelable", we would not pick the wrong (system) class loader anymore.
This commit is contained in:
committed by
Yan Zhulanow
parent
c9ec1a2511
commit
3587a2a08e
+5
-2
@@ -114,6 +114,8 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
||||
"(${containerAsmType.descriptor}${PARCEL_TYPE.descriptor}I)V", false)
|
||||
}
|
||||
else {
|
||||
val context = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType)
|
||||
|
||||
for ((fieldName, type) in properties) {
|
||||
val asmType = codegen.typeMapper.mapType(type)
|
||||
|
||||
@@ -121,7 +123,7 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
||||
v.load(0, containerAsmType)
|
||||
v.getfield(containerAsmType.internalName, fieldName, asmType.descriptor)
|
||||
|
||||
val serializer = ParcelSerializer.get(type, asmType, codegen.typeMapper)
|
||||
val serializer = ParcelSerializer.get(type, asmType, context)
|
||||
serializer.writeValue(v)
|
||||
}
|
||||
}
|
||||
@@ -191,12 +193,13 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
||||
v.dup()
|
||||
|
||||
val asmConstructorParameters = StringBuilder()
|
||||
val context = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType)
|
||||
|
||||
for ((_, type) in properties) {
|
||||
val asmType = codegen.typeMapper.mapType(type)
|
||||
asmConstructorParameters.append(asmType.descriptor)
|
||||
|
||||
val serializer = ParcelSerializer.get(type, asmType, codegen.typeMapper)
|
||||
val serializer = ParcelSerializer.get(type, asmType, context)
|
||||
v.load(1, parcelAsmType)
|
||||
serializer.readValue(v)
|
||||
}
|
||||
|
||||
+9
-3
@@ -183,11 +183,16 @@ class ParcelableDeclarationChecker : SimpleDeclarationChecker {
|
||||
/* isJvm8TargetWithDefaults */ false)
|
||||
|
||||
for (parameter in primaryConstructor?.valueParameters.orEmpty()) {
|
||||
checkParcelableClassProperty(parameter, diagnosticHolder, typeMapper)
|
||||
checkParcelableClassProperty(parameter, descriptor, diagnosticHolder, typeMapper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkParcelableClassProperty(parameter: KtParameter, diagnosticHolder: DiagnosticSink, typeMapper: KotlinTypeMapper) {
|
||||
private fun checkParcelableClassProperty(
|
||||
parameter: KtParameter,
|
||||
containerClass: ClassDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
typeMapper: KotlinTypeMapper
|
||||
) {
|
||||
if (!parameter.hasValOrVar()) {
|
||||
val reportElement = parameter.nameIdentifier ?: parameter
|
||||
diagnosticHolder.reportFromPlugin(
|
||||
@@ -201,7 +206,8 @@ class ParcelableDeclarationChecker : SimpleDeclarationChecker {
|
||||
val asmType = typeMapper.mapType(type)
|
||||
|
||||
try {
|
||||
ParcelSerializer.get(type, asmType, typeMapper, strict = true)
|
||||
val context = ParcelSerializer.ParcelSerializerContext(typeMapper, typeMapper.mapType(containerClass.defaultType))
|
||||
ParcelSerializer.get(type, asmType, context, strict = true)
|
||||
}
|
||||
catch (e: IllegalArgumentException) {
|
||||
// get() throws IllegalArgumentException on unknown types
|
||||
|
||||
+12
-8
@@ -44,6 +44,8 @@ interface ParcelSerializer {
|
||||
fun writeValue(v: InstructionAdapter)
|
||||
fun readValue(v: InstructionAdapter)
|
||||
|
||||
class ParcelSerializerContext(val typeMapper: KotlinTypeMapper, val containerClassType: Type)
|
||||
|
||||
companion object {
|
||||
private fun KotlinTypeMapper.mapTypeSafe(type: KotlinType): Type {
|
||||
return if (type.isError) Type.getObjectType("java/lang/Object") else mapType(type)
|
||||
@@ -52,17 +54,19 @@ interface ParcelSerializer {
|
||||
fun get(
|
||||
type: KotlinType,
|
||||
asmType: Type,
|
||||
typeMapper: KotlinTypeMapper,
|
||||
context: ParcelSerializerContext,
|
||||
forceBoxed: Boolean = false,
|
||||
strict: Boolean = false
|
||||
): ParcelSerializer {
|
||||
val typeMapper = context.typeMapper
|
||||
|
||||
val className = asmType.className
|
||||
fun strict() = strict && !type.annotations.hasAnnotation(RAWVALUE_ANNOTATION_FQNAME)
|
||||
|
||||
return when {
|
||||
asmType.sort == Type.ARRAY -> {
|
||||
val elementType = type.builtIns.getArrayElementType(type)
|
||||
val elementSerializer = get(elementType, typeMapper.mapTypeSafe(elementType), typeMapper, strict = strict())
|
||||
val elementSerializer = get(elementType, typeMapper.mapTypeSafe(elementType), context, strict = strict())
|
||||
|
||||
wrapToNullAwareIfNeeded(type, ArrayParcelSerializer(asmType, elementSerializer))
|
||||
}
|
||||
@@ -90,7 +94,7 @@ interface ParcelSerializer {
|
||||
-> {
|
||||
val elementType = type.arguments.single().type
|
||||
val elementSerializer = get(
|
||||
elementType, typeMapper.mapTypeSafe(elementType), typeMapper, forceBoxed = true, strict = strict())
|
||||
elementType, typeMapper.mapTypeSafe(elementType), context, forceBoxed = true, strict = strict())
|
||||
wrapToNullAwareIfNeeded(type, ListSetParcelSerializer(asmType, elementSerializer))
|
||||
}
|
||||
|
||||
@@ -104,9 +108,9 @@ interface ParcelSerializer {
|
||||
-> {
|
||||
val (keyType, valueType) = type.arguments.apply { assert(this.size == 2) }
|
||||
val keySerializer = get(
|
||||
keyType.type, typeMapper.mapTypeSafe(keyType.type), typeMapper, forceBoxed = true, strict = strict())
|
||||
keyType.type, typeMapper.mapTypeSafe(keyType.type), context, forceBoxed = true, strict = strict())
|
||||
val valueSerializer = get(
|
||||
valueType.type, typeMapper.mapTypeSafe(valueType.type), typeMapper, forceBoxed = true, strict = strict())
|
||||
valueType.type, typeMapper.mapTypeSafe(valueType.type), context, forceBoxed = true, strict = strict())
|
||||
wrapToNullAwareIfNeeded(type, MapParcelSerializer(asmType, keySerializer, valueSerializer))
|
||||
}
|
||||
|
||||
@@ -153,7 +157,7 @@ interface ParcelSerializer {
|
||||
asmType.isSparseArray() -> {
|
||||
val elementType = type.arguments.single().type
|
||||
val elementSerializer = get(
|
||||
elementType, typeMapper.mapTypeSafe(elementType), typeMapper, forceBoxed = true, strict = strict())
|
||||
elementType, typeMapper.mapTypeSafe(elementType), context, forceBoxed = true, strict = strict())
|
||||
wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(asmType, elementSerializer))
|
||||
}
|
||||
|
||||
@@ -186,10 +190,10 @@ interface ParcelSerializer {
|
||||
}
|
||||
|
||||
creatorAsmType?.let { EfficientParcelableParcelSerializer(asmType, creatorAsmType) }
|
||||
?: GenericParcelableParcelSerializer(asmType)
|
||||
?: GenericParcelableParcelSerializer(asmType, context.containerClassType)
|
||||
}
|
||||
else {
|
||||
GenericParcelableParcelSerializer(asmType)
|
||||
GenericParcelableParcelSerializer(asmType, context.containerClassType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -462,7 +462,7 @@ internal class EfficientParcelableParcelSerializer(override val asmType: Type, p
|
||||
}
|
||||
}
|
||||
|
||||
internal class GenericParcelableParcelSerializer(override val asmType: Type) : ParcelSerializer {
|
||||
internal class GenericParcelableParcelSerializer(override val asmType: Type, val containerClassType: Type) : ParcelSerializer {
|
||||
override fun writeValue(v: InstructionAdapter) {
|
||||
// -> parcel, parcelable
|
||||
v.aconst(0) // -> parcel, parcelable, flags
|
||||
@@ -471,7 +471,7 @@ internal class GenericParcelableParcelSerializer(override val asmType: Type) : P
|
||||
|
||||
override fun readValue(v: InstructionAdapter) {
|
||||
// -> parcel
|
||||
v.aconst(asmType) // -> parcel, type
|
||||
v.aconst(containerClassType) // -> parcel, type
|
||||
v.invokevirtual("java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false) // -> parcel, classloader
|
||||
v.invokevirtual(PARCEL_TYPE.internalName, "readParcelable", "(Ljava/lang/ClassLoader;)Landroid/os/Parcelable;", false)
|
||||
v.castIfNeeded(asmType)
|
||||
|
||||
Reference in New Issue
Block a user