Home > Net >  Drools fat jar nullpointer KieServices
Drools fat jar nullpointer KieServices

Time:12-15

I'm generating a fat jar of my project using sbt assembly. Then, when trying to run my jar file, i get a nullpointer on this line:

val kieServices: KieServices = KieServices.Factory.get
val kieContainer: KieContainer = kieServices.getKieClasspathContainer

I've already tried adding a kie.conf, but this does not help. I am not using maven or a pom file etc. And am using scala sbt.

Running drools' latest version.

build.sbt:

ThisBuild / version := "0.1.0-SNAPSHOT"

ThisBuild / scalaVersion := "2.13.10"

lazy val root = (project in file("."))
  .settings(
    name := "untitled",
    libraryDependencies   = Seq(
      "org.drools" % "drools-core" % "8.31.1.Final",
      "org.drools" % "drools-compiler" % "8.31.1.Final",
      "org.drools" % "drools-decisiontables" % "8.31.1.Final",
      "org.drools" % "drools-mvel" % "8.31.1.Final",
      "org.drools" % "drools-model-compiler" % "8.31.1.Final",
      "org.kie" % "kie-api" % "8.31.1.Final"
    ),
    resolvers in Global   = Seq(
      "Sbt plugins" at "https://dl.bintray.com/sbt/sbt-plugin-releases",
    ),
    Compile / packageBin / mainClass := Some("src.Main"),
    Compile / run / mainClass := Some("src.Main")
  )
  .settings(
    assembly / assemblyJarName := "myJar.jar",
    assembly / assemblyMergeStrategy := {
      case PathList("META-INF", xs@_*) => MergeStrategy.discard
      case _ => MergeStrategy.first
    },
  )

project/plugins.sbt

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.15.0")

src/main/scala/src/Main.scala (sorry not sorry):

package src

import org.kie.api.KieServices
import org.kie.api.runtime.KieContainer

object Main extends App {
  val kieServices: KieServices = KieServices.Factory.get
  val kieContainer: KieContainer = kieServices.getKieClasspathContainer
}

CodePudding user response:

Debugging shows that

import scala.jdk.CollectionConverters._

ServiceLoader.load(classOf[KieServices], classOf[KieServices].getClassLoader)
 .asScala.size

is 1 when I do sbt run but 0 when I do java -jar myJar.jar.

In the former case KieServices.Factory.get returns org.drools.compiler.kie.builder.impl.KieServicesImpl@...some...hashcode... but in the latter case it returns null.

Try to add a file src/main/resources/META-INF/services/org.kie.api.KieServices with content

org.drools.compiler.kie.builder.impl.KieServicesImpl

One more issue is that, on contrary to sbt package, sbt assembly is missing this file from the assembly jar. So try to unpack myJar.jar, put manually this file as myJar.jar/META-INF/services/org.kie.api.KieServices and zip the jar back (myJar.jar/META-INF/MANIFEST.MF should exist but myJar.jar/META-INF/services is probably missing: https://github.com/sbt/sbt-assembly/issues/11)

java.util.ServiceLoader.load() function is useless and only returns empty result

How to include a config file in the "META-INF/services" folder of a JAR using Maven


It's missing from assembly jar because of

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

in your build.sbt. So modify the strategy:

assembly / assemblyMergeStrategy := {
  case PathList("META-INF", "services", "org.kie.api.KieServices") => MergeStrategy.concat
  case PathList("META-INF", xs@_*) => MergeStrategy.discard
  case _ => MergeStrategy.first
}

and service file will be included into assembly jar.


Actually, the service file already exists in the dependency: ~/.cache/coursier/v1/https/repo1.maven.org/maven2/org/drools/drools-compiler/8.31.1.Final/drools-compiler-8.31.1.Final.jar:META-INF/services/org.kie.api.KieServices

So you shouldn't add it manually, just do case PathList("META-INF", "services", "org.kie.api.KieServices") => MergeStrategy.concat.

There are different service files in drools-compiler-8.31.1.Final.jar:META-INF/services/ so be careful with case PathList("META-INF", xs@_*) => MergeStrategy.discard, it's possible you'll have more problems later if you ignore service files.


Try

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