Unknown class specified for dataClass - ProGuard - java

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.

Related

Proguard not keeping class although it says so

I'm trying to keep proguard from renaming/optimizing classes which have a certain annotaion. There are quite a few examples out there and it should be straight forward but proguard isn't behaving as I would expect it to be.
Issue
Proguard v6.2.2 obfuscates classes annotated with #KeepClass although -whyareyoukeeping shows test.KeepMe is kept by a directive in the configuration.
I can reproduce the issue with a simple 3 file project.
Proguard config:
-optimizations !code/simplification/cast,!field/*,!class/merging/*
-optimizationpasses 3
-allowaccessmodification
-adaptresourcefilecontents **.properties,META-INF/MANIFEST.MF
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
-keep public class test.Entry {
public static void main(java.lang.String[]);
}
-keep #proguard.annotation.KeepClass public class * {
*;
}
-whyareyoukeeping class test.KeepMe
Class which should be kept:
import proguard.annotation.KeepClass;
#KeepClass
public class KeepMe
{
}
Proguard log:
Explaining why classes and class members are being kept...
Printing usage to [D:\Development\Projects\ProguardTest\build\usage.txt]...
test.KeepMe
is kept by a directive in the configuration.
Removing unused program classes and class elements...
Original number of program classes: 3
Final number of program classes: 2
And finally the files in the processed jar file:
- test
|- Entry.class
|- a.class (Obfuscated KeepMe class)
If however I explicitly list the class in the proguard configuration using
-keep class test.KeepMe{*;}
proguard reports the same log output but the class is untouched (as expected)
Am I missing something or is this a bug in proguard?
As it turns out the issue was actually related to a bug in proguard. After trying the latest beta it's working as expected.

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!

NoClassDefFoundError with a Custom Java Component in WCC

I'm attempting to a create a Custom Java component for oracle-ucm.
It installs currectly however when I run the code I get:
System code execution error. Unable to create service. java.lang.NoClassDefFoundError: com/lowes/content/edam/massMetaDataUpdate/service/ServiceApplication.
component.hda file looks like so:
<?hda version="11.1.1.8.0PSU-2015-01-08 07:49:21Z-r123144" jcharset="UTF8" encoding="utf-8"?>
#Properties LocalData
ComponentName=LowesMassMetadataUpdater
blDateFormat=M/d{/yy}{ h:mm[:ss]{ a}}!mAM,PM!tAmerica/New_York
classpath=$COMPONENT_DIR/classes
hasPreferenceData=0
libpath=$COMPONENT_DIR/libs
preventAdditionalComponentDowngrade=0
version=2016_06_08(build 1)
#end
For reference the beginning of my service class looks like so:
package com.lowes.content.edam.massMetaDataUpdate.service;
import intradoc.server.Service;
public class MMUService extends Service
{ //this is the line that is throwing the error.
private ServiceApplication app = new ServiceApplication();
/** Default Constructor - Does Nothing */
public MMUService() { }
//rest of class omitted for brevity
}
My component is configured start in the MMUService class which is in the same package as the class that cannot be found. Both class files are directly in the same folder. So why can it find the initial service class, but not a contained helper class from the same package?
Advanced Build Settings from Component Wizard
All Blank except for:
Custom Class Path: $COMPONENT_DIR/classes
Custom Library Path: $COMPONENT_DIR/libs
For starters, I would use a ServiceHandler instead of a Service.
Make sure you have an installID under Build > Advanced settings.
Some additional reading on building custom components can be found here:
1
2
I was able to figure out the problem. Before the Application displayed the NoClassDefFoundError it was displaying a Logging error. However, on Subsequent page Loads that error would disappear.
Turns out the logging error:
System code execution error. Unable to create service. Exception type is 'java.lang.ExceptionInInitializerError'.
Runtime error: org.apache.commons.logging.LogConfigurationException:
org.apache.commons.logging.LogConfigurationException:
org.apache.commons.logging.LogConfigurationException:
Class org.apache.commons.logging.impl.Jdk14Logger does not implement Log Runtime error:
org.apache.commons.logging.LogConfigurationException:
org.apache.commons.logging.LogConfigurationException:
Class org.apache.commons.logging.impl.Jdk14Logger does not implement Log Runtime error:
org.apache.commons.logging.LogConfigurationException:
Class org.apache.commons.logging.impl.Jdk14Logger does not implement Log
was the real cause of my issue. And digging into it reveals that the Classloader in WCC is loading a differerent Version of Apache Commons Logging than the application expects.
The fix was to create a Wrapper class of SystemUtils to implement Log and then set the system property org.apache.commons.logging.Log so that when classes call LogFactory.getLog(classname.class); They will get My WCC Logger class and sidestep the whole logging error issue.

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.

Android Proguard Javascript Interface Fail

I use in my project a piece of code as described here
http://lexandera.com/2009/01/extracting-html-from-a-webview/
I create the .apk file, install it on my device and it correctly works. If I try to use the obfuscation with proguard the project fails, the method showHTML(String html) of MyJavaScriptInterface is not reached.
My proguard configuration regarding that
-keep public class com.mypackage.MyClass.MyJavaScriptInterface
-keep public class * implements com.mypackage.MyClass.MyJavaScriptInterface
-keepclassmembers class * implements com.mypackage.MyClass.MyJavaScriptInterface {
<methods>;
}
according to this this answer Android proguard Javascript Interface problem.
SOLVED.
As Eric suggested, I changed the Proguard configuration file like this:
-keep public class com.mypackage.MyClass$MyJavaScriptInterface
-keep public class * implements com.mypackage.MyClass$MyJavaScriptInterface
-keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface {
<methods>;
}
Now my project works perfectly.
For API 17+ you also need to preserve the #JavascriptInterface annotations:
-keepattributes JavascriptInterface
http://developer.android.com/reference/android/webkit/JavascriptInterface.html
If MyJavaScriptInterface is an inner class of MyClass, ProGuard expects a fully qualified name com.mypackage.MyClass$MyJavaScriptInterface. The naming convention with $ is used in the compiled class files on which ProGuard operates. Note that ProGuard mentions class names in the configuration that it can't find in the input jar, suggesting that these names may have been misspelled.
-keepclassmembers class com.mypackage.MyClass$JavaScriptInterface {
public *;
}
Use only this. It works for me.
Those Who are laze to provide the entire package path.
-keepclassmembers class **.*$PaymentJavaScriptInterface{
public *;
}
As suggested by edit in question,
out of those suggestions,
only using
-keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface {
public *;
}
with Important -
For API 17+ to preserve #JavascriptInterface annotations:
-keepattributes JavascriptInterface
(Which was stopping my app to work on Marshmallow)

Categories

Resources