Search code examples
javadockermavenjetty

Running Java Maven project using Jetty docker image


I am having a simple java maven project which generates some user Ids for a given GET request. I am using javax.servlet package.

Everything works fine when I am packaging and deploying the war file in local jetty server.

However things are not working when I am using the docker jetty image and deploying the war file. I am getting the below error

MacBook-Pro-3:UIDGenerators unbxd$ docker run 0xvoila/uid-generator:latest 
2022-07-03 17:50:09.448:INFO :oejs.Server:main: jetty-11.0.11; built: 2022-06-21T21:42:55.454Z; git: 58487315cb75e0f5c81cc6fa50096cbeb3b9554e; jvm 17.0.3+7
2022-07-03 17:50:09.523:INFO :oejdp.ScanningAppProvider:main: Deployment monitor [file:///var/lib/jetty/webapps/]
2022-07-03 17:50:10.234:INFO :oejss.DefaultSessionIdManager:main: Session workerName=node0
2022-07-03 17:50:10.291:WARN :oejw.WebAppContext:main: Failed startup of context o.e.j.w.WebAppContext@4f67eb2a{Archetype Created Web Application,/uid-generator,file:///tmp/jetty-0_0_0_0-8080-uid-generator_war-_uid-generator-any-15856705197144621036/webapp/,UNAVAILABLE}{/var/lib/jetty/webapps/uid-generator.war}
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServlet
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1012)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
    at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:524)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:427)
    at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:421)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:712)


Here is my pom.xml file

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.amit.system</groupId>
  <artifactId>UIDGenerators</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>UIDGenerators Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>uid-generator</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>

<!--        <plugin>-->
<!--          <groupId>org.eclipse.jetty</groupId>-->
<!--          <artifactId>jetty-maven-plugin</artifactId>-->
<!--          <version>9.4.28.v20200408</version>-->
<!--        </plugin>-->

      </plugins>
    </pluginManagement>
  </build>
</project>

Here is my Dockerfile

FROM maven as build

COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package


FROM jetty:latest
COPY --from=build /home/app/target/uid-generator.war /var/lib/jetty/webapps
CMD java -jar "$JETTY_HOME/start.jar"

I tried to debug myself and it seems like javax. servlet is not present in the jetty docker image. But in my pom.xml file I had given javax.servlet as dependencies.

Can anyone help me with the solution.

UPDATED

Here is the java code

package org.amit.system;

import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class UIDGenerator extends HttpServlet {

    int sequence = 0;
    final static int sequenceBits = 12; // max is 4096
    final static int maxSequence = (int)Math.pow(2, sequenceBits) - 1;

    final static int nodeId = 11;
    final static int nodeBits = 10; // max is 1024

    public synchronized int generateSequence(long runningMillisecond){

        this.sequence = this.sequence + 1;

        if (this.sequence >= maxSequence && runningMillisecond == System.currentTimeMillis()){
            waitOneMillisecond(runningMillisecond);
            this.sequence = 0;
        }

        return this.sequence;
    }

    private void waitOneMillisecond(long runningMillisecond){

        while(runningMillisecond == System.currentTimeMillis()){
            continue;
        }
    }

    public int generateNodeId(){
        return this.nodeId;
    }

    public void run(){
        int nodeNumber = this.generateNodeId();

        long epoch = System.currentTimeMillis();
        int sequence = this.generateSequence(epoch);

//        System.out.println("Echo before shift " + epoch);
        epoch = epoch << (this.nodeBits + this.sequenceBits);
        epoch = epoch | nodeNumber << this.sequenceBits;
        epoch = epoch | sequence;

        System.out.println("Echo after shift " + epoch);
    }



    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException
    {
        int nodeNumber = this.generateNodeId();

        long epoch = System.currentTimeMillis();
        int sequence = this.generateSequence(epoch);

        epoch = epoch << (this.nodeBits + this.sequenceBits);
        epoch = epoch | nodeNumber << this.sequenceBits;
        epoch = epoch | sequence;

        response.getOutputStream().print("Echo after shift " + epoch);

    }
}

Solution

  • Jetty 9 is at End of Community Support.

    See: https://github.com/eclipse/jetty.project/issues/7958

    You should upgrade, to at least Jetty 10.

    The problem you have is the combination of jetty-11.0.11 and javax/servlet/http/HttpServlet.

    Jetty 11 supports Servlet 5.0, which underwent the Jakarta "Big Bang" and changed namespace to jakarta.servlet.*

    See Past Question for details (including table in accepted answer for support levels for the combination of Jetty version, Servlet Spec version, EE governing body, and Servlet namespace)