Kotlin Reflection with Proguard - Incomplete hierarchy for class - java

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!

Related

Unknown class specified for dataClass - ProGuard

I need some help, i've activated the proguard for code obfuscation but when i launch the app, crash and logcat print this:
java.lang.RuntimeException: Unable to create application eu.reply.lea.mobile.core.showcase.ShowcaseApplication: java.lang.IllegalArgumentException: Unknown class specified for dataClass: eu.reply.lea.mobile.core.oldies.entity.User
...
Caused by: java.lang.IllegalArgumentException: Unknown class specified for dataClass: eu.reply.lea.mobile.core.oldies.entity.User
In the proguard file i added this lines but doesn't change nothing.
-keepclassmembernames class eu.reply.lea.mobile.core.oldies.entity.User {
public *;
}
-keepclassmembernames class eu.reply.lea.mobile.core.showcase.ShowcaseApplication {
public *;
}
Tried to add #keep and #keepnames annotations in user but nothing changed.
How can i solve this?
Thank you all!
The reason why these errors are showing up can have 2 causes:
This class has been removed because of shrinking
This class relies on reflection
I would suggest adding the following keeprule to your proguard configuration file:
-keep class eu.reply.lea.mobile.core.oldies.entity.User
A useful tool you can use to check what parts of your code will be affected when you define this keeprule can be found here.

Android Proguard - keep class and methods

I need to make sure the method
java.lang.String -> isEmpty()
Is present in the compiled code.
Will Proguard keep this method if it is referenced somewhere in my code? Or is it better to include
-keep class java.lang.String { *; }
Into Proguard configuration file?
I'm asking because to fix java.lang.ClassNotFoundException this code is used:
try {
Class.forName("android.os.AsyncTask");
}
catch(Throwable ignore) {}
Instead of adding this to Proguard:
-keep class android.os.AsyncTask { *; }
If you're referencing that method in your code, it should be kept by Proguard. From the documentation:
The ProGuard tool shrinks, optimizes, and obfuscates your code by
removing unused code and renaming classes, fields, and methods with
semantically obscure names
So if the code is being used, there's no reason why Proguard would remove it.

how to access internal properties from java test code

I've got some class with property marked as internal.
Then I try to set that property from test code which is in java.
How can I access those properties? test code and class code are in the same package.
example:
class MainActivity : AppCompatActivity() {
interal var someProperty = "test"
}
test code:
#Test
public void firstStartTest() {
val activity = MainActivity()
activity.setSomeProperty("something") //does not compile
}
Android Studio is suggesting activity.setSomeProperty$production_sources_for_module_app();
but this also does not compile.
Both classes (MainActivity and test class) must be in one module. This is a module definition:
More specifically, a module is a set of Kotlin files compiled together:
an IntelliJ IDEA module;
a Maven or Gradle project;
a set of files
compiled with one invocation of the Ant task.
https://kotlinlang.org/docs/reference/visibility-modifiers.html
It means, check your project structure.
add #JvmField annotation.
It treats variable as java protected
There are two ways of doing this:
Make the property protected. Note on how Java & Kotlin treat protected differently. In Java it's possible that other classes in the same package access protected members. Thus your test class (in Java) can access it.
Access the property via its ugly name. It should be sort of like activity.setSomeProperty$production_.... Make use the autocomplete. From the documentation:
Members of internal classes go through name mangling, to make it
harder to accidentally use them from Java and to allow overloading for
members with the same signature that don't see each other according to
Kotlin rules;

Eclipse generates Java class filename conflict for inner classes

I have two top-level classes; each has an inner class with the same name:
**A.java**
public class A
{
}
class TestCase
{
}
**B.java**
public class B
{
}
class TestCase
{
}
My expectation is that I will wind up with four class files, including A$TestCase.class and B$TestCase.class, which is what I get when I compile from the command line. Eclipse, however, just creates TestCase.class, and declares that "The type TestCase is already defined" when I try to compile B.java.
Is there an Eclipse option that I can set to produce (what I believe is the standard) A$TestCase.class and B$TestCase.class?
Thanks.
By the way, I am using Luna:
Version: Luna Release (4.4.0)
Build id: 20140612-0600
Both versions of TestCase are top level classses. You need to create inner classes
public class A {
class TestCase {
}
}
It doesn't do this for me. It creates an A$TestCase.class and a B$TestCase.class, as it should.
But this is only when they're actually inner classes... in your case, they're not really inner classes at all.
TestCase is not an inner class as you might think, and this is why formatting code is essential when coding. check this

NoClassDefFoundError

I have an issue where NoClasDefFoundError is being thrown. It puzzles me since I am using interfaces, and no class definition should be available. I have read through some posts which point to Classpath, but I don't believe that to be the issue here (although I may be wrong). I am using NetBeans 6.9.1 IDE.
I have created a sample setup to reproduce the issue. Four projects: Interfaces, Objects, Locator and Consumer. Below you will find the implementations.
At runtime consumer coplains about missing SomeObject implementation, which it should not be aware of since it is accepting interface.
Exception in thread "main"
java.lang.NoClassDefFoundError:
objects/SomeObject
What am I missing?
package interfaces;
public interface ISomeInterface { }
package objects;
import interfaces.ISomeInterface;
public class SomeObject implements ISomeInterface{ }
package locator;
import interfaces.ISomeInterface;
import objects.SomeObject;
public class Locator { public static ISomeInterface LocateImplementation() { return new SomeObject(); }}
package consumer;
import interfaces.ISomeInterface;
import locator.Locator;
public class Main { public static void main(String[] args) { ISomeInterface object = Locator.LocateImplementation(); }}
You can get a NoClassDefFoundError exception with interfaces just as you can with classes. Consider the "Class" in the name of the exception to be the .class file that is generated from compiling a class or interface, not a Java class.
This is saying that the class/interface objects.SomeObject isn't visible on your classpath. Check the location of that .class file and ensure that it's on your classpath - if you're positive it's there, give us some screen shots or something that might help to debug the problem.
Think of NoClassDefFoundError as a runtime linkage problem. JRE loaded one class (or an interface) and it references another class (or an interface), but that referenced class isn't found.
The only way this can happen if you have packaging/classpath issues such that your runtime environment doesn't reflect how things are at build time.
If you are launching this from IDE, make sure that you aren't ignoring any errors and launching anyway. Some classes will not be generated that way.
Usually I run into these problems not when a class is missing, but when there is an error in the static initializers.
Try running your code in a debugger, and set the exception breakpoint to break when any exception is thrown, whether caught or not. I bet you have an uncaught exception in the static initializer for some reason.
In the locateImplementation() method you are returning "new SomeObject()",
JVM needs to have its definition when called. I think it is missing.
You should check if your SomeObject class is in class path because -
Well the JVM will be running the below code -
ISomeInterface object = Locator.LocateImplementation();
and when it does that it will call Locator.LocateImplementation(). This code internally tries to instantiate your SomeObject class which it does not find in the classpath.
So your below understanding
It puzzles me since I am using
interfaces, and no class definition
should be available.
Is not really valid.
Any Interface must be declared inside class
public class Calbacks {
public interface IBaseFragmentInterface {
void NotifyMainActivity();
}
}

Categories

Resources