Main Tutorials

Jersey hello world example

jersey logo

This article shows how to start a Grizzly HTTP server to run a JAX-RS or Eclipse Jersey application.

Tested with

  • Jersey 3.0.2
  • Grizzly 3 HTTP server
  • Java 8
  • Maven
  • JUnit 5

Table of contents

Jersey basics

1. Project Directory

A standard Maven project directory.

jersey hello world

2. Jersey dependencies

The main Jersey dependencies are the jersey-bom and jersey-hk2, others are optional, read the comment for self-explanatory.

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.mkyong</groupId>
    <artifactId>jersey-hello-world</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
    <name>jersey-hello-world</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>
        <java.version>1.8</java.version>
        <junit.version>5.4.0</junit.version>
        <jsonassert.version>1.5.0</jsonassert.version>
        <jersey.version>3.0.2</jersey.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>

        <!-- Grizzly2 HTTP Server -->
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-grizzly2-http</artifactId>
        </dependency>

        <!-- Jersey related and HK2 dependency injection -->
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
        </dependency>

        <!-- add jackson for json conversion
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
        </dependency>
        -->

        <!-- generates the META-INF/hk2-locator/default files for auto scan and discovery -->
        <dependency>
            <groupId>org.glassfish.hk2</groupId>
            <artifactId>hk2-metadata-generator</artifactId>
            <version>3.0.2</version>
        </dependency>

        <!-- Need this to hide warning for jakarta.activation.DataSource -->
        <dependency>
            <groupId>jakarta.activation</groupId>
            <artifactId>jakarta.activation-api</artifactId>
            <version>2.0.1</version>
        </dependency>

        <!-- JUnit 5 -->
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-params</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>

            <!-- JUnit 5 need at least 2.22.0 to support -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
            </plugin>

            <!-- create a thin-jar -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.mkyong.MainApp</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

            <!-- copy project dependencies -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>3.1.2</version>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <!-- we need runtime dependency only -->
                            <includeScope>runtime</includeScope>
                            <outputDirectory>${project.build.directory}/lib/</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

</project>

Review the complete Jersey dependencies for a simple Jersey application.

Terminal

$ mvn dependency:tree

[INFO] Scanning for projects...
[INFO]
[INFO] -------------------< com.mkyong:jersey-hello-world >--------------------
[INFO] Building jersey-hello-world 1.0
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:3.1.2:tree (default-cli) @ jersey-hello-world ---
[INFO] com.mkyong:jersey-hello-world:jar:1.0
[INFO] +- org.glassfish.jersey.containers:jersey-container-grizzly2-http:jar:3.0.2:compile
[INFO] |  +- jakarta.inject:jakarta.inject-api:jar:2.0.0:compile
[INFO] |  +- org.glassfish.grizzly:grizzly-http-server:jar:3.0.0:compile
[INFO] |  |  \- org.glassfish.grizzly:grizzly-http:jar:3.0.0:compile
[INFO] |  |     \- org.glassfish.grizzly:grizzly-framework:jar:3.0.0:compile
[INFO] |  +- org.glassfish.jersey.core:jersey-common:jar:3.0.2:compile
[INFO] |  |  \- org.glassfish.hk2:osgi-resource-locator:jar:1.0.3:compile
[INFO] |  +- org.glassfish.jersey.core:jersey-server:jar:3.0.2:compile
[INFO] |  |  +- org.glassfish.jersey.core:jersey-client:jar:3.0.2:compile
[INFO] |  |  \- jakarta.validation:jakarta.validation-api:jar:3.0.0:compile
[INFO] |  \- jakarta.ws.rs:jakarta.ws.rs-api:jar:3.0.0:compile
[INFO] +- org.glassfish.jersey.inject:jersey-hk2:jar:3.0.2:compile
[INFO] |  +- org.glassfish.hk2:hk2-locator:jar:3.0.1:compile
[INFO] |  |  \- org.glassfish.hk2.external:aopalliance-repackaged:jar:3.0.1:compile
[INFO] |  \- org.javassist:javassist:jar:3.25.0-GA:compile
[INFO] +- org.glassfish.hk2:hk2-metadata-generator:jar:3.0.2:compile
[INFO] |  +- org.glassfish.hk2:hk2-api:jar:3.0.2:compile
[INFO] |  +- org.glassfish.hk2:hk2-utils:jar:3.0.2:compile
[INFO] |  \- jakarta.annotation:jakarta.annotation-api:jar:2.0.0:compile
[INFO] +- jakarta.activation:jakarta.activation-api:jar:2.0.1:compile
[INFO] \- org.junit.jupiter:junit-jupiter-params:jar:5.4.0:test
[INFO]    +- org.apiguardian:apiguardian-api:jar:1.0.0:test
[INFO]    \- org.junit.jupiter:junit-jupiter-api:jar:5.4.0:test
[INFO]       +- org.opentest4j:opentest4j:jar:1.1.1:test
[INFO]       \- org.junit.platform:junit-platform-commons:jar:1.4.0:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.280 s
[INFO] Finished at: 2021-06-17T16:23:29+08:00
[INFO] ------------------------------------------------------------------------

3. Jersey and HK2 dependency injection

3.1 Jersey uses HK2 as the dependency injection framework. The below are @Contract and @Service components, and later we will inject them into the Jersey application.

MessageService.java

package com.mkyong.service;

import org.jvnet.hk2.annotations.Contract;

@Contract
public interface MessageService {
  String getHello();
}
MessageServiceImpl.java

package com.mkyong.service;

import org.jvnet.hk2.annotations.Service;

@Service
public class MessageServiceImpl implements MessageService {

  @Override
  public String getHello() {
      return "Hello World Jersey from HK2";
  }

}

3.2 This Feature enables the auto-scanning components.

AutoScanFeature.java

package com.mkyong.config;

import jakarta.inject.Inject;
import jakarta.ws.rs.core.Feature;
import jakarta.ws.rs.core.FeatureContext;
import org.glassfish.hk2.api.DynamicConfigurationService;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.Populator;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.ClasspathDescriptorFileFinder;
import org.glassfish.hk2.utilities.DuplicatePostProcessor;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/* Auto scan the JAX-RS @Contract and @Service  */
public class AutoScanFeature implements Feature {

  @Inject
  ServiceLocator serviceLocator;

  @Override
  public boolean configure(FeatureContext context) {

      DynamicConfigurationService dcs =
              serviceLocator.getService(DynamicConfigurationService.class);
      Populator populator = dcs.getPopulator();
      try {
          // Populator - populate HK2 service locators from inhabitants files
          // ClasspathDescriptorFileFinder - find files from META-INF/hk2-locator/default
          populator.populate(
                  new ClasspathDescriptorFileFinder(this.getClass().getClassLoader()),
                  new DuplicatePostProcessor());

      } catch (IOException | MultiException ex) {
          Logger.getLogger(AutoScanFeature.class.getName()).log(Level.SEVERE, null, ex);
      }
      return true;
  }
}

4. Jersey endpoints

The below is a Jersey application that exposed a few endpoints to produce different output in text format.

MyResource.java

package com.mkyong.resource;

import com.mkyong.service.MessageService;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

@Path("/hello")
public class MyResource {

  // DI via HK2
  @Inject
  private MessageService messageService;

  // output text
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  public String hello() {
      return "Jersey hello world example.";
  }

  // output text with argument
  @Path("/{name}")
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  public String hello(@PathParam("name") String name) {
      return "Jersey: hello " + name;
  }

  // for dependency injection
  @Path("/hk2")
  @GET
  @Produces(MediaType.TEXT_PLAIN)
  public String helloHK2() {
      return messageService.getHello();
  }

}

5. Start Jersey application

There is no magic here; we need to manually configure the HTTP server and start and end the HTTP Server and the Jersey application. Read the code comments for self-explanatory.

MainApp.java

package com.mkyong;

import com.mkyong.config.AutoScanFeature;
import com.mkyong.resource.MyResource;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.server.ResourceConfig;

import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MainApp {

  private static final Logger LOGGER = Logger.getLogger(MainApp.class.getName());

  // we start at port 8080
  public static final String BASE_URI = "http://localhost:8080/";

  // Starts Grizzly HTTP server
  public static HttpServer startServer() {

      // scan packages
      final ResourceConfig config = new ResourceConfig();
      // config.packages(true, "com.mkyong");
      config.register(MyResource.class);

      // enable auto scan @Contract and @Service
      config.register(AutoScanFeature.class);

      LOGGER.info("Starting Server........");

      final HttpServer httpServer =
              GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), config);

      return httpServer;

  }

  public static void main(String[] args) {

      try {

          final HttpServer httpServer = startServer();

          // add jvm shutdown hook
          Runtime.getRuntime().addShutdownHook(new Thread(() -> {
              try {
                  System.out.println("Shutting down the application...");

                  httpServer.shutdownNow();

                  System.out.println("Done, exit.");
              } catch (Exception e) {
                  Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, e);
              }
          }));

          System.out.println(String.format("Application started.%nStop the application using CTRL+C"));

          // block and wait shut down signal, like CTRL+C
          Thread.currentThread().join();

      } catch (InterruptedException ex) {
          Logger.getLogger(MainApp.class.getName()).log(Level.SEVERE, null, ex);
      }

  }
}

6. Demo

6.1 Start the MainApp directly, or pack it into a single jar and run it.

Terminal

$ cd {project}

$ mvn package

$ java -jar target/jersey-hello-world-1.0.jar

Jun 17, 2021 3:34:56 PM com.mkyong.MainApp startServer
INFO: Starting Server........
Jun 17, 2021 3:34:57 PM org.glassfish.jersey.server.wadl.WadlFeature configure
WARNING: JAX-B API not found . WADL feature is disabled.
Jun 17, 2021 3:34:57 PM org.glassfish.grizzly.http.server.NetworkListener start
INFO: Started listener bound to [localhost:8080]
Jun 17, 2021 3:34:57 PM org.glassfish.grizzly.http.server.HttpServer start
INFO: [HttpServer] Started.
Application started.
Stop the application using CTRL+C

6.2 We can use a simple cURL to test the Jersey endpoints.

Terminal

$ curl http://localhost:8080/hello
Jersey hello world example.

$ curl http://localhost:8080/hello/mkyong
Jersey: hello mkyong

$ curl http://localhost:8080/hello/hk2
Hello World Jersey from HK2

$ curl -v http://localhost:8080/hello/hk2
*   Trying ::1...
* TCP_NODELAY set
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /hello/hk2 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.55.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Content-Length: 27
<
Hello World Jersey from HK2

7. Jersey and unit test

A JAX-RS standard Client and WebTarget class to test the Jersey endpoints.

MyResourceTest.java

package com.mkyong;

import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;

import org.glassfish.grizzly.http.server.HttpServer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class MyResourceTest {

  private static HttpServer httpServer;
  private static WebTarget target;

  @BeforeAll
  public static void beforeAllTests() {
      httpServer = MainApp.startServer();
      Client c = ClientBuilder.newClient();
      target = c.target(MainApp.BASE_URI);
  }

  @AfterAll
  public static void afterAllTests() {
      httpServer.stop();
  }

  @Test
  public void testHello() {
      String response = target.path("hello").request().get(String.class);
      assertEquals("Jersey hello world example.", response);
  }

  @Test
  public void testHelloName() {
      String response = target.path("hello/mkyong").request().get(String.class);
      assertEquals("Jersey: hello mkyong", response);
  }

  @Test
  public void testHelloHK2() {
      String response = target.path("hello/hk2").request().get(String.class);
      assertEquals("Hello World Jersey from HK2", response);
  }

}

8. Download Source Code

$ git clone https://github.com/mkyong/jax-rs

$ cd jax-rs/jersey/jersey-hello-world

$ mvn package

$ java -jar target/jersey-hello-world-1.0.jar

9. References

About Author

author image
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter. If you like my tutorials, consider make a donation to these charities.

Comments

Subscribe
Notify of
109 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments
Nitish
6 years ago
shred lesnar
7 years ago

When I am trying to run the same example. I am getting 404 error on server.

Praveen
8 years ago

I am getting this error when I try to run, HTTP Status 500 – Servlet.init() for servlet jersey-serlvet threw exception

The ResourceConfig instance does not contain any root resource classes.

Anyone can help me here to sort out the issue??.

Johaness
8 years ago

as usual an incomplete broken sample!

Nitish
6 years ago
Reply to  Johaness

Not true

anon
6 years ago

IF you are using TOmcat 8.5 and Jersey 1.19 then you need to add the below 2 dependecies:

com.sun.jersey
jersey-server
1.19

com.sun.jersey
jersey-servlet
1.19

Dorababu
6 years ago

Hi mkyong I had my XML which was generated using SOAP UI, where I am having some global parameters set. I am trying to execute that XML from maven using continuous integration process I am getting the following error GET – Request_GetAllUsers FailedSubmitException: com.eviware.soapui.model.iface.Request$SubmitException: com.eviware.soapui.impl.wsdl.submit.RequestTransportRegistry$MissingTransportException: Missing protocol in endpoint [${Endpoint}]

Can you help me to over come this

Sharad Ladkat
3 years ago

Tried the code. Able to download. Added as a existing maven project. Created .war file from eclipse. Deployed on apache tomcat 9. Restart the server. by using
URL : http://localhost:8080/RESTfulExample/rest/hello/mkyong
I am able to print sysout on server.
Thanks. It worked for me.

Sathish Kumar
6 years ago

Hi mkyong,
I am getting the following exception. I am completely blocked can you please help me here.
com.sun.jersey.api.container.ContainerException: No WebApplication provider is present
com.sun.jersey.spi.container.WebApplicationFactory.createWebApplication(WebApplicationFactory.java:69)
com.sun.jersey.spi.container.servlet.ServletContainer.create(ServletContainer.java:412)
com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.create(ServletContainer.java:327)

Juan Marco
8 years ago

For those of you having trouble:
1. Make sure you are not mixing jersey 1 with jersey 2.
2. The maven dependency for jersey 1 used in this tutorial INCLUDES
javax.ws.rs, so if you have this dependency below in your pom.xml,
you are in for trouble due to library collisions.

javax.ws.rs
javax.ws.rs-api

The error you get won’t be indicative that this is the problem.

More on stack overflow:
http://stackoverflow.com/questions/23277429/exception-in-rest-jersey

Rithik
1 year ago

Hi Mkyong, is it possible to import library files into tomcat

Viktor
4 years ago

how to config – open index.html ????? i’m break my head

Dima
4 years ago

Mkyong you save me again! Thank you!

John the Truth Teller
4 years ago

Does not work !
How does this tutorial, not work with maven… please update it, so many people seem to have the same issue.

Dany Wehbe
5 years ago

Many thanks for this clear demonstration

Leonidas
5 years ago

In the pom.xml file add the dependencies if you are using Java 11.
(https://stackoverflow.com/questions/43574426/how-to-resolve-java-lang-noclassdeffounderror-javax-xml-bind-jaxbexception-in-j)

javax.xml.bind
jaxb-api
2.2.11

com.sun.xml.bind
jaxb-core
2.2.11

com.sun.xml.bind
jaxb-impl
2.2.11

javax.activation
activation
1.1.1

Mrin
5 years ago

for a complete example using Java 11, Jersey and VueJs for frontend checkout https://github.com/mrin9/Angular-SpringBoot-REST-JWT

Pool
5 years ago

Having issues with running the application on the Tomcat Server in IntelliJ. The exploded war is successfully created. Also, it gets successfully deployed on the server. But, no subset of the url seems to work (404 error for all). Any ideas?

Sure Law
6 years ago

To run the demo, do as following steps: 1. Get a servlet container. I use eclipse jetty to do this, and of course tomcat is fine too. 2. cd into base dir of this example and run “mvn clean install”. If you are luck enough, you will get a file named as “RESTfulExample.war” in the target folder. 3. move this file into jetty_home/webapps, and start jetty using command ” java -jar start.jar”. 4 Now, you can access the url refered in author’s blog.

Karthick A S
6 years ago

hi Mkyong, I am trying above sample in my weblogic server….i am facing some issue. Is there i need to add any new jars related to weblogic server.

Und
6 years ago

Not work

Nitish
6 years ago

If you download his project folder and try to run his, make sure that you spec’s match his, especially the jdk, Jersey and Tomcat version.

CORRECTION:
http://localhost:8080/RESTfulExample/rest/hello/mkyong
(returns a 404 for me)
SHOULD BE
http://localhost:8080/rest/hello/mkyong
(works fine)

This is what got mine to work.
Thanks so much mkyong!

neeraj bansal
7 years ago

works for me, thanks

Sydney
7 years ago

And I forgot to configure my server 🙁 Done it now and the example is working perfectly 🙂 … Big-ups to Mkyong

Sydney
7 years ago

Hi, MK, Thanks for delivering such great work. I have been benefiting from your tutorials for a while now. I am currently trying to get this one to work and be able to understand thoroughly. If I may ask, where do we configure the port number? ‘8080’ in your example?

Rishi Prakash
5 years ago
Reply to  Sydney

By default your server will be configured with 8080 port.

Michael Njoroge
7 years ago

its a cool one..

Arno Jan Sta Nimus
7 years ago

Why are you all using this com.sun packages?? they are likely to be removed from api!!

Capricorn1
8 years ago

This was all I needed to get started in the right direction. Thanks!

RAYO
8 years ago

This example to uses qith JBoss 6 I need to change the web.xml

jersey-serlvet
com.sun.jersey.spi.container.servlet.ServletContainer

com.sun.jersey.config.property.packages
mx.com.sia.tutorial.rest

1

jersey-serlvet
/*

resteasy.scan
false

resteasy.scan.providers
false

resteasy.scan.resources
false

Saludos!!!!

Nagarjuna
8 years ago

Hi Sir, This is nagarjuna working for MNC, i have copied this project into my eclipse and converted into maven .
it is not working, am referring to different url. can you provide settings .xml for this project

Eduardo Oportus
8 years ago

very helpfull, thank you.