javaintellij-ideasbtimmutables-library

intelliJ IDEA support for immutables with sbt


When using the java immutables library with IDEA and sbt, compilation and running code works fine, but the editor will give "Cannot resolve symbol ..." and "Cannot resolve method ..." errors when using the generated classes.

Following the documentation for setting up IDEs works fine for Maven, but doesn't solve the issues for sbt.

How can we get editor support and code completion working for generated sources on IDEA with sbt?


Solution

  • First, do follow the instructions in the documentation.

    To configure annotation processing in IntelliJ IDEA, use dialog Preferences > Project Settings > Compiler > Annotation Processors.

    Next, the issue is that sbt is putting our generated source files in target/scala-2.n/classes/our/package. This is the directory for compiled .class files, so we need our sources to generated elsewhere. Editing IDEA settings won't help us here, so we need to edit build.sbt by adding the following:

    // tell sbt (and by extension IDEA) that there is source code in target/generated_sources
    managedSourceDirectories in Compile += baseDirectory.value / "target" / "generated_sources"
    // before compilation happens, create the target/generated_sources directory
    compile in Compile <<= (compile in Compile).dependsOn(Def.task({
      (baseDirectory.value / "target" / "generated_sources").mkdirs()
    }))
    // tell the java compiler to output generated source files to target/generated_sources
    javacOptions in Compile ++= Seq("-s", "target/generated_sources")
    

    Finally we need to tell IDEA that not everything in target/ should be ignored, by removing the exclusion on that directory. Either go to file > Project Structure > Project Settings > Modules, click the target directory and unselect "Excluded". Or, right click the target directory under the Project tab, Mark Directory As > Cancel Exclusion.

    At this point you should see editor support working, and if not, run sbt clean compile to ensure the sources were generated.


    Update: The <<= syntax has been removed in recent sbt versions, you can replace the second directive above with

    // before compilation happens, create the target/generated_sources directory
    compile in Compile := (compile in Compile).dependsOn(Def.task({
      (baseDirectory.value / "target" / "generated_sources").mkdirs()
    })).value