Issue
i am trying to embed a HTTP-Server into an existing java Application. My goal is to create a small rest API as an interface to send commands to the server application it runs in.
I planned using Jakarta and Jersey 3 with Jetty as embeded HTTP-Server. My starting point was the following topic which was for Jersey 2 but i tried my luck: Embed jersey in java application
My problem is that i get 404 Not Found
back when i try to call http://localhost/login/status in my browser. The page is blank. When i switch to using Grizzly2 as embedded HTTP-Server and type the url in the browser, the result is the same. The only difference in Grizzly2 i could spot is when i only call http://localhost/ i get an error page additionally to the 404 Not Found
response back. As soon as i add /login to the url, i get the 404 Not Found
response without an error page. What could be the reason the server does not pick up my resources?
I am using the Eclipse IDE. First i created a clean Maven project, added the following dependencies and created my test code:
org.glassfish.jersey.core -> jersey-server
org.glassfish.jersey.containers -> jersey-container-jetty-http
On my first startup i got some missing class errors, searched for the dependencies they are in and added them to the pom. Following is my current test code.
<!-- 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>test-ee</groupId>
<artifactId>test-ee-embed</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>3.0.4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-bom</artifactId>
<version>3.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>jakarta.xml.bind</groupId>
<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
</dependency>
</dependencies>
</project>
// LoginserverRestApi.java
package de.l2d;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@ApplicationPath("/login")
public class LoginserverRestApi extends ResourceConfig {
@GET @Path("/status")
public String status() {
// TODO Return real server statistics.
return "{\"status\":\"ok\"}";
}
}
// RestApiServer.java
package de.l2d;
import java.net.URI;
import org.eclipse.jetty.server.Server;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import jakarta.ws.rs.core.UriBuilder;
public class RestApiServer {
private Server server;
private RestApiServer() {
URI baseUri = UriBuilder.fromUri("http://localhost/").build();
server = JettyHttpContainerFactory.createServer(baseUri, new LoginserverRestApi(), false);
}
public void start() throws Exception {
server.start();
}
public void stop() throws Exception {
server.stop();
}
private static final class SingletonHolder {
protected static RestApiServer instance = new RestApiServer();
}
public static RestApiServer getInstance() {
return SingletonHolder.instance;
}
}
// Main.java
package de.l2d;
public class Main {
public static void main(String[] args) throws Exception {
RestApiServer.getInstance().start();
Thread.currentThread().join();
RestApiServer.getInstance().stop();
}
}
Solution
I found the solution to my problem. However, i do not know why it behaves like this.
I had to use the Path
annotation instead of the ApplicationPath
annotation on the LoginserverRestApi
class and additionally construct a ResourceConfig
with LoginserverRestApi.class
as parameter and pass that Object to the JettyHttpContainerFactory.createServer
static method. Following are the two files which differ from the initial post:
// LoginserverRestApi.java
package de.l2d;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
@Path("/login")
public class LoginserverRestApi extends ResourceConfig {
@GET @Path("/status")
public String status() {
// TODO Return real server statistics.
return "{\"status\":\"ok\"}";
}
}
// RestApiServer.java
package de.l2d;
import java.net.URI;
import org.eclipse.jetty.server.Server;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import jakarta.ws.rs.core.UriBuilder;
public class RestApiServer {
private Server server;
private RestApiServer() {
URI baseUri = UriBuilder.fromUri("http://localhost/").build();
ResourceConfig config = new ResourceConfig(LoginserverRestApi.class);
server = JettyHttpContainerFactory.createServer(baseUri, config, false);
}
public void start() throws Exception {
server.start();
}
public void stop() throws Exception {
server.stop();
}
private static final class SingletonHolder {
protected static RestApiServer instance = new RestApiServer();
}
public static RestApiServer getInstance() {
return SingletonHolder.instance;
}
}
Answered By - Christian
Answer Checked By - Candace Johnson (JavaFixing Volunteer)