lundi 8 octobre 2018

Kotlin Reflection with Proguard - Incomplete hierarchy for class

I'm running into an issue at runtime when using Proguard with Kotlin reflection. Basically, when I am calling KClass.declaredMemberProperties, I get:

Incomplete hierarchy for class FieldBoundObject, unresolved classes [com.example.test.classes.DisposableObject]
kotlin.reflect.jvm.internal.components.RuntimeErrorReporter.reportIncompleteHierarchy

Here is the relevant stacktrace:

Caused by java.lang.IllegalStateException: Incomplete hierarchy for class FieldBoundObject, unresolved classes [com.example.test.classes.DisposableObject]
   at kotlin.reflect.jvm.internal.components.RuntimeErrorReporter.reportIncompleteHierarchy(RuntimeErrorReporter.kt:26)
   at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassTypeConstructor.computeSupertypes(DeserializedClassDescriptor.kt:181)
   at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:34)
   at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke(AbstractTypeConstructor.kt:22)
   at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:354)
   at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:410)
   at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor.getSupertypes(AbstractTypeConstructor.kt:23)
   at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope.getNonDeclaredFunctionNames(DeserializedClassDescriptor.kt:278)
   at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$functionNamesLazy$2.invoke(DeserializedMemberScope.kt:73)
   at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$functionNamesLazy$2.invoke(DeserializedMemberScope.kt:40)
   at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:354)
   at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:410)
   at kotlin.reflect.jvm.internal.impl.storage.StorageKt.getValue(storage.kt:42)
   at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope.getFunctionNamesLazy(DeserializedMemberScope.kt)
   at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope.getFunctionNames(DeserializedMemberScope.kt:84)
   at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaClassMemberScope.computeFunctionNames(LazyJavaClassMemberScope.kt:75)
   at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaClassMemberScope.computeFunctionNames(LazyJavaClassMemberScope.kt:65)
   at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaScope.computeNonDeclaredFunctions(LazyJavaScope.kt:342)
   at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaScope$allDescriptors$1.invoke(LazyJavaScope.kt:61)
   at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaScope$allDescriptors$1.invoke(LazyJavaScope.kt:55)
   at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:354)
   at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:410)
   at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaScope.getContributedDescriptors(LazyJavaScope.kt:323)
   at kotlin.reflect.jvm.internal.impl.resolve.scopes.ResolutionScope$DefaultImpls.getContributedDescriptors$default(ResolutionScope.kt:52)
   at kotlin.reflect.jvm.internal.KDeclarationContainerImpl.getProperties(KDeclarationContainerImpl.kt:64)
   at kotlin.reflect.jvm.internal.KClassImpl$Data$declaredNonStaticMembers$2.invoke(KClassImpl.kt:151)
   at kotlin.reflect.jvm.internal.KClassImpl$Data$declaredNonStaticMembers$2.invoke(KClassImpl.kt:44)
   at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke(ReflectProperties.java:92)
   at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue(ReflectProperties.java:31)
   at kotlin.reflect.jvm.internal.KClassImpl$Data.getDeclaredNonStaticMembers(KClassImpl.kt)
   at kotlin.reflect.full.KClasses.getDeclaredMemberProperties(KClasses.kt:163)
   at com.example.test.classes.FieldBinder.bindFields(FieldBinder.kt:51)
   at com.example.test.classes.FieldBinder.(FieldBinder.kt:28)
   at com.example.test.classes.FieldBoundObject.(FieldBoundObject.kt:15)
   at com.example.test.models.TestClass.(TestClass.java:52)
   at com.example.test.models.TestClass.(TestClass.java:58)
   at com.example.test.ReactLandingActivity.startClass(ReactLandingActivity.java:93)

Here is the relevant call in Fieldbinder.kt:

class FieldBinder(receiver: Any) {

    private fun bindFields(receiver: Any, classToCheck: Class<*>) {
        for (property in classToCheck.kotlin.declaredMemberProperties) {
            //...
        }
    }

    // ...
}

Here is the signature for the "missing" class DisposableObject

package com.example.test.classes

open class DisposableObject : ScopeProvider, Dispose {

    //...
}

I think it has something to do with name obfuscation. I've tried using @Keep on the actual class itself, as well as using -keep class on the class itself in my Proguard file. However, what DOES solve the problem is keeping names in Proguard:

-dontobfuscate

or

-keepnames class com.example.test.classes.DisposableObject

Is there an issue with name obfuscation and Kotlin reflection? I'm not having the same issues with Java reflection. Or is there a better way to solve this problem? Thanks!





Aucun commentaire:

Enregistrer un commentaire