I'm setting up a new multi-module project (sbt/scala/play/IntejjiJ) and I would like to have two things:
project
|_Dependencies.scala
|_plugin.sbt
modules
|_adapters
|_api (Play REST API)
|_app
|_conf
|_infrastructure (bare bone scala)
|-src/main/scala
|_application (bare bone scala)
|_src/main/scala
|_domain (bare bone scala)
|_src/main/scala
|_query (bare bone scala)
|_src/main/scala
build.sbt
So far, I'm getting the following error when I run the application using Play2 Run/Debug Configuration settings:
[error] java.lang.RuntimeException: No main class detected.
[error] at scala.sys.package$.error(package.scala:26)
[error] (Compile / bgRun) No main class detected.
[error] Total time: 2 s, completed Jun 1, 2019 11:21:31 PM
Here is what I have so far:
build.sbt
import Dependencies._
lazy val commonSettings = Seq(
organization := "com.borkke.rally",
version := "0.1.0-SNAPSHOT",
scalaVersion := "2.12.8",
scalacOptions := Seq(
"-deprecation",
"-feature"
),
libraryDependencies ++= CommonDependencies
)
//PROJECTS
lazy val rally = project
.in(file("."))
.aggregate(domain,application,query,api,infrastructure)
.settings(
name := "rally",
commonSettings,
publishArtifact := false
)
lazy val api = project
.in(file("modules/adapter/api"))
.enablePlugins(PlayScala)
.dependsOn(domain,application,query,infrastructure)
.settings(
name := "api",
commonSettings,
libraryDependencies ++= ApiDependencies
)
lazy val domain = project
.in(file("modules/domain"))
.settings(
name := "domain",
commonSettings
)
lazy val application = project
.in(file("modules/application"))
.dependsOn(domain)
.settings(
name := "application",
commonSettings
)
lazy val query = project
.in(file("modules/query"))
.settings(
name := "query",
commonSettings
)
lazy val infrastructure = project
.in(file("modules/adapter/infrastructure"))
.dependsOn(domain)
.settings(
name := "infrastructure",
commonSettings,
libraryDependencies ++= InfrastructureDependencies
)
Dependencies.scala
import sbt._
import play.sbt.PlayImport._
object Dependencies {
private val scalatest_version = "3.0.5"
private val v2Db_version = "1.4.198"
private val logback_version = "5.3"
private val play_version = "2.7.2"
private val cassandra_driver_version = "3.7.1"
private val postgresql_driver_version = "42.2.5"
private val kafka_client_version = "2.2.0"
private val scalatest = "org.scalatest" %% "scalatest" % scalatest_version
private val scalatic = "org.scalactic" %% "scalactic" % scalatest_version
private val h2Db = "com.h2database" %% "h2" % v2Db_version
private val logback = "net.logstash.logback" % "logstash-logback-encoder" % logback_version
private val play = "com.typesafe.play" %% "play" % play_version
private val cassandra_driver = "com.datastax.cassandra" % "cassandra-driver-extras" % cassandra_driver_version
private val postgresql_driver = "org.postgresql" % "postgresql" % postgresql_driver_version
private val kafka_client = "org.apache.kafka" %% "kafka" % kafka_client_version
lazy val CommonDependencies = Seq(scalatic, scalatest % "test", logback, guice)
lazy val InfrastructureDependencies = Seq(cassandra_driver, postgresql_driver, kafka_client)
lazy val ApiDependencies = Seq(play)
}
plugin.sbt
logLevel := Level.Warn
//wrapper around play console.
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.7.2")
//dependency resolver. parallel downloads
addSbtPlugin("io.get-coursier" % "sbt-coursier" % "1.1.0-M11")
//shows available updates. dependencyUpdates || dependencyUpdatesReport
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.4.0")
//create one jar for application.
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.5")
//linter
addSbtPlugin("org.wartremover" % "sbt-wartremover" % "2.2.1")
Run Configuration
Consider changing the build structure such that api
is moved to become the root project like so:
lazy val api = project
.in(file("."))
.enablePlugins(PlayScala)
.aggregate(domain,application,query,infrastructure)
.dependsOn(domain,application,query,infrastructure)
.settings(
name := "api",
commonSettings,
publishArtifact := false,
libraryDependencies ++= ApiDependencies
)
This means modules/adapters/api
is moved to the project root directory, and lazy val root = ...
is deleted from build.sbt
, such that the directory structure becomes
.
├── app
│ ├── controllers
│ ├── filters
│ ├── services
│ └── views
├── build.sbt
├── conf
│ ├── application.conf
│ ├── logback.xml
│ └── routes
├── modules
│ ├── adapters
│ │ └── infrastructure
│ ├── application
│ │ ├── src
│ ├── domain
│ │ ├── src
│ └── query
│ ├── src
├── project
│ ├── Dependencies.scala
│ ├── build.properties
│ ├── plugins.sbt
│ ├── project
│ └── target
This should make the Play 2 App
run configuration work again, although make sure Play compiler is enabled by checking:
Preferences | Languages & Frameworks | Play2 | Compiler | Use Play 2 compiler for this project
If preferring to keep the original structure, then as a workaround, try defining sbt Task
run configuration instead of Play 2 App
, as documented in official docs:
Run | Edit Configurations
+
to add a new configuration sbt Task
tasks
input box put api/run
Background context, feel free to skip:
The most recent version of Intellij runs into route compile issues when using sbt task
run configs as defined on the Play2 documentation. So I wanted to use the Play 2 App
run config as an alternative.
While Mario's solution works it isn't an option for those who cannot move base directory. Trying to use the Play 2 App
run config results in a No main class detected
similar to what Aleksandar experienced in the comments of the opening question.
To use Play 2 App
run configs you have to:
Specify projects in build.sbt
as you would normally.
Specify the Play2 module and the project uri to the project with your build.sbt
. Unless altered in step 1, this will be the Play2 default: Project name and project root respectively.
Setting in question found here:
File | Settings | Languages & Frameworks | Play2
As seen in the screenshot below, I also check Use Play 2 compiler for this project
Create a Play 2 App
run configuration and specify the Play 2 module
as the module with your main class method.
Debug port should be the one specified in your settings for your breakpoint listener. No need to change by default.
Run your newly created run configuration. Log output should look similar to that of running sbt via bash. Example below.
If it's failing to start, ensure that you don't have duplicate declarations of JVM params across default settings in Scala and JVM.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With