0

I was wondering why scala doesn't need -jar, while java does, when executing a .jar file?

For example:

scala target/some.jar

java -jar target/someother.jar

I look at the scala shell script, it invokes java as:

execCommand \
  "${JAVACMD:=java}" \
  $JAVA_OPTS \
  "${java_args[@]}" \
  "${classpath_args[@]}" \
  -Dscala.home="$SCALA_HOME" \
  $OVERRIDE_USEJAVACP \
  $WINDOWS_OPT \
   scala.tools.nsc.MainGenericRunner  "$@"

Is it correct that scala passes target/some.jar as part "$@" to java, and therefore the java command doesn't prefix target/some.jar with -jar?

Thanks.

Tim
  • 1
  • 141
  • 372
  • 590

1 Answers1

5

Analysing the source code of MainGenericRunner we see scala runner tries to guess what the user intended

  def runTarget(): Option[Throwable] = howToRun match {
    case AsObject =>
      ObjectRunner.runAndCatch(settings.classpathURLs, thingToRun, command.arguments)
    case AsScript if isE =>
      ScriptRunner(settings).runScriptText(combinedCode, thingToRun +: command.arguments)
    case AsScript =>
      ScriptRunner(settings).runScript(thingToRun, command.arguments)
    case AsJar    =>
      JarRunner.runJar(settings, thingToRun, command.arguments)
    case Error =>
      None
    case _  =>
      ...
  }

where howToRun potentially calls guessHowToRun

  private def guessHowToRun(target: String): GenericRunnerCommand.HowToRun = {
    if (!ok) Error
    else if (io.Jar.isJarOrZip(target)) AsJar
    else if (ScalaClassLoader.classExists(settings.classpathURLs, target)) AsObject
    else {
      val f = io.File(target)
      if (!f.hasExtension("class", "jar", "zip") && f.canRead) AsScript
      else {
        Console.err.println("No such file or class on classpath: " + target)
        Error
      }
    }
  }

We can be explicit by providing -howtorun flag:

scala -howtorun:jar some.jar

Scala apps can also be run via java -jar, for example, if we specify the main class in build.sbt

Compile / mainClass := Some("example.MyMain")

and execute sbt assembly, then the produced fat jar under target/ can be executed like so

java -jar myapp-assembly.jar
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • 1
    just to add, when invoking `java`, the command is designed to run compiled class at first, so with smth like `java Xyz.jar` it doesn't automatically discover the jar file (thats why the `-jar` option is required). Furthermore, the jar or class without other dependencies in classpath would run only with standard API classes. In newer (9 maybe) versions of Java it's possible to run a `.java` file, so its compiled just before execution. (when using java cmd with noncompiled `.java` file its possible to extend classpath with standard `-cp`) – itwasntme Mar 18 '20 at 00:53
  • 1
    I'd also would like to add that "look at the scala shell script" isn't simply invoking `scala` or `java` command but it determines lots of additional arguments to desired command so it would be able to get required classpath and options for called file and later it calls generic runner to determine how to run given file. Anyway, your answer is good :) – itwasntme Mar 18 '20 at 02:21