views:

62

answers:

2

"Abstract class instation," you say. "Impossible!"

Here's my code:

public static AbstractFoo getAbstractFoo(Context context) {
    try {
        Class<?> klass = Class
                .forName("com.bat.baz.FooBar");
        Constructor<?> constructor = klass.getDeclaredConstructor(
                String.class, String.class);
        constructor.setAccessible(true);

        AbstractFoo foo = (AbstractFoo) constructor.newInstance(
                "1", "2");
        return foo;
    } catch (ClassNotFoundException e) {
        // Ignore
    } catch (NoSuchMethodException e) {
        throw new InflateException(
                "No matching constructor");
    } catch (IllegalAccessException e) {
        throw new InflateException("Could not create foo", e);
    } catch (InvocationTargetException e) {
        throw new InflateException("Could not create foo", e);
    } catch (InstantiationException e) {
        throw new InflateException("Could not create foo", e);
    }
    return null;
}

com.bat.baz.FooBar is a private class that extends AbstractFoo. Without Proguard, this code runs on my Android device. With it, it fails on the NoSuchMethodException try/catch.

I continue to add statements to my Proguard config file like

-keep public abstract class  AbstractFoo
{public *;protected *; private *;} 

But that doesn't solve the problem. How can I get Proguard to accept that this is a valid way to instantiate the AbstractFoo object? At least, if it works without Proguard, it should work with it.

A: 

Are you also adding statements to keep the stuff in FooBar?

You can use "dexdump" or "dexlist" to see the list of classes and methods that are actually generated into the .dex file. Comparing what you get with and without proguard could be illuminating.

fadden
I didn't figure it out using your method, but I did eventually discover what was up. I inspected my mapping.txt file and found that the constructor for FooBar was simply not being added. Variables above and methods below it were being transformed, but the constructor was simply not there. I am currently trying to figure out why that is, even with an explicit declaration of <init>
GJTorikian
+1  A: 

ProGuard is removing the constructor from the code, because it appears unused. ProGuard can't detect that the constructor is being called by reflection. So, you have to keep it explicitly:

-keepclassmembers class com.bat.baz.FooBar {
  <init>(java.lang.String, java.lang.String);
}

Please note that you may have better chances with questions like these on ProGuard's help forum.

Eric Lafortune