javagradleintellij-idea

IntelliJ Gradle Import Breaks Module Structure


I have seen the other posts on this topic and they have not answered my questions, so I am making a post of my own.

IntelliJ automatically imports Gradle projects and creates an IntelliJ project with its own module structure. However, the way it does it breaks legacy code (especially one provided by my university). Let me show you an example:

Gradle Auto-import

This is one of the introductory projects given by my university, so it is rather small. As far as I am aware, they use the standard Gradle directory structure for projects. All of these classes with package main.java compile with Gradle and work as intended. However, the way IntelliJ imported the project, it thinks that my classes are broken.

I had to manually fix this by removing the modules, transferring all dependencies to the primary project module, and marking src/main/java as the sources root:

The project structure that I want

Magically, all of the errors go away and I can code freely and compile with IDE/Gradle no problem. However, sometimes I need to add more dependencies to the Gradle file, etc., which means that I need to refresh it in the IDE - which results in the disastrous auto-import.

So I have the following questions:


Solution

  • Your first screenshot indicates, based on the folder's icon, that IntelliJ believes src/main/java to be the source root configured by Gradle. This matches the conventional directory layout used by Gradle. Note that this means that src, main, and java are not Java packages. Any type directly in the java folder is in the "unnamed" package. So, if your Gradle project is using src/main/java as the source root, then none of your classes should have a package statement at all, let alone one declaring the package as main.java.

    Your second screenshot indicates, again based on the folder's icon, that you told IntelliJ to use src as the source root (not src/main/java as you claim). This does make main.java a Java package. If src is supposed to be the source root, then your build.gradle file should have something like the following:

    sourceSets {
      main {
        java.srcDirs = ['src']
      }
    }
    

    If you do not have that (or similar) then all the package main.java statements are incorrect and IntelliJ is correctly complaining about the source code. As for why Gradle would still be able to compile the project without the above sourceSets configuration, that's because the Java compiler doesn't really care if the package structure matches the directory structure, at least not when all needed source files are passed to it (which is what Gradle is doing under the hood). IntelliJ, however, sees that the package and directory structures don't match and thus complains.

    In short, based on the information you've provided, there are at least three plausible scenarios:

    1. IntelliJ is importing the project correctly but your source files have erroneous package main.java statements.

    2. IntelliJ is importing the project "incorrectly" because your build.gradle file is missing the source directory configuration shown above.

    3. IntelliJ is importing the project correctly but your source files should be under src/main/java/main/java. The starting src/main/java part would be the source root and the subsequent main/java part would be the packages. This is the least likely scenario of the three in my opinion.

    I would guess the first scenario is what happened, particularly since main.java is a very unusual package name. Perhaps whoever was writing the code didn't understand how Gradle's organization of the source code and Java packages interacted. Or perhaps the code editor they used to write the code didn't recognize the project as a Gradle project and erroneously thought src was the source root (and since the code will still compile via Gradle, the programmer didn't realize the mistake).

    If you want Gradle and IntelliJ to see the project the same way, then you should either (1) remove all the package statements or (2) add the aforementioned configuration to your build.gradle file.