Интерфейс Java 8 с методами по умолчанию не работает, когда Jacoco включен - PullRequest
0 голосов
/ 06 июня 2018

У нас есть интерфейс с методами по умолчанию , и мы реализовали этот интерфейс в классах Java и Kotlin, и мы предоставили реализацию для методов не по умолчанию.

Когдамы запускаем в режиме отладки (в котором нет testCoverageEnabled = true), и приложение работает как положено.Но когда мы запускаем другую конфигурацию с testCoverageEnabled = true, приложение вылетает с ошибкой ниже

java.lang.NoSuchMethodError: No static method $$triggerInterfaceInit()V in class Lcom/ui/viewholders/CAViewContract$$CC; or its super classes (declaration of 'ui.viewholders.CAViewContract$$CC' appears in /data/app/SMCXbiLYvHb1Kk08Kee__g==/base.apk)
    at home.c.CCFragment.<clinit>(Unknown Source:0)
    at home.HomePageCardProvider.getFragment(HomePageCardProvider.java:17)
    at home.HomeFragment.handleCardFragment(HomeFragment.java:172)

Примечание: 1. Версия JaCoCo: «0.8.0» 2. Операционная система: Android с minSdk 21

Если мы изменим minSdk на 24 с самим testCoverageEnabled = true, он будет работать.Мы не можем понять точную проблему.

1 Ответ

0 голосов
/ 23 июня 2018

Эта проблема может возникнуть, если вы хотите вызвать реализацию default метода, который не имеет default реализации в interface, который ваш класс явно implements это.(Но имеет default реализацию в базе (родитель, супер) interface из этого interface).

Пример: предположим, что эти определения:

class A implements DerivedInterface /*, ...*/ {
    @Override public void methodFromBaseInterface() {
        DerivedInterface.super.methodFromBaseInterface(); // Error:
            // NoSuchMethodError: No static method methodFromBaseInterface
    }
    // ...
}

interface DerivedInterface extends BaseInterface {
    // ... 
    // `methodFromBaseInterface` hasn't overriden here.
}

interface BaseInterface {
    default void methodFromBaseInterface() { /* ...*/ }
    // ...
}

Затем выполните:

A a = new A();
a.methodFromBaseInterface(); // This cause above error!

И вы получите ошибку в указанной точке!

(Заметка на полях: вам может потребоваться определить хотя бы один метод в DerivedInterface, чтобы избежать получения NoClassDefFoundError во время выполнения!)


Это похоже наЖук! Мы использовали super ключевое слово.Почему ожидался метод static? !! Другой момент заключается в том, что в приведенном выше коде нет проблем, и вы можете без проблем запустить его в любой среде, совместимой с Java 8!

Я думаю, что проблема связана с неполной поддержкой API языка Java 8 на платформе Android :

Android Studio 3.0 и более поздних версийподдерживает все функции языка Java 7 и подмножество функций языка Java 8, которые зависят от версии платформы .

Специально см. API языка Java 8 и Совместимость minSdkVersion таблица на этой странице :

java.lang.FunctionalInterface: уровень API 24 или выше.


Обходные пути, которые я нашел:

  1. Если у вас есть доступ к определению DerivedInterface, просто переопределите methodFromBaseInterface и явно делегируйте его интерфейсу super:

    interface DerivedInterface extends BaseInterface {
        @Override default void methodFromBaseInterface() {
            BaseInterface.super.methodFromBaseInterface();
        }
        // ...
    }
    
  2. Определите середину class, которая реализует BaseInterface и выведите из нее A.Затем запустите methodFromBaseInterface косвенно бросьте середину class:

    class MiddleClass /*extends B*/ implements BaseInterface {}
    
    class A extends MiddleClass implements DerivedInterface {
        @Override public void methodFromBaseInterface() {
            super.methodFromBaseInterface(); // Indirectly from `MiddleClass`
        }
        // ...
    }
    

    Примечание: раскомментируйте /*extends B*/, если у вашего A класса ранее был super с именем B.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...