Problem:
I'm trying to deploy a simple spring-boot (3.4) application on a pre-installed jetty-server (12.0.18). (The main reason is to keep the package small for both transfer and memory).
The war-file seems to be deployed (addressing the context results in something) but I can't address the endpoint (404).
The only description I found was with ChatGpt, Gemini and DeepSeek and all were quite similar. But I couldn't address the endpoint.
What I did and expectations
All three AIs recommended
- change packaging to WAR
- mark the embedded Jetty-dependency as provided
- extend SpringBootServletInitializer
- deploy the war to jetty 12
For the experiments I tried to deploy a minimal application with one endpoint as shown below:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns=".0.0" xmlns:xsi=";
xsi:schemaLocation=".0.0 .0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>springboot.jetty.deploy</groupId>
<artifactId>myDepTst</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>myDepTst</name>
<description>Deploy a spring-boot application on jetty</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<scope>provided</scope>
</dependency>
<!-- proposed by deepseek -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Main-class:
package springboot.jetty.deploy;
import .springframework.boot.SpringApplication;
import .springframework.boot.builder.SpringApplicationBuilder;
import .springframework.boot.web.servlet.support.SpringBootServletInitializer;
@.springframework.boot.autoconfigure.SpringBootApplication
public class SpringBootApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
System.out.println("### DeployOnJettyApplication.main: Deploy On Jetty");
SpringApplication.run(SpringBootApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.err.println("### DeployOnJettyApplication.configure");
return application.sources(SpringBootApplication.class);
}
}
A WebEndpoint for testing:
package springboot.jetty.deploy;
import jakarta.annotation.PostConstruct;
import .springframework.web.bind.annotation.GetMapping;
import .springframework.web.bind.annotation.RequestMapping;
import .springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/endpt")
public class WebEndpoint {
private int counter = 0;
@PostConstruct
public void init() {
System.out.println("### WebEndpoint.init()");
}
@GetMapping("tst")
public String tst() {
return "### WebEndpoint.tst() called %s-times".formatted(counter++);
}
}
Deploying to Jetty:
- Downloading jetty 12.0.8 and unpacking to .../jetty-home
- copy the built war-file to .../jetty-base/webapps/myDepTst.war
- as the needed modules aren't clear (yet) -- cd jetty-base -- java -jar .../jetty-home/start.jar --add-modules=ee10-demos
- fire up jetty: java -jar .../jetty-home/start.jar
In the logs I find:
2025-03-20 21:27:51.797:WARN :oejdp.ScanningAppProvider:main: class .eclipse.jetty.deploy.providers.ContextProvider@569bf9eb[file:///C:/temp/jetty/jetty-base/webapps/] no environment for App@42b64ab8[ee10,null,C:\temp\jetty\jetty-base\webapps\myDepTst.war], ignoring
2025-03-20 21:27:51.907:INFO :oejd.DeploymentManager:main: addApp: App@c074c0c[ee10,null,C:\temp\jetty\jetty-base\webapps\myDepTst.war]
2025-03-20 21:27:54.765:INFO :oejsh.ContextHandler:main: Started oeje10w.WebAppContext@315f09ef{myDepTst,/myDepTst,b=file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/,a=AVAILABLE,h=oeje10s.SessionHandler@b9a77c8{STARTED}}{C:\temp\jetty\jetty-base\webapps\myDepTst.war}
2025-03-20 21:27:54.766:INFO :oejes.ServletContextHandler:main: Started oeje10w.WebAppContext@315f09ef{myDepTst,/myDepTst,b=file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/,a=AVAILABLE,h=oeje10s.SessionHandler@b9a77c8{STARTED}}{C:\temp\jetty\jetty-base\webapps\myDepTst.war}
Also the logs for the working example ee10-demo-jetty look similar.
Setting .eclipse.jetty.LEVEL=TRACE
in jetty-logging.properties
shows:
2025-03-20 21:55:55.157:DEBUG:oejea.AnnotationParser:qtp192881625-36: Parse class from file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/WEB-INF/classes/springboot/jetty/deploy/SpringBootApplication.class
2025-03-20 21:55:55.157:DEBUG:oejea.AnnotationParser:qtp192881625-36: Parse class from file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/WEB-INF/classes/springboot/jetty/deploy/WebEndpoint.class
which I interpret as jetty analyzing my important classes.
When adressing the context
http://localhost:8080/myDepTst/
I get a "directory-listing" of "/myDepTst/" so the myDepTst was at least partially recognized.
Screenshot: response to getting context
But when addressing the endpoint
http://localhost:8080/myDepTst/endpt/tst
I get a 404:
Screenshot: 404 when addressing endpoint
I'm out of options and any help is appreciated! Thanks in advance
Problem:
I'm trying to deploy a simple spring-boot (3.4) application on a pre-installed jetty-server (12.0.18). (The main reason is to keep the package small for both transfer and memory).
The war-file seems to be deployed (addressing the context results in something) but I can't address the endpoint (404).
The only description I found was with ChatGpt, Gemini and DeepSeek and all were quite similar. But I couldn't address the endpoint.
What I did and expectations
All three AIs recommended
- change packaging to WAR
- mark the embedded Jetty-dependency as provided
- extend SpringBootServletInitializer
- deploy the war to jetty 12
For the experiments I tried to deploy a minimal application with one endpoint as shown below:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache./POM/4.0.0" xmlns:xsi="http://www.w3./2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache./POM/4.0.0 https://maven.apache./xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>springboot.jetty.deploy</groupId>
<artifactId>myDepTst</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>myDepTst</name>
<description>Deploy a spring-boot application on jetty</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<scope>provided</scope>
</dependency>
<!-- proposed by deepseek -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Main-class:
package springboot.jetty.deploy;
import .springframework.boot.SpringApplication;
import .springframework.boot.builder.SpringApplicationBuilder;
import .springframework.boot.web.servlet.support.SpringBootServletInitializer;
@.springframework.boot.autoconfigure.SpringBootApplication
public class SpringBootApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
System.out.println("### DeployOnJettyApplication.main: Deploy On Jetty");
SpringApplication.run(SpringBootApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.err.println("### DeployOnJettyApplication.configure");
return application.sources(SpringBootApplication.class);
}
}
A WebEndpoint for testing:
package springboot.jetty.deploy;
import jakarta.annotation.PostConstruct;
import .springframework.web.bind.annotation.GetMapping;
import .springframework.web.bind.annotation.RequestMapping;
import .springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/endpt")
public class WebEndpoint {
private int counter = 0;
@PostConstruct
public void init() {
System.out.println("### WebEndpoint.init()");
}
@GetMapping("tst")
public String tst() {
return "### WebEndpoint.tst() called %s-times".formatted(counter++);
}
}
Deploying to Jetty:
- Downloading jetty 12.0.8 and unpacking to .../jetty-home
- copy the built war-file to .../jetty-base/webapps/myDepTst.war
- as the needed modules aren't clear (yet) -- cd jetty-base -- java -jar .../jetty-home/start.jar --add-modules=ee10-demos
- fire up jetty: java -jar .../jetty-home/start.jar
In the logs I find:
2025-03-20 21:27:51.797:WARN :oejdp.ScanningAppProvider:main: class .eclipse.jetty.deploy.providers.ContextProvider@569bf9eb[file:///C:/temp/jetty/jetty-base/webapps/] no environment for App@42b64ab8[ee10,null,C:\temp\jetty\jetty-base\webapps\myDepTst.war], ignoring
2025-03-20 21:27:51.907:INFO :oejd.DeploymentManager:main: addApp: App@c074c0c[ee10,null,C:\temp\jetty\jetty-base\webapps\myDepTst.war]
2025-03-20 21:27:54.765:INFO :oejsh.ContextHandler:main: Started oeje10w.WebAppContext@315f09ef{myDepTst,/myDepTst,b=file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/,a=AVAILABLE,h=oeje10s.SessionHandler@b9a77c8{STARTED}}{C:\temp\jetty\jetty-base\webapps\myDepTst.war}
2025-03-20 21:27:54.766:INFO :oejes.ServletContextHandler:main: Started oeje10w.WebAppContext@315f09ef{myDepTst,/myDepTst,b=file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/,a=AVAILABLE,h=oeje10s.SessionHandler@b9a77c8{STARTED}}{C:\temp\jetty\jetty-base\webapps\myDepTst.war}
Also the logs for the working example ee10-demo-jetty look similar.
Setting .eclipse.jetty.LEVEL=TRACE
in jetty-logging.properties
shows:
2025-03-20 21:55:55.157:DEBUG:oejea.AnnotationParser:qtp192881625-36: Parse class from file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/WEB-INF/classes/springboot/jetty/deploy/SpringBootApplication.class
2025-03-20 21:55:55.157:DEBUG:oejea.AnnotationParser:qtp192881625-36: Parse class from file:///C:/temp/jetty/jetty-base/work/jetty-0_0_0_0-8443-myDepTst_war-_myDepTst-any-/webapp/WEB-INF/classes/springboot/jetty/deploy/WebEndpoint.class
which I interpret as jetty analyzing my important classes.
When adressing the context
http://localhost:8080/myDepTst/
I get a "directory-listing" of "/myDepTst/" so the myDepTst was at least partially recognized.
Screenshot: response to getting context
But when addressing the endpoint
http://localhost:8080/myDepTst/endpt/tst
I get a 404:
Screenshot: 404 when addressing endpoint
I'm out of options and any help is appreciated! Thanks in advance
Share Improve this question edited Mar 21 at 13:04 Franz asked Mar 21 at 12:51 FranzFranz 12 bronze badges1 Answer
Reset to default 0Jetty Server
Download Jetty
In C:\temp
- Brower open https://repo1.maven./maven2//eclipse/jetty/jetty-home/12.0.19/jetty-home-12.0.19.zip
- get jetty-home-12.0.19.zip
Unzip jetty-home-12.0.19.zip
In C:\temp , unzip jetty-home-12.0.19.zip
create directory jetty-base
In C:\temp, create directory jetty-base
cd C:\temp
mkdir jetty-base
Create Jetty init Config
open CMD.exe
cd C:\temp
set JETTY_BASE=%cd%\jetty-base
set JETTY_HOME=%cd%\jetty-home-12.0.19
cd %JETTY_BASE%
java -jar %JETTY_HOME%\start.jar --add-module=logging-logback,server,http,ee10-deploy,ee10-jsp
Project SpringBoot_WAR_ST
C:\temp\SpringBoot_WAR_ST
├── pom.xml
└── src
└── main
├── java
│ └── springboot
│ └── jetty
│ └── deploy
│ ├── DemoSpringbootApplication.java
│ ├── HelloJSPController.java
│ └── HelloRestController.java
├── resources
│ ├── application.properties
│ └── logback.xml
└── webapp
└── WEB-INF
└── jsp
└── hello.jsp
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3./2001/XMLSchema-instance" xmlns="http://maven.apache./POM/4.0.0"
xsi:schemaLocation="http://maven.apache./POM/4.0.0 https://maven.apache./xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>springboot.jetty.deploy</groupId>
<artifactId>myDepTst</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>myDepTst</name>
<description>Deploy a spring-boot application on jetty</description>
<properties>
<mavenpiler.source>17</mavenpiler.source>
<mavenpiler.target>17</mavenpiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencies>
<dependency>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
<build>
<finalName>myDepTst</finalName>
<plugins>
<plugin>
<groupId>.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
DemoSpringbootApplication.java
- I changed the name of SpringBootApplication class to DemoSpringbootApplication to avoid misunderstanding. Because there is also a SpringBootApplication in the import (
import .springframework.boot.SpringApplication;
) - Also, when you convert Spring Boot to a war file, the main method is not actually called. You can check the log output.
package springboot.jetty.deploy;
import .springframework.boot.SpringApplication;
import .springframework.boot.autoconfigure.SpringBootApplication;
import .springframework.boot.builder.SpringApplicationBuilder;
import .springframework.boot.web.servlet.support.SpringBootServletInitializer;
import .slf4j.Logger;
import .slf4j.LoggerFactory;
@SpringBootApplication
public class DemoSpringbootApplication extends SpringBootServletInitializer {
private static final Logger log = LoggerFactory.getLogger(DemoSpringbootApplication.class);
public static void main(String[] args) {
log.info(">>>> MAIN START");
SpringApplication.run(DemoSpringbootApplication.class, args);
log.info(">>>> MAIN EXIT");
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
log.info(">>>> configure");
return application.sources(DemoSpringbootApplication.class);
}
}
HelloJSPController.java
- Tests for Spring Web MVC.
package springboot.jetty.deploy;
import .springframework.stereotype.Controller;
import .springframework.web.bind.annotation.RequestMapping;
import .springframework.web.bind.annotation.RequestMethod;
import .springframework.web.servlet.ModelAndView;
import .slf4j.Logger;
import .slf4j.LoggerFactory;
import java.util.Map;
@Controller
public class HelloJSPController {
private static final Logger log = LoggerFactory.getLogger(HelloJSPController.class);
@RequestMapping(value = "/hellojsp", method = RequestMethod.GET)
public ModelAndView hello(Map<String, Object> model) {
//System.out.println("HelloJSP Controller hello");
log.info(">>>> HelloJSP Controller hello");
model.put("message", "HelloJSP Controller hello");
model.put("log", log);
// /WEB-INF/jsp/hello.jsp
return new ModelAndView("hello");
}
}
HelloRestController.java
- I renamed WebEndpoint.java to HelloRestController.java.
package springboot.jetty.deploy;
import jakarta.annotation.PostConstruct;
import .springframework.web.bind.annotation.GetMapping;
import .springframework.web.bind.annotation.RequestMapping;
import .springframework.web.bind.annotation.RestController;
import .slf4j.Logger;
import .slf4j.LoggerFactory;
@RestController
@RequestMapping("/endpt")
public class HelloRestController {
private static final Logger log = LoggerFactory.getLogger(HelloRestController.class);
private int counter = 0;
@PostConstruct
public void init() {
log.info(">>> HelloRestController initialized.");
}
@GetMapping("/hello")
public String hello() {
log.info(">>>> /hello");
return "Hello from WAR!";
}
@GetMapping("/tst")
public String tst() {
log.info(">>>> /tst");
String s1="HelloRestController.tst() called %s-times".formatted(counter++);
log.info(s1);
return s1;
}
}
application.properties
spring.application.name=spring-boot-demo-war-app
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- TOMCAT SERVER -->
<!--
<property name="LOG_HOME" value="${catalina.home}/logs"/>
-->
<!-- JETTY SERVER -->
<property name="LOG_HOME" value="${jetty.base}/logs"/>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d [%thread] %-5level %-50logger{40} - %msg%n</pattern>
</encoder>
</appender>
<appender name="RollingFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_HOME}/app.log</file>
<encoder>
<pattern>%d [%thread] %-5level %-50logger{40} - %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
<maxFileSize>1MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>10MB</totalSizeCap>
<cleanHistoryOnStart>true</cleanHistoryOnStart>
</rollingPolicy>
</appender>
<root level="INFO">
<appender-ref ref="Console"/>
<appender-ref ref="RollingFile"/>
</root>
</configuration>
hello.jsp
- Tests for Spring Web MVC.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import=".slf4j.Logger" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello</title>
<style>
.color-red {
color: red;
}
</style>
</head>
<%
// debug
System.out.println("webapp / WEB-INF / jsp / hello.jsp ");
%>
<%
Logger log = (Logger) request.getAttribute("log");
if (log != null) {
log.info(">>>> Logging from JSP page!");
}
%>
<body>
<h1 class="color-red">SpringBoot hello.jsp!! ${message} </h1>
</body>
</html>
Build
cd C:\temp\SpringBoot_WAR_ST
mvn clean package
Put war into jetty webapp
- copy
C:\temp\SpringBoot_WAR_ST\target\myDepTst.war
- into
C:\temp\jetty-base\webapps
Run Jetty Server
OPEN CMD.exe
cd C:\temp
set JETTY_BASE=%cd%\jetty-base
set JETTY_HOME=%cd%\jetty-home-12.0.19
cd %JETTY_BASE%
java -jar %JETTY_HOME%\start.jar
Test
- http://localhost:8080/myDepTst/hellojsp
- http://localhost:8080/myDepTst/endpt/hello
- http://localhost:8080/myDepTst/endpt/tst
check log
Logback writes the log to: C:\temp\jetty-base\logs\app.log