-
Notifications
You must be signed in to change notification settings - Fork 4.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve default ProGuard / R8 rules and Troubleshooting Guide #2401
Comments
hello, |
@keehl789, is this a general question about R8, not specifically related to Gson? If so, it might be better to ask this somewhere else where you probably get more and better answers, for example on Stack Overflow or on the R8 mailing list. But it would be good then to describe your use case a bit more in detail, so that others can give you more specific answers. |
@Marcono1234 First of all thanks a lot for introducing consumer proguard rules! I have added the rules to one of my projects. Everything seemed to work fine, but I ran into one issue.
Upon minification, R8 removes the
This, in turn, causes a runtime exception:
As a workaround, I'm currently have to explicitly keep the class:
I'm wondering if more general rule can be used in such cases. I'm using gson's 2.10.1 release with those proguard rules. I have uploaded a sample project for demonstration. |
@alipov, I was going to suggest that you could try omitting the As mentioned in #2420 (comment) and in the comment in @sgjesse since you are a lot more familiar with this, do you know if there is a way to define in the |
@alipov, would you mind creating a separate GitHub issue for your problem? That would probably make it easier to track and also easier to find for other users affected by it. The points which were originally mentioned in the description of this issue here were addressed, so it would probably be confusing to reopen or repurpose it for your problem. |
Problem solved by the feature
Improve the default ProGuard / R8 rules in
META-INF/proguard/gson.pro
added by #2397, and the Troubleshooting Guide.Feature description
I was testing the new default rules with an Android app and Kotlin classes, and there might be the following areas to improve.
Troubleshooting Guide:
JsonIOException
: 'Abstract classes can't be instantiated!' (R8)The Troubleshooting Guide currently suggests the following:
This means only the no-args constructor is kept, but not any other constructors. However, especially for Kotlin I assume it is common that classes don't have a no-args constructor because you might declare properties and the primary constructor at once, e.g.
class MyClass(val s: String)
(see Kotlin documentation). Not sure though if using that is a good idea in combination with Gson because it then requires JDK Unsafe to create instances, but that is a different topic.So there are two questions:
<init>(...);
(all constructors), so that the users don't experience issues with R8 anymore (but implicitly depend on JDK Unsafe; usingGsonBuilder.disableJdkUnsafe()
would cause Gson to fail with a different exception)-keep
instead of-keepclassmembers
. In case the<init>
rule for the class properly matches a constructor it might not matter. But in case<init>();
is used, but a no-args constructor does not exist, then-keep
seems to at least have the side-effect that R8 does not make the class abstract (and then using JDK Unsafe an instance can be created).Troubleshooting Guide: Recommend
@Keep
for AndroidInstead of configuring ProGuard / R8 rules, it might be easier for Android developers to use
@Keep
on the corresponding class or constructor, see https://developer.android.com/studio/write/annotations#keepPreventing R8 from making classes abstract / removing no-args constructor
It would be good if we could adjust the default rules to avoid the "Abstract classes can't be instantiated!" exception (for most cases) in the first place.
There is probably no general way to detect if a class might be used with Gson, but the most reliable variant might be to keep the constructor if any of the Gson annotations is used by a class.
This can probably be achieved with an
-if
rule (see also answers to this Stack Overflow question). For example:(duplicated for all Gson annotations)
But it looks like this is not enough, maybe because there is no
-keep
(or-keepclasseswithmembers
) rule for the class in the first place so-if
somehow has no effect? You additionally need the following (duplicated for all Gson annotations probably):Only then the class is not made abstract and the constructor is properly kept...
(As side note: Having only the
-keepclasseswithmembers ... { @SerializedName }
above, but not the-if ... -keep
seems to prevent R8 from making the class abstract, but still removes all constructors, so users would be dependent on JDK Unsafe then.)Or similar to #2379 (comment) maybe the following would work as well:
There is however probably no need for the
-if
rule shown in the original comment, unless that has some special effect, see #2397 (comment).R8 makes class abstract but still keeps constructors
It also looks like the Android app build creates (for some reason) additional constructors / keeps constructors even when the class is made abstract. Due to this, the Troubleshooting Guide URLs are unfortunately not included in the exception messages (they are only added at the moment when there are no constructors).
Not really sure why these constructors exist in the first place and are kept even when the class is made abstract. In the R8 integration test of Gson this behavior was not seen.
Maybe we should remove the
getDeclaredConstructors().length == 0
check if the class is abstract and always refer to the Troubleshooting Guide. The guide would have to be adjusted then though to also properly cover the case where the class was indeed abstract in the source code.Any additional feedback is highly appreciated!
The text was updated successfully, but these errors were encountered: