Starter Projects
Apache Juneau provides three minimal, clone-and-go "Hello World" starter projects — one per deployment type. They are deliberately simpler than the petstore showcase: entry-point templates you can build and run in under five minutes, then graduate from.
Juneau 10 is a pre-release (10.0.0-SNAPSHOT). Each starter's pom.xml already points at the Apache snapshots
repository, so a normal Maven build resolves it with no extra setup, but it needs network access and the
snapshot can change between builds. Maven Central has only 9.2.0 today (see Downloads), and the
starters need 10.0, so they cannot build without that repository. See
Set the version.
New to Juneau? The Getting Started walkthrough builds a small REST app from an empty directory and does not need a starter.
Each starter is a true-orphan branch of apache/juneau.
Clone one branch into a my-app directory (single-branch; not a full Java checkout):
git clone -b microservice-jetty-starter --single-branch https://github.com/apache/juneau.git my-app
git clone -b microservice-springboot-starter --single-branch https://github.com/apache/juneau.git my-app
git clone -b microservice-tomcat-starter --single-branch https://github.com/apache/juneau.git my-app
| Starter | Deployment | Branch |
|---|---|---|
| Jetty | Embedded Jetty, runnable jar | microservice-jetty-starter |
| Spring Boot | Spring Boot, runnable jar | microservice-springboot-starter |
| Tomcat | WAR on Tomcat 10.1+ | microservice-tomcat-starter |
Each starter demonstrates a lean, Juneau-native feature set: a POJO-returning resource (JSON/XML/HTML
content negotiation), the built-in HtmlDoc view, an auto-generated Swagger/OPTIONS page, @Path/@Query
binding, a YAML config file, and a MockRestClient example test exercising an @Remote typed client.
Docs for the starters live on this page and at juneau.apache.org — not on per-starter GitHub Pages.
Quick start
Prerequisites: JDK 17+. Docker is optional.
Jetty
git clone -b microservice-jetty-starter --single-branch https://github.com/apache/juneau.git my-app
cd my-app
./mvnw clean package && java -jar target/my-app.jar
Open http://localhost:10000/helloWorld. The port comes from
juneau.cfg ([Jetty] port). See Ports used in these docs.
# Docker
./mvnw -q clean package
docker build -t my-app .
docker run --rm -p 10000:10000 my-app
The image is eclipse-temurin:17-jre running the shaded uber-jar.
Spring Boot
git clone -b microservice-springboot-starter --single-branch https://github.com/apache/juneau.git my-app
cd my-app
./mvnw spring-boot:run
# or: ./mvnw clean package && java -jar target/my-app-1.0.0-SNAPSHOT.jar
Open http://localhost:10000/helloWorld. The port comes from server.port in
src/main/resources/application.yaml.
# Docker
./mvnw -q clean package
docker build -t my-app .
docker run --rm -p 10000:10000 my-app
The image is eclipse-temurin:17-jre running the Spring Boot jar.
Tomcat (WAR)
git clone -b microservice-tomcat-starter --single-branch https://github.com/apache/juneau.git my-app
cd my-app
./mvnw -q clean package
docker build -t my-app .
docker run --rm -p 8080:8080 my-app
Open http://localhost:8080/helloWorld. The image is
tomcat:10.1-jdk17-temurin with the WAR copied in as ROOT.war.
To an existing Tomcat 10.1+:
./mvnw -q clean package
cp target/my-app.war "$CATALINA_HOME/webapps/ROOT.war"
cp my-app.yaml "$CATALINA_HOME/bin/"
Try content negotiation
Jetty / Spring Boot (port 10000):
curl -H "Accept: application/json" http://localhost:10000/helloWorld
curl -H "Accept: text/xml" http://localhost:10000/helloWorld
curl -H "Accept: text/html" http://localhost:10000/helloWorld
curl "http://localhost:10000/helloWorld/greet/Juneau?loud=true"
Tomcat (port 8080): same paths on http://localhost:8080.
Project layout
Rename com.example / my-app / com.example.myapp to your own coordinates. These are rename-me
templates, not Apache GAVs.
Jetty — standalone shaded uber-jar (maven-shade); no Apache reactor:
pom.xml, mvnw, my-app.yaml, juneau.cfg, Dockerfile
src/main/java/com/example/myapp/{App,RootResources,HelloWorldResource,Greeting,GreetingApi}.java
src/test/java/com/example/myapp/HelloWorldResourceTest.java
App calls JettyMicroservice.run(...).
Spring Boot — Spring Boot parent; no Apache reactor:
pom.xml, mvnw, my-app.yaml, Dockerfile
src/main/java/com/example/myapp/{App,RootResources,HelloWorldResource,Greeting,GreetingApi}.java
src/main/resources/application.yaml
src/test/java/com/example/myapp/HelloWorldResourceTest.java
Tomcat — standalone WAR; servlet registered in web.xml; no App.java:
pom.xml, mvnw, my-app.yaml, Dockerfile
src/main/java/com/example/myapp/{RootResources,HelloWorldResource,Greeting,GreetingApi}.java
src/main/webapp/WEB-INF/web.xml
src/test/java/com/example/myapp/HelloWorldResourceTest.java
Configuration
HelloWorldResource declares @Rest(config="my-app.yaml") and reads:
var message = req.getConfig().getString("HelloWorld/message");
HelloWorld:
message: Hello from my-app.yaml!
The .yaml extension selects Juneau's YAML config format
(org.apache.juneau.config.format.YamlConfigFormat, id yaml). Nested keys map to section/key paths.
| Starter | Second config file | Purpose |
|---|---|---|
| Jetty | juneau.cfg (INI) | Jetty runtime ([Jetty] port, console, logging). |
| Spring Boot | src/main/resources/application.yaml | Spring (server.port). |
| Tomcat | none in-tree besides my-app.yaml | At runtime the Dockerfile copies my-app.yaml to /usr/local/tomcat/bin/. If the file is not found, the resource falls back to "Hello world!". |
These starters currently depend on 10.0.0-SNAPSHOT and declare the Apache snapshots repository.
After 10.0 GA the version pin and snapshots stanza will be removed (a follow-up, not required to clone).
Adding a view (optional)
The starters ship only Juneau's built-in HtmlDoc view. To render a custom HTML page, add one of:
juneau-rest-server-view-freemarkerjuneau-rest-server-view-thymeleaf
Attach the view to a @RestGet method. See FreeMarker view support
and Thymeleaf view support. Left out of the starters on purpose
to stay dependency-light.