I’m trying to figure out how annotations with “AnnotationRetention.BINARY” retention are represented in bytecode.
Annotations with “AnnotationRetention.RUNTIME” retention are explicitly added to bytecode.
Annotations with “AnnotationRetention.BINARY” retention policy are not explicitly added to bytecode. However, it seems like some tools can read them from bytecode.
E. g., “androidx.annotation.RequiresApi” annotation has “AnnotationRetention.BINARY” retention. It is not seen in bytecode. However, it seems that tools like Facebook’s RedEx can somehow read “RequiresApi” annotation.
UPD: Here is an example of the class:
class Test {
companion object {
@JvmStatic
val testProp : Int = 0
@RequiresApi(24)
val testProp22 : Int = 0
}
}
@JvmStatic is AnnotationRetention.RUNTIME @RequiresApi is AnnotationRetention.BINARY
For “@JvmStatic” I see the following in Android Studio dex byte code viewer:
I don’t know the answer, but I would check the Metadata annotation to the enclosing class. Kotlin puts some internal stuff there.
edit:
Actually, did you check they are not present in the bytecode? I ask because the most obvious explanation would be that they are the same as Java’s RetentionPolicy.CLASS - so they are stored in the bytecode, but ignored by JVM at runtime.
@broot, thanks for you comment. Metadata was my guess too, but unfortunately I didn’t find any tool to “decode” metadata and prove that the annotation is somewhere there.
Actually, did you check they are not present in the bytecode?
I updated my post. I tried different viewers to check the bytecode.
Frankly speaking, I don’t think it has anything to do with Kotlin. It is rather Android. In the JVM bytecode both annotations are clearly present:
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class RuntimeAnnotation
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class BinaryAnnotation
object MyTest {
@RuntimeAnnotation
fun testRuntime() = Unit
@BinaryAnnotation
fun testBinary() = Unit
}
public final void testRuntime();
descriptor: ()V
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 41: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this LMyTest;
RuntimeVisibleAnnotations:
0: #12()
RuntimeAnnotation
public final void testBinary();
descriptor: ()V
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 44: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 this LMyTest;
RuntimeInvisibleAnnotations:
0: #14()
BinaryAnnotation
I suspect runtime invisible annotations may be somehow separated or removed in the resulting dex, most probably in order to improve the performance.