scalaintellij-ideaprogram-entry-point

In IntelliJ(2024.1.1) with the Scala Plugin(2024.1.20), Main.main is Failing with "Could not find or load main class org.public_domain.main"


UPDATE: Nestled deep within the large accepted answer is the way to fix this; i.e. rename the method from main to something else, or rename the object Main to something else.

The conflict is a case insensitivity issue on the Windows (or MacOS) file system where having both the object and the @main marked method be the same case-insensitive value creates an issue.

Hopefully, the IntelliJ Scala Plugin guys can add this to their awesome "automated warnings system", so no one else falls into this Scala 3 rabbit hole.


UPDATE Older: Upon further investigation...This works in Scastie strongly suggesting it is an IntelliJ Scala Plugin issue (Jetbrains YouTrack ticket).


After creating a new Scala 3.3.3 project in IntelliJ(2024.1.1) with the Scala Plugin(2024.1.20), my "braceless syntax" Main.main method is failing with "Could not find or load main class org.public_domain.main".

I must be missing something totally obvious. However, after an hour of tinkering with it, I give up. What am I missing?

Here's the ONLY file I've created in the entire project, and upon which I clicked the small green arrow in the left tray of the main method to select "Run org.public_domain.main".

package org.public_domain

object Main:
  @main def main(): Unit =
    println("Hello World!")

SideNote: I'm noticing IntelliJ isn't properly referring to org.public_domain.Main.main as the method I am running.

BTW, if I comment out object Main: (which I very much do not want to do), it runs fine.

IOW, this works fine:

package org.public_domain

@main def main(): Unit =
  println("Hello World!")

Solution

  • package org.public_domain
    
    object Main:
      @main def main(): Unit =
        println("Hello World!")
    

    then this file Main.scala should be placed at /path/to/yourproject/src/main/scala/org/public_domain/Main.scala

    enter image description here

    $ sbt run
    [info] welcome to sbt 1.10.0 (Amazon.com Inc. Java 21.0.3)
    [info] loading global plugins from /home/dmitin/.sbt/1.0/plugins
    [info] loading project definition from /path/to/yourproject/project
    [info] loading settings for project root from build.sbt ...
    [info] set current project to yourproject (in build file:/path/to/yourproject/)
    [info] compiling 1 Scala source to /path/to/yourproject/target/scala-3.3.3/classes ...
    [warn] -- Warning: /path/to/yourproject/src/main/scala/org/public_domain/Main.scala:3:7 
    [warn] 3 |object Main:
    [warn]   |       ^
    [warn]   |object Main differs only in case from class main in package org.public_domain. Such classes will overwrite one another on case-insensitive filesystems.
    [warn] one warning found
    [info] running org.public_domain.main 
    Hello World!
    [success] Total time: 3 s, completed 18 мая 2024 г., 20:06:05
    

    enter image description here

    package org.public_domain
    
    object Main:
      @main def run(): Unit =
        println("Hello World!")
    
    $ cd target/scala-3.3.3/classes/org/public_domain
    $ ls
    main.class  Main.class  Main$.class  main.tasty  Main.tasty
    

    (or run.class instead of main.class if you renamed the method).

    enter image description here


    the IntelliJ Scala plugin is incorrectly invoking org.public_domain.main as opposed to correctly invoking org.public_domain.Main.main

    I'm glad if you resolved your issues but I'm afraid you could misinterpret your findings. At least I can see some confusion. There are several classes here: Main.class, Main$.class, main.class (or run.class if we renamed the method). Main.class and Main$.class represent the object, main.class represents the @main-annotated method. It's exactly the class org.public_domain.main that should be called (it has runnable method public static void main(java.lang.String[])), not org.public_domain.Main (it doesn't have main(String[])). You can see methods in classes with javap:

    $ cd /path/to/yourproject/target/scala-3.3.3/classes/org/public_domain/
    $ ls
    main.class  Main.class  Main$.class  main.tasty  Main.tasty
    
    $ cd /path/to/yourproject/target/scala-3.3.3/classes
    $ javap org.public_domain.Main
    Compiled from "Main.scala"
    public final class org.public_domain.Main {
      public static void main();
    }
    
    $ javap org.public_domain.Main$
    Compiled from "Main.scala"
    public final class org.public_domain.Main$ implements java.io.Serializable {
      public static final org.public_domain.Main$ MODULE$;
      public static {};
      public void main();
    }
    
    $ javap org.public_domain.main
    Compiled from "Main.scala"
    public final class org.public_domain.main {
      public org.public_domain.main();
      public static void main(java.lang.String[]);
    }
    

    If you run your code with IntelliJ IDEA rather than with sbt (I recommended the latter) then you can configure what to run in the menu Run -> Edit configurations

    enter image description here

    enter image description here

    enter image description here

    IntelliJ writes the exact command that is run:

    enter image description here

    By default it's collapsed. If you click it expands. For me it's

    /media/data/jdk1.8.0_351/bin/java -javaagent:/media/data/idea-IU-241.15989.150/lib/idea_rt.jar=38299:/media/data/idea-IU-241.15989.150/bin -Dfile.encoding=UTF-8 -classpath /media/data/jdk1.8.0_351/jre/lib/charsets.jar:/media/data/jdk1.8.0_351/jre/lib/deploy.jar:/media/data/jdk1.8.0_351/jre/lib/ext/cldrdata.jar:/media/data/jdk1.8.0_351/jre/lib/ext/dnsns.jar:/media/data/jdk1.8.0_351/jre/lib/ext/jaccess.jar:/media/data/jdk1.8.0_351/jre/lib/ext/jfxrt.jar:/media/data/jdk1.8.0_351/jre/lib/ext/localedata.jar:/media/data/jdk1.8.0_351/jre/lib/ext/nashorn.jar:/media/data/jdk1.8.0_351/jre/lib/ext/sunec.jar:/media/data/jdk1.8.0_351/jre/lib/ext/sunjce_provider.jar:/media/data/jdk1.8.0_351/jre/lib/ext/sunpkcs11.jar:/media/data/jdk1.8.0_351/jre/lib/ext/zipfs.jar:/media/data/jdk1.8.0_351/jre/lib/javaws.jar:/media/data/jdk1.8.0_351/jre/lib/jce.jar:/media/data/jdk1.8.0_351/jre/lib/jfr.jar:/media/data/jdk1.8.0_351/jre/lib/jfxswt.jar:/media/data/jdk1.8.0_351/jre/lib/jsse.jar:/media/data/jdk1.8.0_351/jre/lib/management-agent.jar:/media/data/jdk1.8.0_351/jre/lib/plugin.jar:/media/data/jdk1.8.0_351/jre/lib/resources.jar:/media/data/jdk1.8.0_351/jre/lib/rt.jar:/media/data/Projects2/scala3demo2/target/scala-3.3.3/classes:/home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.12/scala-library-2.13.12.jar:/home/dmitin/.cache/coursier/v1/https/repo1.maven.org/maven2/org/scala-lang/scala3-library_3/3.3.3/scala3-library_3-3.3.3.jar org.public_domain.main
    

    Now it can be shortened to

    $ cd /path/to/yourproject/target/scala-3.3.3/classes
    $ java -classpath .:/path_to_jars/scala-library-2.13.12.jar:/path_to_jars/scala3-library_3-3.3.3.jar org.public_domain.main
    
    Hello World!