Menu

#508 Some reflections can not be used

v4.7
open-works-for-me
Reflection (1)
5
2014-04-05
2014-04-04
xiaolibang
No

Hi Eric,

In the developing of android, I got a section of code blew
public class ResponseData
{
private DataObject dataObject;

public static class DataObject  
{  
    private long time;  
}

}
I tried to create an instance of DataObject with DataObject.class.newInstance(), but failed after obfuscation.
I debugged that and found there is no constructors for DataObject class in the byte code file.

I saw the instruction for ProGuard v4.7, and found the unused parameterless constructors will be removed after obfuscation/optimization.

I have to modified the code like
public class ResponseData
{
private DataObject dataObject = new DataObject();

public static class DataObject  
{  
    private long time;  
}

}
It worked well.

So the type of reflection can not be used even if the DataObject class is configured to be kept . The empty constructor is useful in reflection sometimes. Could the empty constructor be kept after obfuscation/optimization?

Best regards
xiaolibang

Discussion

  • Eric Lafortune

    Eric Lafortune - 2014-04-05

    Thanks for your report. This case seems to work fine for me, with ProGuard 4.11, but also with the older ProGuard 4.7. For instance:

    public class Test {
    
      public static void main(String[] args) {
        try {
          Inner.class.newInstance();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    
      public static class Inner {}
    }
    

    Can you provide such an example?

    If necessary, you can always keep all empty constructors with

    -keepclassmembers class * {
        <init>();
    }
    
     
    • xiaolibang

      xiaolibang - 2014-04-14

      Thanks for you reply.
      The code which can not work is like:
      public class ResponseData {
      private DataObject dataObject;

      public static class DataObject {
          private long lightOnTime;
      }
      
      public static void main(String[] args) {
          try {
              Class<?> dataClazz = ResponseData.class.getDeclaredField("dataObject").getType();
              dataClazz.newInstance();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
      

      }

      But it can work well if empty constructors are kept with
      -keepclassmembers class * {
      <init>();
      }

       

      Last edit: xiaolibang 2014-04-14
  • Eric Lafortune

    Eric Lafortune - 2014-04-05
    • status: open --> open-works-for-me
     

Log in to post a comment.