javaspring-bootapache-sparkapache-spark-sql

java.lang.NoClassDefFoundError: jakarta/servlet/SingleThreadModel - Error while using apache spark 4.0-preview1


We are trying to migrate our existing Spark analysis engine to Java 17 with Springboot 3.2.5. As I understand this requires a latest version of Spark (v4.0-preview). However, we are getting the above error while creating a SparkSesison object as shown below:

this.sparkSession = SparkSession.builder()
                        .appName("Spark Session")
                        .master("local[*]")
                        .getOrCreate();

Following is the stack trace:

java.lang.NoClassDefFoundError: jakarta/servlet/SingleThreadModel
    at org.sparkproject.jetty.servlet.ServletHolder.setServlet(ServletHolder.java:173) ~[spark-core_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at org.sparkproject.jetty.servlet.ServletHolder.<init>(ServletHolder.java:120) ~[spark-core_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at org.apache.spark.ui.JettyUtils$.createServletHandler(JettyUtils.scala:121) ~[spark-core_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at org.apache.spark.ui.SparkUI.<init>(SparkUI.scala:69) ~[spark-core_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at org.apache.spark.ui.SparkUI$.create(SparkUI.scala:248) ~[spark-core_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at org.apache.spark.SparkContext.<init>(SparkContext.scala:515) ~[spark-core_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at org.apache.spark.SparkContext$.getOrCreate(SparkContext.scala:2965) ~[spark-core_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at org.apache.spark.sql.SparkSession$Builder.$anonfun$getOrCreate$2(SparkSession.scala:1122) ~[spark-sql_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at scala.Option.getOrElse(Option.scala:201) ~[scala-library-2.13.14.jar:?]
    at org.apache.spark.sql.SparkSession$Builder.getOrCreate(SparkSession.scala:1116) ~[spark-sql_2.13-4.0.0-preview1.jar:4.0.0-preview1]
    at com.vislesha.jobengine.config.AnalysisExecutionJobConfig.lambda$setSparkSessionTask$0(AnalysisExecutionJobConfig.java:54) ~[classes/:?]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:388) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:312) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:140) ~[spring-tx-6.1.6.jar:6.1.6]
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:255) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:82) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:369) ~[spring-batch-infrastructure-5.1.1.jar:5.1.1]
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:206) ~[spring-batch-infrastructure-5.1.1.jar:5.1.1]
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:140) ~[spring-batch-infrastructure-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:240) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:229) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:153) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.job.AbstractJob.handleStep(AbstractJob.java:418) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.job.SimpleJob.doExecute(SimpleJob.java:132) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:317) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:157) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:148) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at org.springframework.batch.core.launch.support.TaskExecutorJobLauncher.run(TaskExecutorJobLauncher.java:59) ~[spring-batch-core-5.1.1.jar:5.1.1]
    at com.vislesha.JobEngineApplication$1.run(JobEngineApplication.java:43) ~[classes/:?]
    at org.springframework.boot.SpringApplication.lambda$callRunner$4(SpringApplication.java:786) ~[spring-boot-3.2.5.jar:3.2.5]
    at org.springframework.util.function.ThrowingConsumer$1.acceptWithException(ThrowingConsumer.java:83) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.util.function.ThrowingConsumer.accept(ThrowingConsumer.java:60) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.util.function.ThrowingConsumer$1.accept(ThrowingConsumer.java:88) ~[spring-core-6.1.6.jar:6.1.6]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-3.2.5.jar:3.2.5]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:786) ~[spring-boot-3.2.5.jar:3.2.5]
    at org.springframework.boot.SpringApplication.lambda$callRunners$3(SpringApplication.java:774) ~[spring-boot-3.2.5.jar:3.2.5]
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183) [?:?]
    at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) [?:?]
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:510) [?:?]
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) [?:?]
    at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150) [?:?]
    at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173) [?:?]
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) [?:?]
    at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596) [?:?]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:774) [spring-boot-3.2.5.jar:3.2.5]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:341) [spring-boot-3.2.5.jar:3.2.5]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1354) [spring-boot-3.2.5.jar:3.2.5]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) [spring-boot-3.2.5.jar:3.2.5]
    at com.vislesha.JobEngineApplication.main(JobEngineApplication.java:32) [classes/:?]
Caused by: java.lang.ClassNotFoundException: jakarta.servlet.SingleThreadModel
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ~[?:?]
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) ~[?:?]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525) ~[?:?]
    ... 50 more

Request someone to provide a solution!


Solution

  • tl;dr

    The SingleThreadModel interface was dropped from Servlet 6.0 after two decades of deprecation.

    Spring Boot 3 relies upon Jakarta Servlet 6.0, per Release Notes. Hence your error: That interface no longer exists.

    ➡️ You absolutely must write your servlet’s code to be thread-safe. Ditto for any libraries you call upon.

    SingleThreadModel dropped from Servlet 6+

    Servlet 2.4

    The javax.servlet.SingleThreadModel interface was deprecated in Java Servlet API 2.4, with no direct replacement, on 24 Nov, 2003.

    Servlet 5

    In Servlet 5, the package name changed to jakarta.servlet.SingleThreadModel. The javax. changed to jakarta..

    This package renaming happened as part of the transition when Oracle donated Java EE technologies to the Eclipse Foundation to become Jakarta EE.

    Servlet 6.0

    In Servlet 6.0 and later, the interface was dropped from the specification and API. To quote from the spec page outlining changes:

    Remove API classes and methods that were deprecated in Servlet 5.0 and earlier. This includes removing the SingleThreadModel and HttpSessionContext interfaces and the HttpUtils class as well as various deprecated methods

    See Issue # 418 Remove deprecated code.