Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compileJava error on JDK 17 due to java.lang.NoClassDefFoundError: com/sun/tools/javac/util/Filter #1926

Closed
haisi opened this issue Sep 26, 2021 · 1 comment · Fixed by #1936

Comments

@haisi
Copy link

haisi commented Sep 26, 2021

What happened?

In the following project on JDK 17 I get java.lang.NoClassDefFoundError: com/sun/tools/javac/util/Filter when I gradlew clean build: https://github.com/haisi/jPBE

 Task :compileJava
/Users/hasankara/projects/private/jPBE/src/main/java/li/selman/jpbe/datastructure/Graph.java:144: warning: [UnusedMethod] Private method 'getAllTraceExpressions' is never used.
    private List<Expressions> getAllTraceExpressions(Stream<Edge> edgeStream) {
                              ^
    (see https://errorprone.info/bugpattern/UnusedMethod)
  Did you mean to remove this line?
/Users/hasankara/projects/private/jPBE/src/main/java/li/selman/jpbe/datastructure/Graph.java:32: error: An unhandled exception was thrown by the Error Prone static analysis plugin.
public class Graph {
       ^
     Please report this at https://github.com/google/error-prone/issues/new and include the following:
  
     error-prone version: 2.9.0
     BugPattern: ClassInitializationDeadlock
     Stack Trace:
     java.lang.NoClassDefFoundError: com/sun/tools/javac/util/Filter
        at com.palantir.baseline.errorprone.ClassInitializationDeadlock.matchClass(ClassInitializationDeadlock.java:71)
        at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:450)
        at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:548)
        at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:860)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:86)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
        at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111)
        at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:119)
        at jdk.compiler/com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:152)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:561)
        at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:151)
        at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:614)
        at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:60)
        at com.google.errorprone.scanner.Scanner.scan(Scanner.java:58)
        at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
        at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:152)
        at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:132)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1394)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1341)
        at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:933)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
        at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
        at org.gradle.internal.compiler.java.IncrementalCompileTask.call(IncrementalCompileTask.java:89)
        at org.gradle.api.internal.tasks.compile.AnnotationProcessingCompileTask.call(AnnotationProcessingCompileTask.java:94)
        at org.gradle.api.internal.tasks.compile.ResourceCleaningCompilationTask.call(ResourceCleaningCompilationTask.java:57)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:54)
        at org.gradle.api.internal.tasks.compile.JdkJavaCompiler.execute(JdkJavaCompiler.java:39)
        at org.gradle.api.internal.tasks.compile.daemon.AbstractDaemonCompiler$CompilerWorkAction.execute(AbstractDaemonCompiler.java:135)
        at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:63)
        at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:49)
        at org.gradle.workers.internal.AbstractClassLoaderWorker$1.create(AbstractClassLoaderWorker.java:43)
        at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:97)
        at org.gradle.workers.internal.AbstractClassLoaderWorker.executeInClassLoader(AbstractClassLoaderWorker.java:43)
        at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:32)
        at org.gradle.workers.internal.FlatClassLoaderWorker.run(FlatClassLoaderWorker.java:22)
        at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:85)
        at org.gradle.workers.internal.WorkerDaemonServer.run(WorkerDaemonServer.java:55)
        at org.gradle.process.internal.worker.request.WorkerAction$1.call(WorkerAction.java:138)
        at org.gradle.process.internal.worker.child.WorkerLogEventListener.withWorkerLoggingProtocol(WorkerLogEventListener.java:41)
        at org.gradle.process.internal.worker.request.WorkerAction.run(WorkerAction.java:135)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
        at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
        at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
        at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:414)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
        at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:61)
        at java.base/java.lang.Thread.run(Thread.java:833)
  Caused by: java.lang.ClassNotFoundException: com.sun.tools.javac.util.Filter
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:440)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:587)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        ... 59 more
1 error
1 warning

> Task :compileJava FAILED

On the error prone side, this JDK17 incompatibility has already been fixed.

A compatibility layer might look like:
import com.sun.tools.javac.code.Scope;
import com.sun.tools.javac.code.Scope.LookupKind;
import com.sun.tools.javac.code.Symbol;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.function.Predicate;
import javax.lang.model.element.Name;

/**
 * A compatibility wrapper around {@link com.sun.tools.javac.util.Filter}.
 * <p>
 * Adapted from <a href="https://github.com/google/error-prone/blob/master/check_api/src/main/java/com/google/errorprone/util/ErrorProneScope.java">
 *     Error Prone</a>.
 */
class ScopeCompat {
    private final Scope scope;

    ScopeCompat(Scope scope) {
        this.scope = scope;
    }

    @SuppressWarnings("unchecked") // reflection
    public Iterable<Symbol> getSymbolsByName(Name name, Predicate<Symbol> predicate) {
        return (Iterable<Symbol>) invoke(getSymbolsByName, name, maybeAsFilter(predicate));
    }

    @SuppressWarnings("unchecked") // reflection
    public Iterable<Symbol> getSymbolsByName(Name name, Predicate<Symbol> predicate, LookupKind lookupKind) {
        return (Iterable<Symbol>) invoke(getSymbolsByNameLookupKind, name, maybeAsFilter(predicate), lookupKind);
    }

    @SuppressWarnings("unchecked") // reflection
    public Iterable<Symbol> getSymbols(Predicate<Symbol> predicate) {
        return (Iterable<Symbol>) invoke(getSymbols, maybeAsFilter(predicate));
    }

    @SuppressWarnings("unchecked") // reflection
    public Iterable<Symbol> getSymbols(LookupKind lookupKind) {
        return (Iterable<Symbol>) invoke(getSymbols, lookupKind);
    }

    @SuppressWarnings("unchecked") // reflection
    public Iterable<Symbol> getSymbols(Predicate<Symbol> predicate, LookupKind lookupKind) {
        return (Iterable<Symbol>) invoke(getSymbols, maybeAsFilter(predicate), lookupKind);
    }

    public boolean anyMatch(Predicate<Symbol> predicate) {
        return (boolean) invoke(anyMatch, maybeAsFilter(predicate));
    }

    private static final Class<?> FILTER_CLASS = getFilterClass();

    private static Class<?> getFilterClass() {
        try {
            return Class.forName("com.sun.tools.javac.util.Filter");
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    private static final Method anyMatch = getImpl("anyMatch", Predicate.class);

    private static final Method getSymbolsByName = getImpl("getSymbolsByName", Name.class, Predicate.class);

    private static final Method getSymbolsByNameLookupKind =
            getImpl("getSymbolsByName", Name.class, Predicate.class, LookupKind.class);

    private static final Method getSymbols = getImpl("getSymbols", Predicate.class);

    private static Method getImpl(String name, Class<?>... parameters) {
        return FILTER_CLASS != null
                ? getMethodOrDie(
                        Scope.class,
                        name,
                        Arrays.stream(parameters)
                                .map(p -> p.equals(Predicate.class) ? FILTER_CLASS : p)
                                .toArray(Class<?>[]::new))
                : getMethodOrDie(Scope.class, name, parameters);
    }

    private Object invoke(Method method, Object... args) {
        try {
            return method.invoke(scope, args);
        } catch (ReflectiveOperationException e) {
            throw new LinkageError(e.getMessage(), e);
        }
    }

    private Object maybeAsFilter(Predicate<Symbol> predicate) {
        if (FILTER_CLASS == null) {
            return predicate;
        }
        return Proxy.newProxyInstance(
                getClass().getClassLoader(), new Class<?>[] {FILTER_CLASS}, (proxy, method, args) -> {
                    checkState(method.getName().equals("accepts"));
                    return predicate.test((Symbol) args[0]);
                });
    }

    private static Method getMethodOrDie(Class<?> clazz, String name, Class<?>... parameters) {
        try {
            return clazz.getMethod(name, parameters);
        } catch (NoSuchMethodException e) {
            throw new LinkageError(e.getMessage(), e);
        }
    }
}
With changes in `ClassInitalizationDeadlock#cannotBeInitializedExternally`
private boolean cannotBeInitializedExternally(ClassSymbol newClassSymbol) {
    if (newClassSymbol.isPrivate()) {
        return true;
    }

    WriteableScope scope = newClassSymbol.members();
    return !new ScopeCompat(scope)
            .getSymbols(CanBeExternallyInitializedFilter.INSTANCE, LookupKind.NON_RECURSIVE)
            .iterator()
            .hasNext();
}
java -version
openjdk version "17" 2021-09-14
OpenJDK Runtime Environment Temurin-17+35 (build 17+35)
OpenJDK 64-Bit Server VM Temurin-17+35 (build 17+35, mixed mode, sharing)

What did you want to happen?

Support error-prone on JDK 17.

@fawind
Copy link
Contributor

fawind commented Oct 19, 2021

Thanks for the detailed report! This should be fixed with the latest release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants