Отражение Java в Android Studio не удается найти общедоступный статический метод для вызова

#java #android #api #reflection

#java #Android #API #отражение

Вопрос:

Код отражения Java в моем приложении для Android вызывает общедоступный статический метод в пакете B из пакета A.

Недавно, после некоторых обновлений Gradle, я не могу вызвать тот же метод. Моя реализация завершается с ошибкой noSuchMethod Found exception. Как я могу заставить реализацию находить этот метод?

Я попытался распечатать все доступные методы из класса. Результатом являются все общедоступные нестатические методы. Статические методы недоступны для вызова. Метод, который я хочу вызвать, является статическим методом «getInstance», который инициализирует класс и возвращает одноэлементный экземпляр.

Вызывающий код:

 implementationClass = Class.forName(CLIENT_CLASS_NAME, false, ClientProvider.class.getClassLoader());
final Method method = implementationClass.getMethod("getInstance", (Class[]) null);
result = method.invoke(null, (Object[]) null);
  

Вызываемый код:

 /**
* Public static method to be reflected.
*/
public static ClientImpl getInstance() {
    return ClientImplHolder.INSTANCE;
}

/**
 * Private class used to hold the lazily initialized singleton instance.
 */
private static class ClientImplHolder {
    private static final ClientImpl INSTANCE = new ClientImpl();
}
  

При попытке ‘GetMethod’ я получаю исключение NoSuchMethodException.

Не уверен, что я здесь делаю не так, ценю любую помощь. Спасибо!

Комментарии:

1. если вы используете последнюю версию, доступ к интерфейсам и отражениям, отличным от sdk, запрещен

Ответ №1:

Оказывается, Proguard удалял метод из сборки, поскольку он больше нигде не использовался. Добавлено исключение для класса, и проблема исчезла.

Ответ №2:

Если я правильно понял, вы неправильно использовали reflection API

просто попробуйте это.

 public class Test {

    public static void main(String[] args) {
        try {
            ClientImpl client = (ClientImpl) Class.forName(ClientImpl.class.getCanonicalName())
                    .getMethod("getInstance")
                    .invoke(null);

            System.out.println(client.toString()   " with some -> "   client.getSome());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

/**
 * Public static method to be reflected.
 */

class ClientImpl {

    private final int some;

    public int getSome() {
        return some;
    }

    private ClientImpl(int some) {
        this.some = some;
    }

    public static ClientImpl getInstance() {
        return ClientImplHolder.INSTANCE;
    }

    /**
     * Private class used to hold the lazily initialized singleton instance.
     */
    private static class ClientImplHolder {
        private static final ClientImpl INSTANCE = new ClientImpl(123);
    }
}
  

и это приведет к правильному результату

 ClientImpl@<hashcode> with some -> 123
  

Когда вы используете статические методы в reflection API, вам не нужно явно вызывать ClassLoader, вы должны указать его canonicalName в качестве аргумента, затем вы можете вызывать его методы.

Комментарии:

1. У меня не сработало. Я все еще получаю то же исключение.

Ответ №3:

Попробуйте заменить его, возможно, это проблема с параметрами.

     final Method method = implementationClass.getMethod("getInstance");
    result = method.invoke(null);
  

Ответ №4:

Начиная с Android 9 (уровень API 28), платформа ограничивает, какие интерфейсы, отличные от SDK, может использовать ваше приложение. Эти ограничения применяются всякий раз, когда приложение ссылается на интерфейс, отличный от SDK, или пытается получить его дескриптор с помощью отражения.

Комментарии:

1. Когда я запускаю implementationClass.getMethods() , я получаю другие методы из того же класса, которые доступны для использования. Только getInstance (который является единственным статическим методом) недоступен для использования.

2. попробуйте getDeclaredMethod() вместо GetMethod()