The latest version of ProGuard, during the shrinking phase, removes methods that should not be removed. All settings have default values. I kept getting the following error messages:
Exception in thread "main" java.lang.NoSuchMethodError: a.iterator()Ljava/util/Iterator; at Main.main(Unknown Source)
and finally managed to reduce the error-causing class into a small application. Please note the double inheritance in the interface. The ProGuard version is 4.11 beta8.
import java.util.*; public class Main { // Combined interface to allow anonymous iterable classes public interface AnonIterable extends Iterable, Iterator {} public static void main(String[] args) { AnonIterable iterable = new AnonIterable() { // Iterable method public Iterator iterator() { return this; } // Iterator methods public boolean hasNext() { return false; } public Object next() { return null; } public void remove() {} }; iterable.iterator(); // Crashes with java.lang.NoSuchMethodError :( } }
The anonymous inner class, new AnonIterable() {...}, after being processed by ProGuard, loses all its methods. Only empty constructor remains:
public final class a { a() { } }
Disabling obfuscation doesn't help. The weird thing is, disabling shrinking doesn't help either. The app still crashes with NoSuchMethodError, but the decompiled version of inner class becomes different:
public final class a { a() { } private Iterator a() { return this; } private static boolean b() { return false; } private static Object c() { return null; } private static void d() { } }
Apparently, any connection with the interface's method signatures gets lost at some point.
Thanks for the report. This bug seems to have been fixed by a very recent correction in this area, which you can now find in ProGuard 4.11 beta9.
The new version fixes the problem, much thanks for the quick fix! :)
The new version (4.11 beta9) works great, with one note: comparing to version 4.10, it produces quite some extra glue code. In certain cases, ProGuard generates a whole chain of extra assignments: d2 = d1; d3 = d2; d4 = d3 etc (each variable is used only once). While this may be good for obfuscation purposes, this is not perfect for optimization. But this is just a minor thing.