Vinay S Shenoy
Vinay S Shenoy

Reputation: 4028

Cannot compile a java library with Gradle, works with the IDE

I’m running into a weird problem when I try to build my project via Gradle.

The build works fine when I import the project into IntelliJ and build/run tests via the IDE. However, if I run ./gradlew test, the build fails and it’s unable to resolve symbols in the JDK (like GenericArrayType).

If I delegate IntelliJ’s build/run actions to Gradle, I see the same problems in my IDE as well, so something seems to be up with my Gradle build, and I can’t figure out what. Other projects work fine, so it seems to be a problem with this specific project.

I have tried this on different machines (one running Ubuntu and the other running macOS) as well as different Gradle versions (4.10.2, 5.1.1), but the problem persists. I copied and pasted the source code to another project that already works perfectly fine, and then it started failing with the same errors as well, when I ran the unit tests.

Can someone help me figure out what’s going wrong here?

Here's what my settings.gradle looks like:

rootProject.name = 'types'

And build.gradle:

group 'com.vinaysshenoy'
version '1.0.0'

buildscript {
  ext.junit_version = '4.12'
  ext.assertj_version = '3.11.1'
  ext.jsr305_version = '3.0.2'

  repositories {
    mavenCentral()
  }
}

apply plugin: 'java-library'

java {
  sourceCompatibility JavaVersion.VERSION_1_8
  targetCompatibility JavaVersion.VERSION_1_8
}

repositories {
  mavenCentral()
}

dependencies {
  implementation "com.google.code.findbugs:jsr305:$jsr305_version"
  testImplementation "junit:junit:$junit_version"
  testImplementation "org.assertj:assertj-core:$assertj_version"
}

Here's what I see when I run it via the command line:

      public static final class GenericArrayTypeImpl implements GenericArrayType {
                                                                ^
      symbol:   class GenericArrayType
      location: class Util
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:230: error: cannot find symbol
      public static final class ParameterizedTypeImpl implements ParameterizedType {
                                                                 ^
      symbol:   class ParameterizedType
      location: class Util
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:340: error: cannot find symbol
      public static final class WildcardTypeImpl implements WildcardType {
                                                            ^
      symbol:   class WildcardType
      location: class Util
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:54: error: incompatible types: ParameterizedTypeImpl cannot be converted to ParameterizedType
        return new ParameterizedTypeImpl(null, rawType, typeArguments);
               ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:63: error: incompatible types: ParameterizedTypeImpl cannot be converted to ParameterizedType
        return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);
               ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:68: error: incompatible types: GenericArrayTypeImpl cannot be converted to GenericArrayType
        return new GenericArrayTypeImpl(componentType);
               ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:78: error: incompatible types: WildcardTypeImpl cannot be converted to WildcardType
        return new WildcardTypeImpl(new Type[] { bound }, EMPTY_TYPE_ARRAY);
               ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:86: error: incompatible types: WildcardTypeImpl cannot be converted to WildcardType
        return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound });
               ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:153: error: incompatible types: ParameterizedType cannot be converted to ParameterizedTypeImpl
          Type[] aTypeArguments = pa instanceof ParameterizedTypeImpl
                                  ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:154: error: incompatible types: ParameterizedType cannot be converted to ParameterizedTypeImpl
              ? ((ParameterizedTypeImpl) pa).typeArguments
                                         ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:156: error: incompatible types: ParameterizedType cannot be converted to ParameterizedTypeImpl
          Type[] bTypeArguments = pb instanceof ParameterizedTypeImpl
                                  ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/Types.java:157: error: incompatible types: ParameterizedType cannot be converted to ParameterizedTypeImpl
              ? ((ParameterizedTypeImpl) pb).typeArguments
                                         ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:52: error: incompatible types: bad type in conditional expression
          return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
                               ^
        GenericArrayTypeImpl cannot be converted to Type
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:55: error: incompatible types: Type cannot be converted to ParameterizedTypeImpl
          if (type instanceof ParameterizedTypeImpl) { return type; }
              ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:57: error: incompatible types: ParameterizedTypeImpl cannot be converted to Type
          return new ParameterizedTypeImpl(p.getOwnerType(),
                 ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:61: error: incompatible types: Type cannot be converted to GenericArrayTypeImpl
          if (type instanceof GenericArrayTypeImpl) { return type; }
              ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:63: error: incompatible types: GenericArrayTypeImpl cannot be converted to Type
          return new GenericArrayTypeImpl(g.getGenericComponentType());
                 ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:66: error: incompatible types: Type cannot be converted to WildcardTypeImpl
          if (type instanceof WildcardTypeImpl) { return type; }
              ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:68: error: incompatible types: WildcardTypeImpl cannot be converted to Type
          return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
                 ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:118: error: incompatible types: bad type in conditional expression
                ? new ParameterizedTypeImpl(newOwnerType, original.getRawType(), args)
                  ^
        ParameterizedTypeImpl cannot be converted to Type
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:260: error: method does not override or implement a method from a supertype
        @Override
        ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:265: error: method does not override or implement a method from a supertype
        @Override
        ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:270: error: method does not override or implement a method from a supertype
        @Override
        ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:279: error: incompatible types: ParameterizedTypeImpl cannot be converted to Type
              && Types.equals(this, (ParameterizedType) other);
                              ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:313: error: method does not override or implement a method from a supertype
        @Override
        ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:321: error: incompatible types: GenericArrayTypeImpl cannot be converted to Type
              && Types.equals(this, (GenericArrayType) o);
                              ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:363: error: method does not override or implement a method from a supertype
        @Override
        ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:368: error: method does not override or implement a method from a supertype
        @Override
        ^
    /Users/vinay/Dev/IdeaProjects/types/src/main/java/com/vinaysshenoy/types/util/Util.java:376: error: incompatible types: WildcardTypeImpl cannot be converted to Type
              && Types.equals(this, (WildcardType) other);
                          ^

Upvotes: 7

Views: 2139

Answers (4)

Chriki
Chriki

Reputation: 16338

Solution

@Zgurskyi’s answer is a good workaround, however, I believe it only cures the symptom of the actual problem (see below). Here’s another, IMHO cleaner way to fix the underlying issue: make the imports of the nested types of com.vinaysshenoy.types.util.Util from com.vinaysshenoy.types.Types non-static:

diff --git a/src/main/java/com/vinaysshenoy/types/Types.java b/src/main/java/com/vinaysshenoy/types/Types.java
index e3a44d8..92ac237 100644
--- a/src/main/java/com/vinaysshenoy/types/Types.java
+++ b/src/main/java/com/vinaysshenoy/types/Types.java
@@ -17,9 +17,9 @@ package com.vinaysshenoy.types;


 import static com.vinaysshenoy.types.util.Util.EMPTY_TYPE_ARRAY;
-import static com.vinaysshenoy.types.util.Util.GenericArrayTypeImpl;
-import static com.vinaysshenoy.types.util.Util.ParameterizedTypeImpl;
-import static com.vinaysshenoy.types.util.Util.WildcardTypeImpl;
+import com.vinaysshenoy.types.util.Util.GenericArrayTypeImpl;
+import com.vinaysshenoy.types.util.Util.ParameterizedTypeImpl;
+import com.vinaysshenoy.types.util.Util.WildcardTypeImpl;
 import static com.vinaysshenoy.types.util.Util.getGenericSupertype;
 import static com.vinaysshenoy.types.util.Util.resolve;

(BTW, other than @Zgurskyi I can also reproduce this with a manual javac call. I only have one JDK installed; maybe @Zgurskyi’s javac on the command line is not from the same JDK that Gradle uses.)

Actual Problem

You statically import nested classes (not just class members), although this should never be necessary. I’m actually surprised that this seems to usually work, but apparently some Java compilers at least choke on it under certain circumstances.

In your case, the Java compiler used by Gradle couldn’t correctly resolve the imports in the following scenario (only a rough, not very technical description of what the compiler does):

  1. when processing com.vinaysshenoy.types.util.Util, the compiler finds a static import of com.vinaysshenoy.types.Types.arrayOf, so the compiler looks at the com.vinaysshenoy.types.Types class.
  2. com.vinaysshenoy.types.Types has a static import of com.vinaysshenoy.types.util.Util.GenericArrayTypeImpl, so the compiler looks at the nested GenericArrayTypeImpl class.
  3. com.vinaysshenoy.types.util.Util.GenericArrayTypeImpl uses (java.lang.reflect.)GenericArrayType, however, the import for that type was not yet processed at this point which leads to the “cannot find symbol” error.

Arguably, it could also be considered to be a JDK bug that this works with some compilers but not with others.

Upvotes: 2

Martin Zeitler
Martin Zeitler

Reputation: 76639

after having built the project, I've come to a whole other conclusion: it seems the system-wide JDK has corrupted files - and that it works with the IDE, that is because it uses an embedded version.

in case Gradle cannot use that JDK, it can be defined in the gradle.properties file (the path to the IDE's embedded JDK should work, better than the one installed system-wide, as used by default):

# replace this path with the path to the IDE's embedded JDK:
org.gradle.java.home = /Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home

... and this should already make it build.

Upvotes: 1

Oleksii Zghurskyi
Oleksii Zghurskyi

Reputation: 4365

In order to build the project, use fully qualified names for implemented interfaces for static nested classes defined in com.vinaysshenoy.types.util.Util:

  public static final class ParameterizedTypeImpl implements java.lang.reflect.ParameterizedType { ... }

  public static final class GenericArrayTypeImpl implements java.lang.reflect.GenericArrayType { ... }

  public static final class WildcardTypeImpl implements java.lang.reflect.WildcardType { ... }

Also, if you don't want to use fully qualified names, then just extract static nested classes to top level.

Notes:

  1. The project compiles without errors, when JDK compiler is used:
javac -cp path_to_jsr305-3.0.2.jar -d bin src/main/java/com/vinaysshenoy/types/Types.java src/main/java/com/vinaysshenoy/types/util/Util.java
  1. This problem seems to be dependent on platform. I've tried to build project on Windows 10/Oracle JDK 1.8.0_111 - and no issues were observed. However, the issue reproduced exactly as described on Ubuntu 16.04/Oracle JDK 1.8.0_201 & Ubuntu 16.04/OpenJDK 1.8.0_191.

Upvotes: 3

Peter Walser
Peter Walser

Reputation: 15706

I checked out your project, and could successfully build it with gradlew clean build.

I assume that gradle can't find the JDK installation, due to

  • the JDK not being installed (IDEs often come with their own bundled installation), or
  • the JAVA_HOME environment variable not being properly set (set and point it to your JDK installation directory).

Upvotes: 1

Related Questions