ZetCode

Jersey application with embedded Jetty

last modified July 13, 2020

In this tutorial, we create a simple Java REST application with Jersey and embedded Jetty. We also show how to pack the application into an executable uber JAR.

Jersey is an open source framework for developing RESTful Web Services in Java. It is a reference implementation of the Java API for RESTful Web Services (JAX-RS) specification.

Jetty is a Java HTTP (Web) server and Java Servlet container. It can be easily embedded in devices, tools, frameworks, application servers, and clusters.

RESTFul application

A RESTFul application creates a system (API) that follows the REST architectural style, which is used for designing networked applications. RESTful applications use HTTP requests perform CRUD (Create/Read/Update/Delete) operations on resources.

Code example

The following is a very simple Java RESTful application created with Jersey and embedded Jetty server.

$ tree
.
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── zetcode
    │   │           ├── app
    │   │           │   └── Main.java
    │   │           └── res
    │   │               └── MyMessage.java
    │   └── resources
    └── test
        └── java

This is our project structure.

The project consists of two Java source files and the Maven POM file.

pom.xml
<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/maven-v4_0_0.xsd">
    
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.zetcode</groupId>
    <artifactId>JerseyJettyEx</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>JerseyJettyEx</name>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>        
    </properties>    

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-jetty-http</artifactId>
            <version>2.25</version>
        </dependency>
        
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-util</artifactId>
            <version>9.4.0.v20161208</version>
        </dependency>        
        
        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>2.25</version>
        </dependency>
        
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <version>2.25</version>
        </dependency>        
        
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>9.4.0.v20161208</version>
        </dependency>        
        
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.4.0.v20161208</version>
        </dependency>        
        
    </dependencies>

    <build>
        <finalName>JerseyJettyEx</finalName>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.5.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>java</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <mainClass>com.zetcode.app.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
</project>

In the pom.xml file, we have necessary Jersey and Jetty dependencies. We also use the exec-maven-plugin, which is used for executing Java programs.

MyMessage
package com.zetcode.res;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("msg")
public class MyMessage {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getMessage() {
        
        return "My message\n";
    }
}

We define a resource. It responds to a HTTP GET request and returns plain text.

@Path("msg")
public class MyMessage {

The @Path annotation identifies the URL path to which the resource responds.

com/zetcode/Main.java
package com.zetcode.app;

import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;

public class Main {

    public static void main(String[] args) {

        Server server = new Server(8080);

        ServletContextHandler ctx = 
                new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
                
        ctx.setContextPath("/");
        server.setHandler(ctx);

        ServletHolder serHol = ctx.addServlet(ServletContainer.class, "/rest/*");
        serHol.setInitOrder(1);
        serHol.setInitParameter("jersey.config.server.provider.packages", 
                "com.zetcode.res");

        try {
            server.start();
            server.join();
        } catch (Exception ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } finally {

            server.destroy();
        }
    }
}

In Main.java, we set up and start Jetty.

Server server = new Server(8080);

Jetty server is started listening on 8080 port.

ServletContextHandler ctx = 
        new ServletContextHandler(ServletContextHandler.NO_SESSIONS);

The next step is to create a ServletContextHandler object.

ctx.setContextPath("/");

With the setContextPath method we set the path to which the application is mapped.

ServletHolder serHol = ctx.addServlet(ServletContainer.class, "/rest/*");

We add the Jersey ServletContainer to the Jetty servlet holder. This essentially joins Jersey with Jetty.

serHol.setInitParameter("jersey.config.server.provider.packages", 
        "com.zetcode.res");

Here we tell Jersey where to look for resources.

Building and running application

In the following steps, we build and run the application.

$ mvn package

We build the application with mvn package command.

$ mvn exec:java

The application is started with mvn exec:java command.

$ curl localhost:8080/rest/msg
My message

We use curl tool to issue a HTTP GET request to our resource.

Uber JAR

Uber JAR is a JAR that contains both our package and all its dependencies in one single JAR file. Such JAR is also called a fat JAR.

maven-shade-plugin
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>2.4.3</version>
    <configuration>
        <createDependencyReducedPom>true</createDependencyReducedPom>
        <filters>
            <filter>
                <artifact>*:*</artifact>
                <excludes>
                    <exclude>META-INF/*.SF</exclude>
                    <exclude>META-INF/*.DSA</exclude>
                    <exclude>META-INF/*.RSA</exclude>
                </excludes>
            </filter>
        </filters>
    </configuration>

    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <transformers>
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
                    <transformer
                        implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <manifestEntries>
                            <Main-Class>com.zetcode.app.Main</Main-Class>
                        </manifestEntries>
                    </transformer>
                </transformers>
            </configuration>
        </execution>
    </executions>
</plugin>

With the maven-shade-plugin we can create one executable JAR containing all dependencies.

<transformer
   implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
   <manifestEntries>
       <Main-Class>com.zetcode.app.Main</Main-Class>
   </manifestEntries>
</transformer>

In order to make the JAR executable, it must have a main class in the manifest. This is achieved with the ManifestResourceTransformer.

$ mvn clean package

We clean and build the application.

$ java -jar target/JerseyJettyEx-1.0-SNAPSHOT.jar

We use this command to start the application.

In this tutorial, we have created a simple Java REST application with Jersey and embedded Jetty. We have shown how to create an uber JAR.