Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep classes containing specific members?

I want to keep only classes, which contain methods annotated with @Keep, and these methods. These methods (and owning classes) should be kept even if they are unused.

What I write in .pro-file is:

-keepclassmembers class * {
    @Keep *;
}

-keepclasseswithmembers class * {
    @Keep *;
}

But it shrinks out classes with @Keep methods if they are unused.

Then I try this:

-keep class * {
    @Keep *;
}

it just keeps all the classes.

So, what should I write in .pro-file?

Update 1: example Thanks for your answer. But I already use fully-qualified annotation names and include JARs with annotations, but it doesn't do what I want. So, I've prepared a sample.

I have 2 JARs:

example.jar/

  example/
    code/
      more/
        A.class

lib.jar/

  example/
    lib/
      Keep.class

A.java:

package example.code.more;

import example.lib.*;

public class A {
  @Keep
  void foo() {}
}

Keep.java:

package example.lib;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.CLASS)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
public @interface Keep {

}

Proguard config, example.pro:

-injars  example.jar
-injars  lib.jar
-outjars obfuscated.jar

-libraryjars <java.home>/lib/rt.jar

-printmapping rt.map

-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

-printseeds
-overloadaggressively
-dontoptimize
-keeppackagenames example.lib.**

-keepattributes *Annotation*

-keepclassmembers class * extends java.lang.Enum {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep class example.lib.* { *; }
-keep class * extends java.lang.annotation.Annotation { *; }


-keepclassmembers class * {
    @example.lib.Keep *;
}

-keepclasseswithmembers class * {
    @example.lib.Keep *;
}

See, package names are correct and all the JARs are included.

Resulting map-file:

example.lib.Keep -> example.lib.Keep:

So, A.class gets removed. What am I doing wrong?

like image 403
Andy Avatar asked Jul 01 '11 12:07

Andy


People also ask

How do you keep a particular class in ProGuard?

-keepclassmembernames. This is the most permissive keep directive; it lets ProGuard do almost all of its work. 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.

How can we control access to members in Java?

In Java, you can use access specifiers to protect both a class's variables and its methods when you declare them. The Java language supports four distinct access levels for member variables and methods: private, protected, public, and, if left unspecified, package.

Can a class have variable of its own type?

Because in Java, a variable of type abc doesn't contain an abc object. A variable of type abc contains a reference to an abc object. Your reasoning would be valid in say C++. But a class can have static object of self type.

Can a class contain an object of itself?

A class declaration can contain static object of self type, it can also have pointer to self type, but it cannot have a non-static object of self type. For example, following program works fine.


1 Answers

Like in examples/annotations/lib/annotations.pro in the ProGuard distribution, you should specify fully qualified names. Furthermore, the option -keepclasseswithmembers doesn't combine well with the "*" wildcard -- use the "<methods>" wildcard instead:

-keepclasseswithmembers class * {
  @proguard.annotation.Keep <methods>;
}

You also mustn't forget to read the jar that contains the annotation classes:

-libraryjars annotations.jar 
like image 200
Eric Lafortune Avatar answered Oct 04 '22 10:10

Eric Lafortune