Collectives™ on Stack Overflow
Find centralized, trusted content and collaborate around the technologies you use most.
Learn more about Collectives
Teams
Q&A for work
Connect and share knowledge within a single location that is structured and easy to search.
Learn more about Teams
This is the config setting in question:
-keep @interface *
This setting is referenced in this post:
https://stackoverflow.com/a/17437740/367544
And here in the Proguard manual:
https://www.guardsquare.com/en/proguard/manual/troubleshooting#notkept
But the manual (or the post) doesn't explain how or why this config setting works. I would think that this config value would keep any annotations that were
defined
in your application. I emphasize the word
defined
here because I want to compare it to where an annotation is
used
. So if I defined an annotation in my code like
public @interface MyAnnotation {}
then I would expect this config setting to preserve it. However, if I were to use my annotation in another class like
public class MyClass { @MyAnnotation public void run(){} }
then I would
not
expect this config setting to preserve it there. I would think that to preserve the annotation where it's used, you would need a setting like
-keep class * { @interface <methods>; }
. However, my understanding is clearly wrong, because the
-keep @interface *
config setting
does
preserve the annotations where they're
used
.
Can anyone explain why the
-keep @interface *
config setting affects annotations where they're used inside other classes? Additionally, the Proguard manual never explains how to use
@interface
keyword at all. Is that like a wildcard for any annotation? Or does it refer to the definition of the annotation like in my example
public @interface MyAnnotation {}
? Or is it something else entirely?
When every interface is compiled, even with proguard, it should create a valid class file that can be used in the java virtual machine.
Java has specific naming rules for connecting interfaces and classes in packages with the files.
So for example even if interface
VeryImportantInterface
of package
com.mycompany.mypackage
is obfuscated and as a result you get:
interface
a
in package
b.c.d
java expects to find interface
a
in package
b.c.d
in a file named
a.class
Similar rules apply for inner classes and interfaces.
So if you do obfuscate the definition of a class or interface, it will have to be mentioned everywhere with its obfuscated name.Otherwise if for example class
MyClass.class
is obfuscated to
a.class
and another class, e.g.
MyClassReference
still references this class as
MyClass
then a
ClassNotFoundException
will be thrown when
MyClassReference
attempts to use
MyClass
for the first time.
Regarding
-keep @interface *
As specified in
ProGuard RefCard
'keep' prevents classes and class members from being removed or renamed.
ProGuard RefCard
also mentions that wildcard
*
can be used
*
can be used for any number of characters (but not the package separator)
the class name
*
refers to any class, irrespective of its package.
*
matches any field or method
So
-keep @interface *
according to the definitions above applies to
public @interface MyAnnotation {}
since its name match the wildcard
*
. Since according to the definition
MyAnnotation
is not to be removed, it is not removed from anywhere.
On the contrary
-keep class * { @interface <methods>; }
is more specific and would keep only the usages of the annotation.
Another thing to consider is that
keep
is followed by a
Class specification
. And based on the
Class specification
The @ specifications can be used to restrict classes and class members to the ones that are annotated with the specified annotation types. An annotationtype is specified just like a classname.
During the shrinking process pro guard will delete all the methods and members that are directly or indirectly used plus the ones specified by
-keep
. However it does not explicitly mention what it does with annotations.
Pro-Guard mentions regarding shrinking the following:
By default, shrinking is applied; all classes and class members are removed, except for the ones listed by the various -keep options, and the ones on which they depend, directly or indirectly.
Shrinking Options
So one case could be that pro-guard somehow detects that the annotation is used and prevents it from beeing removed during shrinking.
Another case would be that the annotations are considered metadatum of the methods and not beeing considered members.
It is really not obvious or well documented in proguard documentation.
You can use
-whyareyoukeeping @interface *
and
-verbose
to get a feedback from Prog-Guard on why it is keeping the related interfaces.
Update:
Since the result of the above configuration directives was:
... is kept by a directive in the configuration.
, it can only be concluded that the
-keep @interface *
actually . Hence it is does not provide any additional clarification. Without any specific explanation on the Pro-Guard documentation I think the following 2 possible explanations are possible:
1. The proguard shrinking step considers that the annotation is used in some part of the code, thus needed and is not reduced.
2. The class_specification
@interface *
matches both annotated methods and annotation declarations.
–
–
–
–
–
Thanks for contributing an answer to Stack Overflow!
-
Please be sure to
answer the question
. Provide details and share your research!
But
avoid
…
-
Asking for help, clarification, or responding to other answers.
-
Making statements based on opinion; back them up with references or personal experience.
To learn more, see our
tips on writing great answers
.