parboiled: JDK11 reporting illegal reflective access

WARNING: Illegal reflective access by org.parboiled.transform.AsmUtils (file:/home/aaime/.m2/repository/org/parboiled/parboiled-java/1.1.7/parboiled-java-1.1.7.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int)
WARNING: Illegal reflective access by org.parboiled.transform.AsmUtils (file:/home/aaime/.m2/repository/org/parboiled/parboiled-java/1.1.7/parboiled-java-1.1.7.jar) to method java.lang.ClassLoader.findLoadedClass(java.lang.String)

I’m going to upgrade to 1.2.0 soon, but checked the code, the access seems to be still there:

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 19
  • Comments: 25 (8 by maintainers)

Most upvoted comments

Just released parboiled 1.4.0 which should fix the problem on Java 17.

with OpenJDK 17 (next Long Term Support release), this will become more fun - https://openjdk.java.net/jeps/403:

It will no longer be possible to relax the strong encapsulation of internal elements via a single command-line option, as was possible in JDK 9 through JDK 16.

WARNING: Please consider reporting this to the maintainers of org.parboiled.transform.AsmUtils
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

it is very possible, that Java 12 will halt with this lib on classpath

Is there any fix for this? Is there a version of parboiled that doesn’t trigger warnings on Java 11 and also supports Java 8?

AsmUtils.loadClass utilizes defineClass which doesn’t have JDK agnostic alternative so bundling the bytebuddy that has ClassInjector for this purpose would be a viable option. Another approach would be to indirectly provide the class injector as function. AsmUtils.findLoadedClass is even worse since to my knowledge there is no counterpart for that in JDK11. Luckily the already processed classes can be tracked in a class injector function.

ASMSettings also dictates what JDK level can be used in Vars and Actions. I got constant pool errors with static interface methods since the version isn’t derived from the given parser class but instead hardcoded to JDK7. ClassFileVersion of bytebuddy has this kind of feature so it really would be a smart addition to the dependencies.

This is how my ParserTransformer.transformParser looks when bytebuddy is applied via function. The actual workaround is in form of a gitst patch, but this is how I bypass the warning and more-over get my > JDK7 parser implementation to work.

https://gist.github.com/TuomasKiviaho/3d6dae166e85c4aaba94afb0318b4e4d

PS. I’m personally not using Parboiled.createParser since the parser instance isn’t thread-safe. Hence the example only contains how to generate a working parser in whichever environment the bytebuddy is capable of supporting.

    public static <T> Class<? extends T> transformParser(Class<T> parserClass)
        throws Exception
    {
        ClassInjector classInjector = (ClassInjector.UsingLookup.isAvailable()
            ? Optional.of(parserClass).<ClassInjector> map(
                ClassInjector.UsingLookup.of(MethodHandles.lookup())::in)
            : Optional.<ClassInjector> empty()).orElseGet(() -> {
                ClassLoader classLoader = parserClass.getClassLoader();
                ProtectionDomain protectionDomain = parserClass.getProtectionDomain();
                return ClassInjector.UsingUnsafe.isAvailable()
                    ? new ClassInjector.UsingUnsafe(classLoader, protectionDomain)
                    : new ClassInjector.UsingReflection(classLoader, protectionDomain);
            });
        Map<String, Class<?>> groupClasses = new TreeMap<>();
        return ParserTransformer.transformParser(parserClass,
            (className, groupClassGenerator) -> {
                return groupClasses.computeIfAbsent(className, key -> {
                    byte[] groupClassCode = groupClassGenerator.get();
                    Map<String, Class<?>> groupClass = classInjector.injectRaw(
                        Collections.singletonMap(className, groupClassCode));
                    return groupClass.get(className);
                });
            }, () -> {
                try
                {
                    return ClassFileVersion.of(parserClass).getMinorMajorVersion();
                }
                catch (IOException e)
                {
                    throw new UncheckedIOException(e);
                }
            });
    }

Not sure if it is related, but I’m hitting a similar warning on 1.3.1 (Java 9)

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by org.parboiled.transform.AsmUtils (file:/C:/Users/Mike/.m2/repository/org/parboiled/parboiled-java/1.3.1/parboiled-java-1.3.1.jar) to method java.lang.ClassLoader.findLoadedClass(java.lang.String)
WARNING: Please consider reporting this to the maintainers of org.parboiled.transform.AsmUtils
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release