Groovy compilation fails with `Unable to load class due to missing dependency`

I am trying (and failing) to compile a Java class which depends on a Groovy class in Gradle 2.4.

Here is the Gradle log:


Parallel execution with configuration on demand is an incubating feature.
:compileJava UP-TO-DATE
:compileGroovy
startup failed:
General error during conversion: java.lang.NoClassDefFoundError: Unable to load class uk.co.rx14.jlaunchlib.auth.MinecraftAuth due to missing dependency uk/co/rx14/jlaunchlib/auth/MinecraftAuthResult
java.lang.RuntimeException: java.lang.NoClassDefFoundError: Unable to load class uk.co.rx14.jlaunchlib.auth.MinecraftAuth due to missing dependency uk/co/rx14/jlaunchlib/auth/MinecraftAuthResult
        at org.codehaus.groovy.control.CompilationUnit.convertUncaughtExceptionToCompilationError(CompilationUnit.java:1088)
        at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1066)
        at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:588)
        at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:566)
        at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:543)
        at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:522)
        at org.gradle.api.internal.tasks.compile.ApiGroovyCompiler.execute(ApiGroovyCompiler.java:156)
        at org.gradle.api.internal.tasks.compile.ApiGroovyCompiler.execute(ApiGroovyCompiler.java:56)
        at org.gradle.api.internal.tasks.compile.daemon.CompilerDaemonServer.execute(CompilerDaemonServer.java:53)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
        at org.gradle.messaging.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
        at org.gradle.messaging.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:360)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
        at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoClassDefFoundError: Unable to load class uk.co.rx14.jlaunchlib.auth.MinecraftAuth due to missing dependency uk/co/rx14/jlaunchlib/auth/MinecraftAuthResult
        at org.codehaus.groovy.vmplugin.v5.Java5.configureClassNode(Java5.java:389)
        at org.codehaus.groovy.ast.ClassNode.lazyClassInit(ClassNode.java:262)
        at org.codehaus.groovy.ast.ClassNode.getInterfaces(ClassNode.java:357)
        at org.codehaus.groovy.ast.ClassNode.getAllInterfaces(ClassNode.java:420)
        at org.codehaus.groovy.ast.ClassNode.getAllInterfaces(ClassNode.java:422)
        at org.codehaus.groovy.ast.ClassNode.getAllInterfaces(ClassNode.java:412)
        at org.codehaus.groovy.control.ResolveVisitor.resolveNestedClass(ResolveVisitor.java:337)
        at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:307)
        at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:275)
        at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:259)
        at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:271)
        at org.codehaus.groovy.control.ResolveVisitor.visitConstructorOrMethod(ResolveVisitor.java:189)
        at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:123)
        at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1083)
        at org.codehaus.groovy.ast.ClassCodeVisitorSuisitClass(ClassCodeVisitorSupport.java:50)
        at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1260)
        at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:175)
        at org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit$1.call(JavaAwareCompilationUnit.java:69)
        at org.codehaus.groovy.control.CompilationUnit.applyToPrimaryClassNodes(CompilationUnit.java:1052)
        ... 19 more

1 error

:compileGroovy FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':compileGroovy'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 1.414 secs

Here is the Java class:

package uk.co.rx14.jlaunchlib.auth;

public interface MinecraftAuth {
    /**
     * Uses the given credentials to generate a new
     * {@link MinecraftAuthResult}.
     *
     * @param credentialsProvider The provider of the credentials to
     *                            authenticate with.
     * @return the authentication result to use in the minecraft arguments.
     * @throws ForbiddenOperationException when the credentials are invalid.
     * @throws IllegalArgumentException when something is null.
     */
    MinecraftAuthResult auth(CredentialsProvider credentialsProvider);

    /**
     * Refreshes a previously-valid {@link MinecraftAuthResult}. If the
     * refreshing fails, it returns an auth result where valid is set to false.
     *
     * @return the {@link MinecraftAuthResult}.
     * @throws IllegalArgumentException when something is null.
     */
    MinecraftAuthResult refresh(MinecraftAuthResult result);
}

And the Groovy class:

package uk.co.rx14.jlaunchlib.auth

import groovy.transform.Immutable

@Immutable class MinecraftAuthResult {
    String accessToken, clientToken
    Profile selectedProfile
    boolean valid

    @Override
    String toString() {
        "${getClass().getName()}(accessToken: $accessToken, clientToken: $clientToken, selectedProfile: $selectedProfile, valid: $valid)"
    }

    public static @Immutable class Profile {
        String name, id
    }
}

This code compiles perfectly fine in IDEA, and a workaround for now is to simply rename the Java class to MinecraftAuth.groovy

Two things:

  1. Make sure that the Java class that references Groovy classes is under src/main/groovy and not under src/main/java - the files in each directory are compiled with the respective compiler as follows:
  • The src/main/java fiels are compiled with the standard Java compiler - it is faster and guarantees that these classes do not depend on Groovy in any way.
  • The src/main/groovy fiels (can mix *.groovy or *.java) are compiled with the Groovy compiler, taking the classes produced by the Java step on the classppath.
  1. If that was not the problem, delete the .gradle directory from the build root and try running a clean build. There was an old bug that was corrupting the Gradle caches if you move a file from Java to Gradle source dirs.

The Java file was always in the src/main/groovy folder, so that’s not the issue. I moved the file back to being a Java class, and it compiled fine. Must have just been a strange state bug that got fixed by renaming it to groovy and back…

I have come across the same error again, this time I have found a fix.

Deleting .gradle/ in the project directory doesn’t fix the problem but gradle clean does so I suppose both .gradle and build/ have to be deleted.