0

I have a jar with a simple java class like below

package org.debraj.pkgcmp.dummy;

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

import com.google.common.annotations.VisibleForTesting;

public class PackageAnnotation {
    @VisibleForTesting
    public void dummyMethod() {

    }
}

After decompiling the class with javap the annotation information is not showing up.

dmanna-m01:dummy dmanna$ javap PackageAnnotation.class
Compiled from "PackageAnnotation.java"
public class org.debraj.pkgcmp.dummy.PackageAnnotation {
  public org.debraj.pkgcmp.dummy.PackageAnnotation();
  public void dummyMethod();
}

Can someone let me know why the annotation information is missing in the decompiled class even though the @VisibleForTesting is annotation of type RetentionPolicy.CLASS?

dmanna-m01:dummy dmanna$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

Guava Version -23.5-jre

I have already seen this question but the accepted answer does not seem to be valid here. As per the Java doc

RetentionPolicy.class - Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time.

So javap should be able to show the annotation information for RetentionPolicy.CLASS also.

EDIT

dmanna-m01:dummy dmanna$ javap -c PackageAnnotation.class
Compiled from "PackageAnnotation.java"
public class org.debraj.pkgcmp.dummy.PackageAnnotation {
  public org.debraj.pkgcmp.dummy.PackageAnnotation();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void dummyMethod();
    Code:
       0: return
}

Output of javap -v

dmanna-m01:dummy dmanna$ javap -v PackageAnnotation.class
Classfile /Users/dmanna/workspaces/java/eclipse/pkgcmp/target/classes/org/debraj/pkgcmp/dummy/PackageAnnotation.class
  Last modified Feb 14, 2018; size 489 bytes
  MD5 checksum 06949d127e5f631f77060be1b1f09b60
  Compiled from "PackageAnnotation.java"
public class org.debraj.pkgcmp.dummy.PackageAnnotation
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // org/debraj/pkgcmp/dummy/PackageAnnotation
   #2 = Utf8               org/debraj/pkgcmp/dummy/PackageAnnotation
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Utf8               Code
   #8 = Methodref          #3.#9          // java/lang/Object."<init>":()V
   #9 = NameAndType        #5:#6          // "<init>":()V
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lorg/debraj/pkgcmp/dummy/PackageAnnotation;
  #14 = Utf8               dummyMethod
  #15 = Utf8               RuntimeInvisibleAnnotations
  #16 = Utf8               Lcom/google/common/annotations/VisibleForTesting;
  #17 = Utf8               SourceFile
  #18 = Utf8               PackageAnnotation.java
{
  public org.debraj.pkgcmp.dummy.PackageAnnotation();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #8                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lorg/debraj/pkgcmp/dummy/PackageAnnotation;

  public void dummyMethod();
    descriptor: ()V
    flags: ACC_PUBLIC
    RuntimeInvisibleAnnotations:
      0: #16()
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       1     0  this   Lorg/debraj/pkgcmp/dummy/PackageAnnotation;
}
SourceFile: "PackageAnnotation.java"

EDIT 2

I am still not seeing the annotation in javap if I use some RUNTIME retention policy (e.g - Subscribe )

package org.debraj.pkgcmp.dummy;

import com.google.common.eventbus.Subscribe;

public class PackageAnnotation {
    @Subscribe
    public void dummyMethod() {

    }
}

Output of javap

dmanna-m01:dummy dmanna$ javap PackageAnnotation.class
Compiled from "PackageAnnotation.java"
public class org.debraj.pkgcmp.dummy.PackageAnnotation {
  public org.debraj.pkgcmp.dummy.PackageAnnotation();
  public void dummyMethod();
}

Output of javap -c

dmanna-m01:dummy dmanna$ javap -c PackageAnnotation.class
Compiled from "PackageAnnotation.java"
public class org.debraj.pkgcmp.dummy.PackageAnnotation {
  public org.debraj.pkgcmp.dummy.PackageAnnotation();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void dummyMethod();
    Code:
       0: return
}

Output of javap -v

dmanna-m01:dummy dmanna$ javap -v PackageAnnotation.class
Classfile /Users/dmanna/workspaces/java/eclipse/pkgcmp/target/classes/org/debraj/pkgcmp/dummy/PackageAnnotation.class
  Last modified Feb 14, 2018; size 476 bytes
  MD5 checksum fd8b8e678ed771fa19193b73feae1acb
  Compiled from "PackageAnnotation.java"
public class org.debraj.pkgcmp.dummy.PackageAnnotation
  minor version: 0
  major version: 49
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#16         // java/lang/Object."<init>":()V
   #2 = Class              #17            // org/debraj/pkgcmp/dummy/PackageAnnotation
   #3 = Class              #18            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               LocalVariableTable
   #9 = Utf8               this
  #10 = Utf8               Lorg/debraj/pkgcmp/dummy/PackageAnnotation;
  #11 = Utf8               dummyMethod
  #12 = Utf8               RuntimeVisibleAnnotations
  #13 = Utf8               Lcom/google/common/eventbus/Subscribe;
  #14 = Utf8               SourceFile
  #15 = Utf8               PackageAnnotation.java
  #16 = NameAndType        #4:#5          // "<init>":()V
  #17 = Utf8               org/debraj/pkgcmp/dummy/PackageAnnotation
  #18 = Utf8               java/lang/Object
{
  public org.debraj.pkgcmp.dummy.PackageAnnotation();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lorg/debraj/pkgcmp/dummy/PackageAnnotation;

  public void dummyMethod();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 9: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       1     0  this   Lorg/debraj/pkgcmp/dummy/PackageAnnotation;
    RuntimeVisibleAnnotations:
      0: #13()
}
SourceFile: "PackageAnnotation.java"
tuk
  • 5,941
  • 14
  • 79
  • 162
  • @VisibleForTesting is a guava class. I saw it in the source code. – tuk Feb 13 '18 at 19:14
  • 2
    Have you tried with `javap -v`? – chrylis -cautiouslyoptimistic- Feb 13 '18 at 19:16
  • No but I tried with javap -c – tuk Feb 13 '18 at 19:16
  • What does the `-c` and the `-v` produce in the output? You should be seeing a `RuntimeInvisibleAnnotations` entry with a reference to the annotation. – Sotirios Delimanolis Feb 14 '18 at 04:50
  • @SotiriosDelimanolis - Updated the question with `-c` and `-v`. But why this annotation is `RuntimeInvisibleAnnotations`. As [the code](https://google.github.io/guava/releases/21.0/api/docs/src-html/com/google/common/annotations/GwtCompatible.html#line.65) shows the type is having type `RententionPolicy.CLASS`. – tuk Feb 14 '18 at 08:57
  • That code is for a different annotation. `@VisibleForTesting` has no explicit retention policy so it defaults to `CLASS`. It's runtime invisible because reflection operations should not return it at runtime. – Sotirios Delimanolis Feb 14 '18 at 15:31
  • @SotiriosDelimanolis - As per my understanding `CLASS` type annotations are retained in the .class file. So `javap` should have been able to show it in decompiled class. Please check my edit 2 I am still not seeing the annotation in the output of `javap` even if I am using RUNTIME annotations. – tuk Feb 14 '18 at 17:38
  • _So javap should have been able to show it in decompiled class_ And it did, as you saw in the `RuntimeInvisibleAnnotations`. For `RUNTIME`, you see it in the `RuntimeVisibleAnnotations` and it's available through reflection operations. – Sotirios Delimanolis Feb 14 '18 at 17:48
  • @SotiriosDelimanolis Can you please post your explanation in comment as an answer so that I can accept it? – tuk Apr 19 '20 at 18:13

0 Answers0