1

I'm using reflection to invoke methods on java.util.stream.Stream but because the actual implementations (ReferencePipeline etc.) have the actual code which runs, I get illegal reflective access warnings when calling method.setAccessible(true), and without that call, it doesn't work. I was wondering whether there is a way to automatically delegate this to a super method where access isn't illegal? That is, I want to call filter where it's legal on java.util.stream.Stream and not ReferencePipeline or whatever the implementation is.

EDIT Here is some code. target is a concrete instance of a Stream obtained via reflection.

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);
}
Sina Madani
  • 1,246
  • 3
  • 15
  • 27
  • 1
    Can you please provide code to illustrate the problem? – Karol Dowbecki Nov 14 '18 at 16:53
  • A minimal example would require too much code since it's reflection. The problem is that I'm invoking what is supposedly a perfectly legal method (e.g. `filter`) but because the instance it's being invoked on is a subclass of Stream there's no way to convince Java that I'm trying to use the "legal" one – Sina Madani Nov 14 '18 at 17:07
  • An overriden method can't limit the visibility of a super method. You are most likely trying to access an overloaded method in a child class. There is no way to tell what's happening since you don't want to provide the code :( – Karol Dowbecki Nov 14 '18 at 17:11
  • Surely there must be something that can be done with `MethodHandles`? – Sina Madani Nov 14 '18 at 17:17

1 Answers1

1

Use the interface class Stream instead of the implementing class target.getClass(). Change the code to:

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

Root cause of the problem is java.util.stream.ReferencePipeline as well as java.util.stream.ReferencePipeline.Head being package protected. Your class can't access these classes using reflection even if the filter() method itself is defined as public.

The Stream.class.getMethods() approach will work because your class can access the public Stream class. See sun.reflect.Reflection.ensureMemberAccess() check if you need details.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111