Незаконный отражающий доступ к Streams с использованием отражения

Я использую отражение для вызова методов в java.util.stream.Stream, но поскольку фактические реализации (ReferencePipeline и т. д.) Имеют фактический исполняемый код, я получаю предупреждения о незаконном отражении доступа при вызове method.setAccessible(true), а без этого вызова он не работает. не работает. Мне было интересно, есть ли способ автоматически делегировать это супер-методу, доступ к которому не является незаконным? То есть я хочу вызвать filter там, где это разрешено для java.util.stream.Stream, а не ReferencePipeline или какой-либо другой реализации.

ИЗМЕНИТЬ Вот код. target - это конкретный экземпляр Stream, полученный посредством отражения.

assert target instanceof java.util.stream.Stream;

Method candidate = Stream.of(target.getClass().getMethods())
    .filter(method -> method.getName().equals("filter"))
    //.filter(myComplicatedCriteria) - omitted for brevity
    .findAny().orElseThrow();

try {
    candidate.setAccessible(true);
    return candidate.invoke(target, candidateParameterValues);
}
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
    throw new EolRuntimeException(ex);
}

Не могли бы вы предоставить код, чтобы проиллюстрировать проблему?

Karol Dowbecki 14.11.2018 17:53

Минимальный пример потребует слишком много кода, поскольку он отражает. Проблема в том, что я вызываю предположительно совершенно законный метод (например, filter), но поскольку экземпляр, в котором он вызывается, является подклассом Stream, невозможно убедить Java, что я пытаюсь использовать «легальный» метод.

Sina Madani 14.11.2018 18:07

Переопределенный метод не может ограничить видимость супер-метода. Скорее всего, вы пытаетесь получить доступ к перегруженному методу в дочернем классе. Невозможно узнать, что происходит, так как вы не хотите предоставлять код :(

Karol Dowbecki 14.11.2018 18:11

Неужто должно быть что-то, что можно сделать с MethodHandles?

Sina Madani 14.11.2018 18:17
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
154
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используйте класс интерфейса Stream вместо класса реализации target.getClass(). Измените код на:

Method candidate = Stream.of(Stream.class.getMethods())
        .filter(method -> method.getName().equals("filter"))
        ...  

Основная причина проблемы - java.util.stream.ReferencePipeline, а также java.util.stream.ReferencePipeline.Head, защищенный пакетом. Ваш класс не может получить доступ к этим классам с помощью отражения, даже если сам метод filter() определен как public.

Подход Stream.class.getMethods() будет работать, потому что ваш класс может получить доступ к общедоступному классу Stream. См. Проверку sun.reflect.Reflection.ensureMemberAccess(), если вам нужны подробности.

Другие вопросы по теме