scalaakkaakka-httpsbt-assemblyuberjar

Scala Akka Http : com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'dispatcher'


Creating API using scala Akka, code is running in IDE but when jar is created not able to run the code: usind scala 2.11.12 and Below is build.sbt

ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / scalaVersion := "2.11.12"

lazy val root = (project in file("."))
  .settings(
    name := "JNPM_SCALA_DATA_API",
    // Ensure that the IDE-specific settings like 'idePackagePrefix' are necessary or correctly configured.
    idePackagePrefix := Some("org.jio.jnpm"),
    // Adding resolver within project settings
    resolvers += "Typesafe Repo" at "https://repo.typesafe.com/typesafe/releases/",
    // Library dependencies
    libraryDependencies ++= Seq(
      "com.typesafe.akka" %% "akka-http" % "10.0.15",  // Updated to stable version
      "com.typesafe.akka" %% "akka-actor" % "2.4.20",
      "com.typesafe.akka" %% "akka-stream" % "2.4.20",
      "com.typesafe.akka" %% "akka-http-spray-json" % "10.0.15"  // JSON library for Akka HTTP
    ),
    // Assembly settings
//    assembly / assemblyMergeStrategy := {
//      case PathList("META-INF", xs @ _*) => MergeStrategy.discard
//      case "application.conf" => MergeStrategy.concat
//      case _ => MergeStrategy.first
//    }
//  )
    assembly / assemblyMergeStrategy := {
      case PathList("META-INF", xs @ _*) => MergeStrategy.discard
      case "application.conf" => MergeStrategy.concat
      case _ => MergeStrategy.first
    }
  )

Below is application.conf:

akka {
  loglevel = "INFO"
  actor {
    default-dispatcher {
      type = "Dispatcher"
      executor = "fork-join-executor"
      fork-join-executor {
        parallelism-min = 2
        parallelism-factor = 2.0
        parallelism-max = 10
      }
    }
  }
  stream {
    materializer {
      initial-input-buffer-size = 16
      max-input-buffer-size = 128
    }
  }
}

Main method :

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.model.{HttpResponse, StatusCodes}
import akka.http.scaladsl.model.StatusCodes._
import akka.http.scaladsl.server.Route
import models.{JsonSupport, ReportPayload}

import scala.concurrent.ExecutionContextExecutor
import akka.stream.ActorMaterializerSettings
import akka.http.scaladsl.server.RouteResult.route2HandlerFlow
import com.typesafe.config.ConfigFactory

object WebServer extends JsonSupport{
  def main(args: Array[String]): Unit = {

    implicit val system: ActorSystem = ActorSystem("akkaHttpServer", ConfigFactory.load())

    println("Dispatcher Config: " + system.settings.config.getConfig("akka.actor.default-dispatcher"))

    val materializerSettings = ActorMaterializerSettings(system).withDispatcher("akka.actor.default-dispatcher") //default-dispatcher
    implicit val materializer: ActorMaterializer = ActorMaterializer(materializerSettings)(system)

    implicit val executionContext: ExecutionContextExecutor = system.dispatcher

    val route: Route = concat(

      get {
        path("hello") {
          complete(HttpResponse(OK, entity = "Hello from Akka HTTP!"))
        }
      },
      post {
        path("echo") {
          entity(as[String]) { body =>
            complete(HttpResponse(OK, entity = body))  // Echoes back the posted content
          }
        }
      },

      post {
        path("jnpm" / "pm" / "data" / "network_element") {
          entity(as[ReportPayload]) { reportPayload =>
            // Log received report details (simple console output for demonstration).
            println(s"Received report for user: ${reportPayload.user_id}")
            // Responds with a confirmation message.
            complete(StatusCodes.OK, s"Report for ${reportPayload.report_name} received and is being processed.")
          }
        }
      }
    )

    import akka.http.scaladsl.server.RouteResult._
    val bindingFuture = Http().bindAndHandle(route, "0.0.0.0", 8088)
    println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
    scala.io.StdIn.readLine() // Blocks here to keep the app running until the ENTER key is pressed.
    bindingFuture
      .flatMap(_.unbind()) // Disconnects the server from the port.
      .onComplete(_ => system.terminate()) // Shuts down the actor system to clean up resources.
  }
}

Getting below error :

Loading config from properties {java.runtime.name=Java(TM) SE Runtime Environment, sun.boot.library.path=C:\Program Files (x86)\Java\jre-1.8\bin, java.vm.version=25.371-b11, java.vm.vendor=Oracle Corporation, java.vendor.url=http://java.oracle.com/, path.separator=;, java.vm.name=Java HotSpot(TM) Client VM, file.encoding.pkg=sun.io, user.script=, user.country=IN, sun.java.launcher=SUN_STANDARD, sun.os.patch.level=, java.vm.specification.name=Java Virtual Machine Specification, user.dir=C:\SCALA_SPARK\JNPM_SCALA_DATA_API\target\scala-2.11, java.runtime.version=1.8.0_371-b11, java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment, java.endorsed.dirs=C:\Program Files (x86)\Java\jre-1.8\lib\endorsed, os.arch=x86, java.io.tmpdir=C:\Users\VIVEKA~1.DES\AppData\Local\Temp\, line.separator=
, java.vm.specification.vendor=Oracle Corporation, user.variant=, os.name=Windows 11, sun.jnu.encoding=Cp1252, java.library.path=C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files (x86)\Common Files\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Program Files\WindowsPowerShell\Scripts;C:\Windows\CCM;C:\Windows\CCM;C:\Windows\CCM;C:\Program Files (x86)\Enterprise Vault\EVClient\x64\;C:\Windows\CCM;C:\Windows\CCM;C:\Windows\CCM;C:\Users\Vivekanand.Desai\AppData\Local\Programs\Python\Python310\Scripts\;C:\Users\Vivekanand.Desai\AppData\Local\Programs\Python\Python310\;C:\Users\Vivekanand.Desai\AppData\Local\Programs\Python\Launcher\;C:\Users\Vivekanand.Desai\AppData\Local\Microsoft\WindowsApps;C:\apps\hadoop\bin;C:\apps\spark-3.5.0-bin-hadoop3\spark-3.5.0-bin-hadoop3\bin;C:\apps\spark-3.5.0-bin-hadoop3\spark-3.5.0-bin-hadoop3\sbin;C:\Java\jre-8u202-windows-x64\jre1.8.0_202\bin;;., java.specification.name=Java Platform API Specification, java.class.version=52.0, sun.management.compiler=HotSpot Client Compiler, os.version=10.0, user.home=C:\Users\Vivekanand.Desai, user.timezone=, java.awt.printerjob=sun.awt.windows.WPrinterJob, file.encoding=Cp1252, java.specification.version=1.8, user.name=Vivekanand.Desai, java.class.path=JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar, java.vm.specification.version=1.8, sun.arch.data.model=32, java.home=C:\Program Files (x86)\Java\jre-1.8, sun.java.command=JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar, java.specification.vendor=Oracle Corporation, user.language=en, awt.toolkit=sun.awt.windows.WToolkit, config.trace=loads, java.vm.info=mixed mode, java.version=1.8.0_371, java.ext.dirs=C:\Program Files (x86)\Java\jre-1.8\lib\ext;C:\Windows\Sun\Java\lib\ext, sun.boot.class.path=C:\Program Files (x86)\Java\jre-1.8\lib\resources.jar;C:\Program Files (x86)\Java\jre-1.8\lib\rt.jar;C:\Program Files (x86)\Java\jre-1.8\lib\jsse.jar;C:\Program Files (x86)\Java\jre-1.8\lib\jce.jar;C:\Program Files (x86)\Java\jre-1.8\lib\charsets.jar;C:\Program Files (x86)\Java\jre-1.8\lib\jfr.jar;C:\Program Files (x86)\Java\jre-1.8\classes, sun.stderr.encoding=cp437, java.vendor=Oracle Corporation, java.specification.maintenance.version=4, file.separator=\, java.vendor.url.bug=http://bugreport.sun.com/bugreport/, sun.cpu.endian=little, sun.io.unicode.encoding=UnicodeLittle, sun.stdout.encoding=cp437, sun.desktop=windows, sun.cpu.isalist=}
Loading config from resource 'application.conf' URL jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/application.conf from class loader sun.misc.Launcher$AppClassLoader@647e05
Loading config from a URL: jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/application.conf
URL sets Content-Type: 'content/unknown'
'content/unknown' isn't a known content type
Loading config from class loader sun.misc.Launcher$AppClassLoader@647e05 but there were no resources called application.json
exception loading application.json: java.io.IOException: resource not found on classpath: application.json
Loading config from class loader sun.misc.Launcher$AppClassLoader@647e05 but there were no resources called application.properties
exception loading application.properties: java.io.IOException: resource not found on classpath: application.properties
Loading config from resource 'reference.conf' URL jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/reference.conf from class loader sun.misc.Launcher$AppClassLoader@647e05
Loading config from a URL: jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/reference.conf
URL sets Content-Type: 'content/unknown'
'content/unknown' isn't a known content type
Looking for 'version.conf' relative to ParseableResourceURL(jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/reference.conf)
Looking for 'version.json' relative to ParseableResourceURL(jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/reference.conf)
Looking for 'version.properties' relative to ParseableResourceURL(jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/reference.conf)
Loading config from resource 'version.conf' URL jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/version.conf from class loader sun.misc.Launcher$AppClassLoader@647e05
Loading config from a URL: jar:file:/C:/SCALA_SPARK/JNPM_SCALA_DATA_API/target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar!/version.conf
URL sets Content-Type: 'content/unknown'
'content/unknown' isn't a known content type
Loading config from class loader sun.misc.Launcher$AppClassLoader@647e05 but there were no resources called version.json
exception loading version.json: java.io.IOException: resource not found on classpath: version.json
Loading config from class loader sun.misc.Launcher$AppClassLoader@647e05 but there were no resources called version.properties
exception loading version.properties: java.io.IOException: resource not found on classpath: version.properties
Loading config from a String resizer.enabled=on
Dispatcher Config: Config(SimpleConfigObject({"executor":"fork-join-executor","fork-join-executor":{"parallelism-factor":2,"parallelism-max":10,"parallelism-min":2},"type":"Dispatcher"}))
Exception in thread "main" com.typesafe.config.ConfigException$Missing: No configuration setting found for key 'dispatcher'
        at com.typesafe.config.impl.SimpleConfig.findKeyOrNull(SimpleConfig.java:152)
        at com.typesafe.config.impl.SimpleConfig.findOrNull(SimpleConfig.java:170)
        at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:184)
        at com.typesafe.config.impl.SimpleConfig.find(SimpleConfig.java:189)
        at com.typesafe.config.impl.SimpleConfig.getString(SimpleConfig.java:246)
        at akka.stream.ActorMaterializerSettings$.apply(ActorMaterializer.scala:267)
        at akka.stream.ActorMaterializerSettings$.apply(ActorMaterializer.scala:258)
        at org.jio.jnpm.WebServer$.main(WebServer.scala:31)
        at org.jio.jnpm.WebServer.main(WebServer.scala)

Code run fine in IDE but not using jar file. It is looking for keyword dispatcher not sure where its is looking


Solution

  • Your assembly strategy is bad:

    assembly / assemblyMergeStrategy := {
      case PathList("META-INF", xs @ _*) => MergeStrategy.discard
      case "application.conf" => MergeStrategy.concat
      case _ => MergeStrategy.first
    }
    

    Remove this assembly / assemblyMergeStrategy section in build.sbt (then the default assembly strategy will be applied) and then

    sbt clean
    sbt assembly
    java -jar ./target/scala-2.11/JNPM_SCALA_DATA_API-assembly-0.1.0-SNAPSHOT.jar
    

    should work.

    The default sbt-assembly strategy is

      val defaultMergeStrategy: String => MergeStrategy = {
        case x if Assembly.isConfigFile(x) =>
          MergeStrategy.concat
        case PathList(ps @ _*) if Assembly.isReadme(ps.last) || Assembly.isLicenseFile(ps.last) =>
          MergeStrategy.rename
        case PathList("META-INF", xs @ _*) =>
          (xs map {_.toLowerCase}) match {
            case ("manifest.mf" :: Nil) | ("index.list" :: Nil) | ("dependencies" :: Nil) =>
              MergeStrategy.discard
            case ps @ (x :: xs) if ps.last.endsWith(".sf") || ps.last.endsWith(".dsa") =>
              MergeStrategy.discard
            case "plexus" :: xs =>
              MergeStrategy.discard
            case "services" :: xs =>
              MergeStrategy.filterDistinctLines
            case ("spring.schemas" :: Nil) | ("spring.handlers" :: Nil) =>
              MergeStrategy.filterDistinctLines
            case _ => MergeStrategy.deduplicate
          }
        case _ => MergeStrategy.deduplicate
      }
    

    https://github.com/sbt/sbt-assembly/blob/develop/README.md#merge-strategy

    https://github.com/sbt/sbt-assembly/blob/develop/src/main/scala/sbtassembly/MergeStrategy.scala#L185-L211

    For debugging you can use the strategy

    assembly / assemblyMergeStrategy := (_ => MergeStrategy.singleOrError)
    

    to see all duplicates:

    [error] SingleOrError found multiple files with the same target path:
    [error]   Jar name = akka-actor_2.11-2.4.20.jar, jar org = com.typesafe.akka, entry target = reference.conf
    [error]   Jar name = akka-http-core_2.11-10.0.15.jar, jar org = com.typesafe.akka, entry target = reference.conf
    [error]   Jar name = akka-http_2.11-10.0.15.jar, jar org = com.typesafe.akka, entry target = reference.conf
    [error]   Jar name = akka-stream_2.11-2.4.20.jar, jar org = com.typesafe.akka, entry target = reference.conf
    [error]   Jar name = ssl-config-core_2.11-0.2.1.jar, jar org = com.typesafe, entry target = reference.conf
    [error] SingleOrError found multiple files with the same target path:
    [error]   Jar name = akka-actor_2.11-2.4.20.jar, jar org = com.typesafe.akka, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = akka-http-core_2.11-10.0.15.jar, jar org = com.typesafe.akka, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = akka-http-spray-json_2.11-10.0.15.jar, jar org = com.typesafe.akka, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = akka-http_2.11-10.0.15.jar, jar org = com.typesafe.akka, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = akka-parsing_2.11-10.0.15.jar, jar org = com.typesafe.akka, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = akka-stream_2.11-2.4.20.jar, jar org = com.typesafe.akka, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = config-1.3.0.jar, jar org = com.typesafe, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = ssl-config-core_2.11-0.2.1.jar, jar org = com.typesafe, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = spray-json_2.11-1.3.4.jar, jar org = io.spray, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = reactive-streams-1.0.0.jar, jar org = org.reactivestreams, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = scala-java8-compat_2.11-0.7.0.jar, jar org = org.scala-lang.modules, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = scala-parser-combinators_2.11-1.0.4.jar, jar org = org.scala-lang.modules, entry target = META-INF/MANIFEST.MF
    [error]   Jar name = scala-library-2.11.12.jar, jar org = org.scala-lang, entry target = META-INF/MANIFEST.MF
    

    So your duplicates are several reference.conf and META-INF/MANIFEST.MF files. Apparently, using MergeStrategy.first for reference.conf you removed dispatcher somewhere. That was the reason of error.

    When the above default strategy is not enough it's better to express custom strategy partially reusing the default one:

    assembly / assemblyMergeStrategy := {
      case ... => ... // additional cases
      case x   =>
        // default strategy
        val oldStrategy = (assembly / assemblyMergeStrategy).value 
        oldStrategy(x)
    }
    

    The minimal strategy closest to yours is

    assembly / assemblyMergeStrategy := {
      case PathList("META-INF", xs @ _*) => MergeStrategy.discard
      case "reference.conf" => MergeStrategy.concat
      case _ => MergeStrategy.singleOrError
    }
    

    Using custom strategies inaccurately (for example using MergeStrategy.discard, MergeStrategy.first/MergeStrategy.last not selectively) can lead to many (sometimes weird) issues:

    SBT assembly output 0xEFBFBD instead of 0xCAFEBABE in class file

    sbt-assembly and Lucene "An SPI class of type org.apache.lucene.codecs.Codec with name 'Lucene94' does not exist.¨ exception

    Drools fat jar nullpointer KieServices

    Run Drools Kie project from fat jar

    sbt-assembly: deduplication found error