Search code examples
javareflectionillegalaccessexception

Illegal reflective access on Streams using reflection


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);
}

Solution

  • 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.