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)
|
"(${containerAsmType.descriptor}${PARCEL_TYPE.descriptor}I)V", false)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
val context = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType)
|
||||||
|
|
||||||
for ((fieldName, type) in properties) {
|
for ((fieldName, type) in properties) {
|
||||||
val asmType = codegen.typeMapper.mapType(type)
|
val asmType = codegen.typeMapper.mapType(type)
|
||||||
|
|
||||||
@@ -121,7 +123,7 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
|||||||
v.load(0, containerAsmType)
|
v.load(0, containerAsmType)
|
||||||
v.getfield(containerAsmType.internalName, fieldName, asmType.descriptor)
|
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)
|
serializer.writeValue(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,12 +193,13 @@ open class ParcelableCodegenExtension : ExpressionCodegenExtension {
|
|||||||
v.dup()
|
v.dup()
|
||||||
|
|
||||||
val asmConstructorParameters = StringBuilder()
|
val asmConstructorParameters = StringBuilder()
|
||||||
|
val context = ParcelSerializer.ParcelSerializerContext(codegen.typeMapper, containerAsmType)
|
||||||
|
|
||||||
for ((_, type) in properties) {
|
for ((_, type) in properties) {
|
||||||
val asmType = codegen.typeMapper.mapType(type)
|
val asmType = codegen.typeMapper.mapType(type)
|
||||||
asmConstructorParameters.append(asmType.descriptor)
|
asmConstructorParameters.append(asmType.descriptor)
|
||||||
|
|
||||||
val serializer = ParcelSerializer.get(type, asmType, codegen.typeMapper)
|
val serializer = ParcelSerializer.get(type, asmType, context)
|
||||||
v.load(1, parcelAsmType)
|
v.load(1, parcelAsmType)
|
||||||
serializer.readValue(v)
|
serializer.readValue(v)
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-3
@@ -183,11 +183,16 @@ class ParcelableDeclarationChecker : SimpleDeclarationChecker {
|
|||||||
/* isJvm8TargetWithDefaults */ false)
|
/* isJvm8TargetWithDefaults */ false)
|
||||||
|
|
||||||
for (parameter in primaryConstructor?.valueParameters.orEmpty()) {
|
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()) {
|
if (!parameter.hasValOrVar()) {
|
||||||
val reportElement = parameter.nameIdentifier ?: parameter
|
val reportElement = parameter.nameIdentifier ?: parameter
|
||||||
diagnosticHolder.reportFromPlugin(
|
diagnosticHolder.reportFromPlugin(
|
||||||
@@ -201,7 +206,8 @@ class ParcelableDeclarationChecker : SimpleDeclarationChecker {
|
|||||||
val asmType = typeMapper.mapType(type)
|
val asmType = typeMapper.mapType(type)
|
||||||
|
|
||||||
try {
|
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) {
|
catch (e: IllegalArgumentException) {
|
||||||
// get() throws IllegalArgumentException on unknown types
|
// get() throws IllegalArgumentException on unknown types
|
||||||
|
|||||||
+12
-8
@@ -44,6 +44,8 @@ interface ParcelSerializer {
|
|||||||
fun writeValue(v: InstructionAdapter)
|
fun writeValue(v: InstructionAdapter)
|
||||||
fun readValue(v: InstructionAdapter)
|
fun readValue(v: InstructionAdapter)
|
||||||
|
|
||||||
|
class ParcelSerializerContext(val typeMapper: KotlinTypeMapper, val containerClassType: Type)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun KotlinTypeMapper.mapTypeSafe(type: KotlinType): Type {
|
private fun KotlinTypeMapper.mapTypeSafe(type: KotlinType): Type {
|
||||||
return if (type.isError) Type.getObjectType("java/lang/Object") else mapType(type)
|
return if (type.isError) Type.getObjectType("java/lang/Object") else mapType(type)
|
||||||
@@ -52,17 +54,19 @@ interface ParcelSerializer {
|
|||||||
fun get(
|
fun get(
|
||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
asmType: Type,
|
asmType: Type,
|
||||||
typeMapper: KotlinTypeMapper,
|
context: ParcelSerializerContext,
|
||||||
forceBoxed: Boolean = false,
|
forceBoxed: Boolean = false,
|
||||||
strict: Boolean = false
|
strict: Boolean = false
|
||||||
): ParcelSerializer {
|
): ParcelSerializer {
|
||||||
|
val typeMapper = context.typeMapper
|
||||||
|
|
||||||
val className = asmType.className
|
val className = asmType.className
|
||||||
fun strict() = strict && !type.annotations.hasAnnotation(RAWVALUE_ANNOTATION_FQNAME)
|
fun strict() = strict && !type.annotations.hasAnnotation(RAWVALUE_ANNOTATION_FQNAME)
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
asmType.sort == Type.ARRAY -> {
|
asmType.sort == Type.ARRAY -> {
|
||||||
val elementType = type.builtIns.getArrayElementType(type)
|
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))
|
wrapToNullAwareIfNeeded(type, ArrayParcelSerializer(asmType, elementSerializer))
|
||||||
}
|
}
|
||||||
@@ -90,7 +94,7 @@ interface ParcelSerializer {
|
|||||||
-> {
|
-> {
|
||||||
val elementType = type.arguments.single().type
|
val elementType = type.arguments.single().type
|
||||||
val elementSerializer = get(
|
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))
|
wrapToNullAwareIfNeeded(type, ListSetParcelSerializer(asmType, elementSerializer))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,9 +108,9 @@ interface ParcelSerializer {
|
|||||||
-> {
|
-> {
|
||||||
val (keyType, valueType) = type.arguments.apply { assert(this.size == 2) }
|
val (keyType, valueType) = type.arguments.apply { assert(this.size == 2) }
|
||||||
val keySerializer = get(
|
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(
|
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))
|
wrapToNullAwareIfNeeded(type, MapParcelSerializer(asmType, keySerializer, valueSerializer))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +157,7 @@ interface ParcelSerializer {
|
|||||||
asmType.isSparseArray() -> {
|
asmType.isSparseArray() -> {
|
||||||
val elementType = type.arguments.single().type
|
val elementType = type.arguments.single().type
|
||||||
val elementSerializer = get(
|
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))
|
wrapToNullAwareIfNeeded(type, SparseArrayParcelSerializer(asmType, elementSerializer))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,10 +190,10 @@ interface ParcelSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
creatorAsmType?.let { EfficientParcelableParcelSerializer(asmType, creatorAsmType) }
|
creatorAsmType?.let { EfficientParcelableParcelSerializer(asmType, creatorAsmType) }
|
||||||
?: GenericParcelableParcelSerializer(asmType)
|
?: GenericParcelableParcelSerializer(asmType, context.containerClassType)
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
override fun writeValue(v: InstructionAdapter) {
|
||||||
// -> parcel, parcelable
|
// -> parcel, parcelable
|
||||||
v.aconst(0) // -> parcel, parcelable, flags
|
v.aconst(0) // -> parcel, parcelable, flags
|
||||||
@@ -471,7 +471,7 @@ internal class GenericParcelableParcelSerializer(override val asmType: Type) : P
|
|||||||
|
|
||||||
override fun readValue(v: InstructionAdapter) {
|
override fun readValue(v: InstructionAdapter) {
|
||||||
// -> parcel
|
// -> 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("java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;", false) // -> parcel, classloader
|
||||||
v.invokevirtual(PARCEL_TYPE.internalName, "readParcelable", "(Ljava/lang/ClassLoader;)Landroid/os/Parcelable;", false)
|
v.invokevirtual(PARCEL_TYPE.internalName, "readParcelable", "(Ljava/lang/ClassLoader;)Landroid/os/Parcelable;", false)
|
||||||
v.castIfNeeded(asmType)
|
v.castIfNeeded(asmType)
|
||||||
|
|||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
// CURIOUS_ABOUT writeToParcel, createFromParcel, <clinit>
|
||||||
|
|
||||||
|
package test
|
||||||
|
|
||||||
|
import kotlinx.android.parcel.*
|
||||||
|
import android.os.Parcelable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
class Foo(val parcelable: Parcelable): Parcelable
|
||||||
Vendored
+68
@@ -0,0 +1,68 @@
|
|||||||
|
public final class test/Foo$Companion : java/lang/Object {
|
||||||
|
private void <init>()
|
||||||
|
|
||||||
|
public void <init>(kotlin.jvm.internal.DefaultConstructorMarker p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class test/Foo$Creator : java/lang/Object, android/os/Parcelable$Creator {
|
||||||
|
public void <init>()
|
||||||
|
|
||||||
|
public final java.lang.Object createFromParcel(android.os.Parcel p0) {
|
||||||
|
LABEL (L0)
|
||||||
|
ALOAD (1)
|
||||||
|
LDC (in)
|
||||||
|
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkParameterIsNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||||
|
NEW
|
||||||
|
DUP
|
||||||
|
ALOAD (1)
|
||||||
|
LDC (Ltest/Foo;)
|
||||||
|
INVOKEVIRTUAL (java/lang/Class, getClassLoader, ()Ljava/lang/ClassLoader;)
|
||||||
|
INVOKEVIRTUAL (android/os/Parcel, readParcelable, (Ljava/lang/ClassLoader;)Landroid/os/Parcelable;)
|
||||||
|
INVOKESPECIAL (test/Foo, <init>, (Landroid/os/Parcelable;)V)
|
||||||
|
ARETURN
|
||||||
|
LABEL (L1)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final test.Foo[] newArray(int p0)
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class test/Foo : java/lang/Object, android/os/Parcelable {
|
||||||
|
public final static test.Foo$Creator CREATOR
|
||||||
|
|
||||||
|
public final static test.Foo$Companion Companion
|
||||||
|
|
||||||
|
private final android.os.Parcelable parcelable
|
||||||
|
|
||||||
|
static void <clinit>() {
|
||||||
|
NEW
|
||||||
|
DUP
|
||||||
|
ACONST_NULL
|
||||||
|
INVOKESPECIAL (test/Foo$Companion, <init>, (Lkotlin/jvm/internal/DefaultConstructorMarker;)V)
|
||||||
|
PUTSTATIC (Companion, Ltest/Foo$Companion;)
|
||||||
|
NEW
|
||||||
|
DUP
|
||||||
|
INVOKESPECIAL (test/Foo$Creator, <init>, ()V)
|
||||||
|
PUTSTATIC (CREATOR, Ltest/Foo$Creator;)
|
||||||
|
RETURN
|
||||||
|
}
|
||||||
|
|
||||||
|
public void <init>(android.os.Parcelable p0)
|
||||||
|
|
||||||
|
public final int describeContents()
|
||||||
|
|
||||||
|
public final android.os.Parcelable getParcelable()
|
||||||
|
|
||||||
|
public final void writeToParcel(android.os.Parcel p0, int p1) {
|
||||||
|
LABEL (L0)
|
||||||
|
ALOAD (1)
|
||||||
|
LDC (parcel)
|
||||||
|
INVOKESTATIC (kotlin/jvm/internal/Intrinsics, checkParameterIsNotNull, (Ljava/lang/Object;Ljava/lang/String;)V)
|
||||||
|
ALOAD (1)
|
||||||
|
ALOAD (0)
|
||||||
|
GETFIELD (parcelable, Landroid/os/Parcelable;)
|
||||||
|
LDC (0)
|
||||||
|
INVOKEVIRTUAL (android/os/Parcel, writeParcelable, (Landroid/os/Parcelable;I)V)
|
||||||
|
RETURN
|
||||||
|
LABEL (L1)
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -84,6 +84,12 @@ public class ParcelBytecodeListingTestGenerated extends AbstractParcelBytecodeLi
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("parcelable.kt")
|
||||||
|
public void testParcelable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/parcelable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("serializable.kt")
|
@TestMetadata("serializable.kt")
|
||||||
public void testSerializable() throws Exception {
|
public void testSerializable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/serializable.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("plugins/android-extensions/android-extensions-compiler/testData/parcel/codegen/serializable.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user