Jersey hello world example
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
- 1. Project Directory
- 2. Jersey dependencies
- 3. Jersey and HK2 dependency injection
- 4. Jersey endpoints
- 5. Start Jersey application
- 6. Demo
- 7. Jersey and unit test
- 8. Download Source Code
- 9. References
Jersey basics
- Many Java-based HTTP servers deploy Jersey applications, for example, JDK HTTP Server, Grizzly, Simple, Jetty and Netty. Read this Jersey and HTTP servers.
- Jersey uses HK2 dependency injection framework.
- Jersey uses Java APIs logging, or JUL, or
java.util.logging.*
.
1. Project Directory
A standard Maven project directory.
2. Jersey dependencies
The main Jersey dependencies are the jersey-bom
and jersey-hk2
, others are optional, read the comment for self-explanatory.
<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.
$ 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.
package com.mkyong.service;
import org.jvnet.hk2.annotations.Contract;
@Contract
public interface MessageService {
String getHello();
}
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.
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;
}
}
Note
More Jersey and HK2 examples.
4. Jersey endpoints
The below is a Jersey application that exposed a few endpoints to produce different output in text format.
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.
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.
$ 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.
$ 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.
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
Changing http://localhost:8080/RESTfulExample/rest/hello/mkyong to
http://localhost:8080/rest/hello/mkyong
made it work for me!
Thanks so much mkyong
When I am trying to run the same example. I am getting 404 error on server.
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??.
as usual an incomplete broken sample!
Not true
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
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
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.
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)
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
Hi Mkyong, is it possible to import library files into tomcat
how to config – open index.html ????? i’m break my head
Mkyong you save me again! Thank you!
Does not work !
How does this tutorial, not work with maven… please update it, so many people seem to have the same issue.
Many thanks for this clear demonstration
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
for a complete example using Java 11, Jersey and VueJs for frontend checkout https://github.com/mrin9/Angular-SpringBoot-REST-JWT
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?
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.
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.
Not work
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!
works for me, thanks
And I forgot to configure my server 🙁 Done it now and the example is working perfectly 🙂 … Big-ups to Mkyong
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?
By default your server will be configured with 8080 port.
its a cool one..
Why are you all using this com.sun packages?? they are likely to be removed from api!!
This was all I needed to get started in the right direction. Thanks!
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!!!!
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
very helpfull, thank you.