Android java.lang.VerifyError для частного метода с аннотированным аргументом - PullRequest
3 голосов
/ 07 июня 2010

У меня очень простой проект, который компилируется, но не может быть запущен в эмуляторе. Проблема с этим методом:

private void bar(@Some String a) {} // java.lang.VerifyError

Эту проблему можно избежать, если удалить аннотацию

private void bar(String a) {} // OK

или видимость метода изменилась:

void bar(@Some String a) {} // OK
public void bar(@Some String a) {} // OK
protected void bar(@Some String a) {} // OK

Есть идеи, что не так с оригинальным методом? Это ошибка Далвика, или?

Если кто-то хотел бы поэкспериментировать с кодом, вот он:

Test.java:

public class Test {

    private void bar(@Some String a) {}

    public void foo() {
        bar(null);
    }
}

Some.java:

public @interface Some {}

MainActivity.java:

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        new Test().foo();
    }
}

Трассировка стека:

ERROR/dalvikvm(1358): Could not find method com.my.Test.bar, referenced from method com.my.Test.foo
WARN/dalvikvm(1358): VFY: unable to resolve direct method 11: Lcom/my/Test;.bar (Ljava/lang/String;)V
WARN/dalvikvm(1358): VFY:  rejecting opcode 0x70 at 0x0001
WARN/dalvikvm(1358): VFY:  rejected Lcom/my/Test;.foo ()V
WARN/dalvikvm(1358): Verifier rejected class Lcom/my/Test;
DEBUG/AndroidRuntime(1358): Shutting down VM
WARN/dalvikvm(1358): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
ERROR/AndroidRuntime(1358): Uncaught handler: thread main exiting due to uncaught exception
ERROR/AndroidRuntime(1358): java.lang.VerifyError: com.my.Test
ERROR/AndroidRuntime(1358):     at com.my.MainActivity.onCreate(MainActivity.java:13)
ERROR/AndroidRuntime(1358):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.access$1800(ActivityThread.java:112)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
ERROR/AndroidRuntime(1358):     at android.os.Handler.dispatchMessage(Handler.java:99)
ERROR/AndroidRuntime(1358):     at android.os.Looper.loop(Looper.java:123)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.main(ActivityThread.java:3948)
ERROR/AndroidRuntime(1358):     at java.lang.reflect.Method.invokeNative(Native Method)
ERROR/AndroidRuntime(1358):     at java.lang.reflect.Method.invoke(Method.java:521)
ERROR/AndroidRuntime(1358):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
ERROR/AndroidRuntime(1358):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
ERROR/AndroidRuntime(1358):     at dalvik.system.NativeStart.main(Native Method)

Ответы [ 2 ]

3 голосов
/ 30 августа 2011

На самом деле это ошибка компилятора Eclipse 3.5 ( Bug 289576 ), которая изменяет модификатор private метода с аннотированным аргументом, так что метод становится "закрытым для пакета". Итак, ваш:

private void bar(@Some String a) {…}

в файле .class становится:

void bar(@Some String a) {…}

Однако измененный метод все еще вызывается инструкцией JVM invokespecial , которая предназначена только для вызовов закрытых методов (также для некоторых других не относящихся к методам вещей), но, что удивительно, работает и для "package-private" "методы в Sun / Oracle JVM.
Во время Android .class => .dex перевод invokespecial инструкция JVM преобразуется в invoke-direct инструкция Dalvik, которая может вызывать только частные методы и конструкторы. Так как метод bar() стал методом, видимым для пакета, invoke-direct не может его найти и выдает NoSuchMethodError.

Решением является использование Eclipse 3.6+ или компилятора javac (через build.xml ant-скрипт).

0 голосов
/ 28 мая 2011

Я предполагаю, что "private void bar (String) {}" помечен компилятором как полностью встроенный и фактически никогда не создается. Точно, почему тогда возникает ссылка в foo () (против вставки), сказать сложно, но, вероятно, аннотация испортила бухгалтерию компилятора.

(Подсказка здесь «приватная» - частные методы почти всегда являются хорошими кандидатами для встраивания, особенно с пустыми телами.)

...