Tell Proguard to keep annotation on methods - java

I'm using my own annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface Loggable { }
and obfuscate using Proguard. I use the -keepattributes *Annotation*
in the Proguard configuration to keep the annotations.
At runtime, when I retrieve the annotation from an annotated class using someClass.getAnnotation(Loggable.class) everything works - I retrieve a non-null instance of my annotation.
However, when I want to apply the same to an annotated method of some class, I retrieve null from someMethod.getAnnotation(Loggable.class).
Is Proguard removing the annotations from methods? How do I tell it not to do so?
I'm using Proguard 4.7.

You need to use keepclassmembers parameter:
-keepclassmembers class ** {
#com.yourpackage.Loggable public *;
}

Related

Converting package level Java annotation to Kotlin

Is it possible to convert a package level Java annotation to Kotlin?
Java annotation (MyAnnotation.java):
package com.myexample.annotation;
#Retention(RUNTIME) #Target(PACKAGE)
public #interface MyAnnotation {
}
Application of annotation (package-info.java)
#MyAnnotation
package com.myexample
The following does not seem to work (although it does compile) - my annotation processor does not detected any of the classes in the package com.myexample:
MyAnnotation.kt
package com.myexample.annotation
#Target(allowedTargets = [AnnotationTarget.CLASS, AnnotationTarget.FILE])
#Retention(AnnotationRetention.SOURCE)
annotation class MyAnnotation
package-info.kt
#file:MyAnnotation
package com.myexample
import com.myexample.annotation.MyAnnotation
No, it's not currently possible. You can simply leave package-info.java as a Java file.

How to stop Proguard shrink from removing annotation parameters even though it keeps the annotation itself?

I'm only using Proguard (version 5.2.1) to shrink, not to obfuscate or optimize. Here's my config:
-forceprocessing
-dontobfuscate
-dontoptimize
-dontwarn
-dontnote
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-libraryjars <java.home>/lib
-keep class ** extends **.MyRequestHandler
-keep #org.springframework.stereotype.Component class **
-keep #org.aspectj.lang.annotation.Aspect class **
-keep #interface *
I have a class which is an AspectJ aspect that looks like this:
#Aspect
public class MyAspect {
#Pointcut("execution(* com.amazonaws.services.dynamodb*.*AmazonDynamoDB.*(..))")
public void myPointCut() {
}
#Around(value = "myPointCut()")
public Object logExecution(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint);
return joinPoint.proceed();
}
}
When I feed my application through Proguard, and then decompile the resulting class file, this is what it looks like:
#Aspect
public class MyAspect {
#Pointcut("execution(* com.amazonaws.services.dynamodb*.*AmazonDynamoDB.*(..))")
public void myPointCut() {
}
#Around
public Object logExecution(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint);
return joinPoint.proceed();
}
}
Notice that the "value" parameter from the #Around annotation is missing! This is very weird behavior... I almost think it's a bug in Proguard. It's keeping the annotation itself, just not the parameter... though weirdly enough it is keeping the parameter from the #Pointcut annotation. Does anyone know how to fix this?
As a reminder, I'm only shrinking, and the -keepattributes config is only for obfuscation, so please no one respond that -keepattributes *Annotation* will fix it. I've tried it and it has no effect.
I found this similar question (annotations having no effect in proguard) which is where I got the -keep #interface * config. This setting is supposed to keep all annotations, which it seems to be doing, but for some reason it's not keeping all of the parameters. I tried many variations of this, such as:
-keep #interface **
-keep #interface* *
-keep #interface.On *
-keep #interface.* *
-keepclassmembers class ** { #org.aspectj.lang.annotation.Around ; }
-keepclassmembers class ** { #org.aspectj.lang.annotation.Around.On ; }
-keepclassmembers class ** { #org.aspectj.lang.annotation.Around.* ; }
Some of these approaches just cause Proguard to throw an error, and the ones that don't aren't having any effect. Please help!
The answer was posted on this ProGuard bug report: https://sourceforge.net/p/proguard/bugs/700/
You just need to change this config value:
-keep #interface *
To this:
-keep #interface * {*;}
This still seems like a bug in ProGuard because I'm clearly using those annotation parameters, and I'm telling ProGuard to keep the classes and the annotations, so it shouldn't be removing them... but this is the workaround.

How annotation internally works in java

I know how to create custom annotation. But i am unable to understand how does it work internally. If i take example of spring annontation.
#PropertySource(value = { "classpath:database.properties" }).
if we see internal details of #PropertySource annotation
#Target({ java.lang.annotation.ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Repeatable(PropertySources.class)
public #interface PropertySource {
public abstract String name();
public abstract String[] value();
public abstract boolean ignoreResourceNotFound();
}
We do not have provided any implementation here for loading property file.
Then How is it loading property file from classpath. Who is working behind the scene ?
Really simple: framework. That is. All 'custom' annotations processed by frameworks using reflection. Only small scope of annotations are processed by compiler, such as #Override, #SuppressWarnings, #Retention and so on

Is it possible to let ProGuard keep elements with RetentionPolicy.SOURCE?

I'm using the #VisibleForTesting annotation located in the Android Support Annotations library, and it looks like this:
#Retention(SOURCE)
public #interface VisibleForTesting {
}
As I understand it, ProGuard operates on the .class files and since this annotation isn't available at compile time due to its retention policy, all the annotated methods are stripped away. I'd like to run automated tests on my app and use the methods exposed for testing to verify that the ProGuard configuration doesn't break any use cases.
Is it possible to configure ProGuard to keep these elements somehow? So far I've tried:
-keep #android.support.annotation.VisibleForTesting class *
-keep class android.support.annotation.** {
#**.VisibleForTesting *;
}
-keep interface android.support.annotation.** {
#**.VisibleForTesting *;
}
And:
-keep interface android.support.annotation.VisibleForTesting
-keepclasseswithmembers class * {
#android.support.annotation.VisibleForTesting *;
}
-keepclassmembers class ** {
#android.support.annotation.VisibleForTesting *;
}
These two configurations do not work. If I annotate the methods with #Keep as well, and configure ProGuard to keep those methods, the methods are kept and the tests pass. However, by doing that I have to annotate all methods with two annotations.
Is it possible to hook into the annotation processor and override the retention policy for #VisibleForTesting? Or is that already too late in the build process?
Guava's #VisibleForTesting uses RetentionPolicy.CLASS, while Android Support Annotations Library uses RetentionPolicy.SOURCE. I'm considering posting a request to change the policy, but I suppose it's set to SOURCE for a reason, possibly due to performance and a very slightly increased file size?
Are there any options other than using two annotations (#VisibleForTesting and #Keep)?
Annotations with a RetentionPolicy == SOURCE are not present in .class files on which ProGuard is operating. Thus there is no way to use them in rules as they will never match.
Annotations with RetentionPolicy == CLASS should work fine. If needed, they can even be removed in release builds using ProGuard.

annotations having no effect in proguard

I'm having troubles getting proguard to keep things based on their annotations (under Android).
I have an annotation, com.example.Keep:
#Target({ ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR })
public #interface Keep {
}
I have a class, which is only ever constructed through reflection:
public class Bar extends Foo {
#com.example.Keep
Bar(String a, String b) { super(a, b); }
//...
}
It works as expected (class keeps its constructor albeit with an obfuscated class name) When my proguard config includes the following:
-keepattributes Signature,*Annotation*,SourceFile,LineNumberTable
-keepclassmembers class ** extends com.example.Bar {
<init>(...);
}
It drops the constructor if I try change that to:
-keepattributes Signature,*Annotation*,SourceFile,LineNumberTable
-keepclassmembers class ** extends com.example.Bar {
#com.example.Keep <init>(...);
}
I see the same behaviour with both my own annotations and proguard's annotation.jar annotations. I've copied and pasted the annotation name from Foo's import of Keep, so am confident it's not a typo or incorrect import.
Can anyone think of what I might be missing?
If your annotations are being processed as program code, you should explicitly preserve them:
-keep,allowobfuscation #interface *
The reason is somewhat technical: ProGuard may remove them in the shrinking step, so they are no longer effective in the optimization step and the obfuscation step.
Cfr. ProGuard manual > Troubleshooting > Classes or class members not being kept.

Categories

Resources