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 the response, but I feel like you've only confirmed my question. First of all, as I mentioned, I'm only shrinking, not obfuscating. As you say, the -keep @interface * should really only apply to where annotations are defined like your example public @interface MyAnnotation {} -- but the whole point of my question is that this isn't what's actually happening. This -keep @interface * command is keeping annotations where they're used (please reread my original post for more context). I'm trying to understand why. Dasmowenator May 9, 2018 at 19:02 I will rephrase to make the answer more clear the point where this answer covers your question. Thanks for pointing out that you are shrinking in your comment. I just noticed the shrink tag in your question. I had only read the body, where this is not mentioned. Spyros K May 10, 2018 at 7:18 PS: You are right, the answer does not clearly answer your question, and the proguard documentation, really does not provide enough detail. Can you use -whyareyoukeeping @interface * , -whyareyoukeeping @* and -verbose to get a feedback from Prog-Guard on why it is keeping the related interfaces. You can add it to your question and we can try to see what is going. It is really very interesting. Spyros K May 10, 2018 at 8:12 The -whyareyoukeeping @* option doesn't work, it just throws an error. I tried running with the -whyareyoukeeping @interface * config and the result was: ... is kept by a directive in the configuration. Not very helpful unfortunately :/ Dasmowenator May 10, 2018 at 20:06 Thank you for trying it! Indeed it is not very helpful. Are there any specific references of this annotation ? For example using reflection to search for the annotation? Spyros K May 11, 2018 at 7:09

    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 .