MalformedParameterizedTypeException when using proguard - java

I'm using proguard to shrink a shaded jar for use as a command line tool. The shaded jar works fine but I'm getting an exception when running the jar created by proguard. The app uses Guice injection and I added configuration that I found on SO, mostly in this answer.
This is the Exception:
Exception in thread "main" java.lang.reflect.MalformedParameterizedTypeException
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.validateConstructorArguments(ParameterizedTypeImpl.java:60)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:53)
at sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl.make(ParameterizedTypeImpl.java:95)
at sun.reflect.generics.factory.CoreReflectionFactory.makeParameterizedType(CoreReflectionFactory.java:105)
at sun.reflect.generics.visitor.Reifier.visitClassTypeSignature(Reifier.java:140)
at sun.reflect.generics.tree.ClassTypeSignature.accept(ClassTypeSignature.java:49)
at sun.reflect.generics.repository.ClassRepository.getSuperclass(ClassRepository.java:84)
at java.lang.Class.getGenericSuperclass(Class.java:696)
at com.google.inject.internal.MoreTypes.getGenericSupertype(MoreTypes.java:273)
at com.google.inject.TypeLiteral.getSupertype(TypeLiteral.java:257)
at com.google.inject.spi.InjectionPoint.hierarchyFor(InjectionPoint.java:755)
at com.google.inject.spi.InjectionPoint.getInjectionPoints(InjectionPoint.java:635)
at com.google.inject.spi.InjectionPoint.forInstanceMethodsAndFields(InjectionPoint.java:356)
at com.google.inject.internal.ConstructorBindingImpl.getInternalDependencies(ConstructorBindingImpl.java:151)
at com.google.inject.internal.InjectorImpl.getInternalDependencies(InjectorImpl.java:585)
at com.google.inject.internal.InjectorImpl.cleanup(InjectorImpl.java:543)
at com.google.inject.internal.InjectorImpl.initializeJitBinding(InjectorImpl.java:529)
at com.google.inject.internal.InjectorImpl.createJustInTimeBinding(InjectorImpl.java:847)
at com.google.inject.internal.InjectorImpl.createJustInTimeBindingRecursive(InjectorImpl.java:772)
at com.google.inject.internal.InjectorImpl.getJustInTimeBinding(InjectorImpl.java:256)
at com.google.inject.internal.InjectorImpl.getBindingOrThrow(InjectorImpl.java:205)
at com.google.inject.internal.InjectorImpl.getInternalFactory(InjectorImpl.java:853)
at com.google.inject.internal.FactoryProxy.notify(FactoryProxy.java:46)
at com.google.inject.internal.ProcessedBindingData.runCreationListeners(ProcessedBindingData.java:50)
at com.google.inject.internal.InternalInjectorCreator.initializeStatically(InternalInjectorCreator.java:133)
at com.google.inject.internal.InternalInjectorCreator.build(InternalInjectorCreator.java:106)
at com.google.inject.Guice.createInjector(Guice.java:95)
at com.google.inject.Guice.createInjector(Guice.java:72)
at com.google.inject.Guice.createInjector(Guice.java:62)
at com.acme.ui.cli.Main.main(Main.java:44)
And this the configuration that's producing it:
-injars acme-cli-0.2.1-SNAPSHOT.jar
-outjars target/acme-cli-0.2.1-SNAPSHOT.jar
-libraryjars /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre/lib/jce.jar
-libraryjars /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre/lib/jsse.jar
-libraryjars /Library/Java/JavaVirtualMachines/jdk1.7.0_25.jdk/Contents/Home/jre/lib/rt.jar
-dontobfuscate
-dontpreverify
-dontoptimize
-printmapping mapping.map
-ignorewarnings
-keepattributes *Annotation*,Signature
# Keep - Applications. Keep all application classes, along with their 'main' methods.
-keep public class com.acme.ui.cli.Main {
public static void main(java.lang.String[]);
}
# Keep Guice-related classes
-keep public class javax.inject.**
-keep class com.google.inject**
-keep class * extends com.google.inject.AbstractModule
# keeps all fields and Constructors annotated with #Inject and #AssistedInject
-keepclasseswithmembers class * {
#com.google.inject.Inject <fields>;
#com.google.inject.Inject <init>(...);
}
-keepclasseswithmembers class * {
#com.google.inject.assistedinject.AssistedInject <fields>;
#com.google.inject.assistedinject.AssistedInject <init>(...);
}
When I add this the problem goes away:
-keep class * {
<init>(...);
}
But it keeps many more classes and doubles the size of the jar. I'm using proguard 4.10 and tried 4.9 too. These are some of the option I've experimented with that seemed most relevant:
-keepattributes *
-keepparameternames
-keep class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl {
<init>(...);
}
Since it's seems related to Guice and keeping all constructors solves the problem, I've also experimented with the various ways you can configure the keep options without results. But I must say that I don't understand them fully.
I'm not sure if it's related to the problem, but what looks odd is that the only constructor in the class ParameterizedTypeImpl has a signature like this: private ParameterizedTypeImpl(java.lang.Class<?> aClass, java.lang.reflect.Type[] types, java.lang.reflect.Type type), but the signature in the stacktrace looks like it's accepting ParameterizedTypeImpl itself: ParameterizedTypeImpl.<init>(ParameterizedTypeImpl.java:53).
Now I'm stuck; Any suggestions that could help me further are very appreciated.

This is a known bug that was fixed in Proguard 5.0. See https://sourceforge.net/p/proguard/bugs/518/

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.

Jackson library post-obfuscation using Proguard

After a while trying some solutions here I'm still facing the problem of getting NullPointerException, apparently when using Jackson library, after trying to shrink my jar file using Proguard.
This is what I had defined to my Proguard config file:
-injars <my_raw_filejar>.jar
-outjars <shrunk_filejar>.jar
-libraryjars <JAVA_HOME>/lib/rt.jar
-keep public class packagename.MainClass{
public static void main(java.lang.String[]);
}
-keepnames class org.codehaus.jackson.** { *; }
-keepattributes *Annotation*
-keepattributes EnclosingMethod
-keepattributes Signature
-dontobfuscate
-optimizations !code/allocation/variable
-dontoptimize
-dontwarn
-ignorewarnings
But I'm getting the error below, once I run my generated shrunk jar:
Exception in thread "main" java.lang.ExceptionInInitializerError
at com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:535)
at com.fasterxml.jackson.databind.ObjectMapper.<init>(ObjectMapper.java:452)
at org.apache.beam.sdk.options.PipelineOptionsFactory.<clinit>(PipelineOptionsFactory.java:450)
at skry.tech.terbium.pipelines.TerbiumFeedBigTablePipeline.main(TerbiumFeedBigTablePipeline.java:30)
Caused by: java.lang.NullPointerException
at com.fasterxml.jackson.databind.cfg.MapperConfig.collectFeatureDefaults(MapperConfig.java:99)
at com.fasterxml.jackson.databind.cfg.MapperConfigBase.<clinit>(MapperConfigBase.java:31)
... 4 more
Is there any clue of what is happening and how to solve this error?
I had the same problem here.
Since the issue seemed to be based on an Enum being null. I added the following code to my proguard.conf
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}

Getting "Note: duplicate definition of library class" Proguard

Below is the application.pro which is the configuration to obfuscate the spring related standalone application:
# This ProGuard configuration file illustrates how to process applications.
# Usage:
# java -jar proguard.jar #applications.pro
#
# Specify the input jars, output jars, and library jars.
-injars xyz.jar
-outjars xyz_out.jar
-libraryjars C:\Program Files\Java\jdk1.8.0_20\jre\lib\rt.jar
-libraryjars <LocationOfJar>/xyz.jar
#-libraryjars servlet.jar
#-libraryjars jai_core.jar
#...
# Save the obfuscation mapping to a file, so you can de-obfuscate any stack
# traces later on. Keep a fixed source file attribute and all line number
# tables to get line numbers in the stack traces.
# You can comment this out if you're not interested in stack traces.
-printmapping out.map
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
# Preserve all annotations.
-keepattributes *Annotation*
# You can print out the seeds that are matching the keep options below.
#-printseeds out.seeds
# Preserve all public applications.
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames,includedescriptorclasses class * {
native <methods>;
}
# Preserve the special static methods that are required in all enumeration
# classes.
-keepclassmembers,allowoptimization enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
# You can comment this out if your application doesn't use serialization.
# If your code contains serializable classes that have to be backward
# compatible, please refer to the manual.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Your application may contain more items that need to be preserved;
# typically classes that are dynamically created using Class.forName:
# -keep public class mypackage.MyClass
# -keep public interface mypackage.MyInterface
# -keep public class * implements mypackage.MyInterface
#Warnings to be removed. Otherwise maven plugin stops, but not dangerous
-keep public class com.sun.xml.internal.**
-keep public class com.sun.istack.internal.**
-keep public class org.codehaus.jackson.**
-keep public class org.springframework.**
-keep public class java.awt.**
-keep public class javax.security.**
-keep public class java.beans.**
-keep public class javax.xml.**
-keep public class java.util.**
-keep public class org.w3c.dom.**
-keep public class com.google.common.**
-keep public class org.apache.**
-keep public class org.xnio.**
-keep public class javax.xml.**
-keep public class java.time.**
-keep public class com.sun.corba.**
-keep public class org.hibernate.**
-keep public class antlr.**
-dontwarn com.sun.xml.internal.**
-dontwarn com.sun.istack.internal.**
-dontwarn org.codehaus.jackson.**
-dontwarn org.springframework.**
-dontwarn java.awt.**
-dontwarn javax.security.**
-dontwarn java.beans.**
-dontwarn javax.xml.**
-dontwarn java.util.**
-dontwarn org.w3c.dom.**
-dontwarn com.google.common.**
-dontwarn org.apache.**
-dontwarn org.xnio.**
-dontwarn javax.xml.**
-dontwarn java.time.**
-dontwarn com.sun.corba.**
-dontwarn org.hibernate.**
-dontwarn antlr.**
-dontskipnonpubliclibraryclasses
When I run:
java -jar proguard.jar #applications.pro
I get this below error:
Note: duplicate definition of library class
And output is not generated as given in the application.pro:
Note: there were 166 classes trying to access generic signatures using reflection.
You should consider keeping the signature attributes
(using '-keepattributes Signature').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 21 classes trying to access enclosing classes using reflection.
You should consider keeping the inner classes attributes
(using '-keepattributes InnerClasses').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 5 classes trying to access enclosing methods using reflection.
You should consider keeping the enclosing method attributes
(using '-keepattributes InnerClasses,EnclosingMethod').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 563 library classes explicitly being kept.
You don't need to keep library classes; they are already left unchanged.
(http://proguard.sourceforge.net/manual/troubleshooting.html#libraryclass)
Note: there were 55 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Note: there were 4 class casts of dynamically created class instances.
You might consider explicitly keeping the mentioned classes and/or
their implementations (using '-keep').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclasscast)
Note: there were 292 accesses to class members by means of introspection.
You should consider explicitly keeping the mentioned class members
(using '-keep' or '-keepclassmembers').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclassmember)
Warning: there were 5329 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Warning: there were 117 instances of library classes depending on program classes.
You must avoid such dependencies, since the program classes will
be processed, while the library classes will remain unchanged.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dependency)
Warning: there were 42 unresolved references to program class members.
Your input classes appear to be inconsistent.
You may need to recompile the code.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
Error: Please correct the above warnings first.
How to resolve this issue?

ProGuard for Android and GSON

I'm setting up ProGuard for my Android project. My project also uses GSON.
I've researched ProGuard configurations for compatibility with GSON and Android and came across this example offered by google-gson https://code.google.com/p/google-gson/source/browse/trunk/examples/android-proguard-example/proguard.cfg.
ProGuard config copied below:
##---------------Begin: proguard configuration common for all Android apps ----------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-printmapping mapping.txt
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable
-repackageclasses ''
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
public static <fields>;
}
# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class * {
public protected *;
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
##---------------End: proguard configuration common for all Android apps ----------
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON #Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
##---------------End: proguard configuration for Gson ----------
Questions:
I see that this file has not been updated since 2011, is it still recommended for use? I ask because Android/GSON has changed quite a bit since then so I don't know how much of the above in unnecessary or incorrect.
If this is not recommended, is there a new recommended ProGuard configuration for GSON in Android?
I think most of those settings you have there are already included in the Android SDK by default.
So you can remove most of them, just leaving in the section devoted to GSON.
I am developing in Eclipse using Android SDK Tools 22.6.3 & whatever version of ProGuard ships with that.
Here's what I'm using for GSON 2.2.4 (as per their example):
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
# -keep class mypersonalclass.data.model.** { *; }
It looks exactly the same as what you have, except I don't need the line about the annotations.
You can see I've commented out some classes that I added myself. If you serialize/deserialize your own classes, you need to declare them here in place of the reference to mypersonalclass.data.model. This is really important, as you don't want ProGuard to obfuscate the field or class names that GSON uses for serialization.
I always leave those types of comments in there, so I know how to configure the next library or app.
The previous answer stopped working for me recently probably due to some changes in Android (R8 is used now instead of Proguard). The configuration I use now is as follows (source - GSON examples):
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON #Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in #JsonAdapter)
-keep class * implements com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
#com.google.gson.annotations.SerializedName <fields>;
}
##---------------End: proguard configuration for Gson ----------
I found out that classes whose fields are annotated by #SerializedName do not have to be explicitly listed unless they are inner classes.
In my case, I just used GSON for deserializing JSON to an Object. So it was enough to add the following line to proguard file.
-keep class your.data.object.modals.package.** { <fields>; }
In my case I added the above but still got an error until in my app level gradle I changed compile 'org.immutables:gson:2.4.6' to provided 'org.immutables:gson:2.4.6'. Maybe someone more enlightened can explain why but this solved my problem.
Using -keep is a bad practice and you should never do it .You almost never want to use -keep; if you do need a ProGuard rule, you usually want one of the more specific variants
-keepclassmembers - This protects only the members of the class from shrinking and obfuscation.
-keepnames - This allows shrinking for classes and members, but not obfuscation. That is, any unused code is going to get removed. But the code that is kept will keep its original names.
-keepclassmembernames - Unused classes are removed, the remaining classes are renamed, unused members of those classes are removed, but then the remaining members keep their original names.
For more information please read this
PS - this is what I did for Gson
-keepclassmembernames class rscom.pojo.** { <fields>; }

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