How to embed Jetty and Jersey into my Java application

29,621

Solution 1

A few things.

  1. Jetty 9.0.0.RC0 is an old, not-yet stable, release candidate, consider upgrading to a stable, final release, such as 9.0.4.v20130625
  2. You need something that will connect that Jax RS class into the servlet api. Usually done via a Servlet or some sort of initialization with your library of choice. (In you case Jersey)

In your example, you have only setup a DefaultServlet to serve static files, nothing has been configured to use your DBCollection object.

For Jersey, you'll need to configure the org.glassfish.jersey.servlet.ServletContainer and setup its servlet-mappings on a context of your choice.

Example:

package com.example;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

public class Main
{
    public static void main(String[] args)
    {
        Server server = new Server(8080);

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

        ServletHolder jerseyServlet = context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class, "/webapi/*");
        jerseyServlet.setInitOrder(1);
        jerseyServlet.setInitParameter("jersey.config.server.provider.packages","com.example");

        ServletHolder staticServlet = context.addServlet(DefaultServlet.class,"/*");
        staticServlet.setInitParameter("resourceBase","src/main/webapp");
        staticServlet.setInitParameter("pathInfoOnly","true");

        try
        {
            server.start();
            server.join();
        }
        catch (Throwable t)
        {
            t.printStackTrace(System.err);
        }
    }
}

This example adds the ServletContainer that jersey provides to the ServletContextHandler that Jetty uses to look up what to do based on the incoming request. Then it adds the DefaultServlet to handle any requests for content that Jersey does not handle (such as static content)

Solution 2

In case you want to completely manage the lifecycle of your DBCollection resource programmatically (eg you instantiate it yourself, do some setup/initialization etc), instead of having Jersey create the instance for you, you can use a ResourceConfig like such:

ServletContextHandler sch = new ServletContextHandler();
sch.setContextPath("/xxx");

TheResource resource = new TheResource();
ResourceConfig rc = new ResourceConfig();
rc.register(resource);

ServletContainer sc = new ServletContainer(rc);
ServletHolder holder = new ServletHolder(sc);
sch.addServlet(holder, "/*");

Server server = new Server(port);
server.setHandler(sch);
server.start();
server.join();

Note the line TheResource resource = new TheResource();. Here we create our own instance of TheResource, and we can manipulate it at will now.

Share:
29,621
Admin
Author by

Admin

Updated on November 19, 2020

Comments

  • Admin
    Admin over 3 years

    So I'm trying to embed jetty into my web application so that if I package it as a jar someone can just run the jar file without having to worry about configuring a server. However, I'm having some problems setting up my main class so that jetty can access my resource classes. I've looked at tutorials but they haven't given me exactly what I'm looking for. This is what I have so far.

    package pojo;
    
    import org.eclipse.jetty.server.Server;
    import org.eclipse.jetty.servlet.DefaultServlet;
    import org.eclipse.jetty.servlet.ServletContextHandler;
    import org.eclipse.jetty.servlet.ServletHolder;
    
    public class Main {
    
        public static void main(String[] args) throws Exception {
            Server server = new Server(8080);
            ServletContextHandler context = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
            context.setContextPath("/");
            ServletHolder h = new ServletHolder(new DefaultServlet());
            h.setInitParameter("javax.ws.rs.Application","resources.DBCollection");
            context.addServlet(h, "/*");
            server.setHandler(context);
            server.start();
            server.join();
        }
    }
    

    And I'm trying to map it to this class:

    package resources;
    
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.Context;
    import javax.ws.rs.core.MediaType;
    import javax.ws.rs.core.Request;
    import javax.ws.rs.core.UriInfo;
    
    import pojo.Party;
    
    @Path("/parties")
    public class DBCollection {
    
        @Context
        UriInfo url;
    
        @Context
        Request request;
    
        String name;
    
        @GET
        @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
        public List<Party> getAllParties() throws Exception
        {
            List<Party> list = new ArrayList<Party>();
            list.addAll(DBConnection.getPartyCollection().values());
            return list;
        }
    
        @GET
        @Path("count")
        @Produces(MediaType.TEXT_PLAIN)
        public String getPartyCount() throws Exception
        {
            return String.valueOf(DBConnection.getPartyCollection().size());
        }
    
        @Path("{party}")
        public DBResource getParty(@PathParam("party")String party)
        {
            return new DBResource(url,request,party);
        }
    }
    

    Here's my POM file:

    <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/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>PartyAPI</groupId>
        <artifactId>PartyAPIMaven</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.6</version>
            </dependency>
            <dependency>
                <groupId>com.codahale.metrics</groupId>
                <artifactId>metrics-core</artifactId>
                <version>3.0.1</version>
            </dependency>
            <dependency>
                <groupId>com.sun.jersey</groupId>
                <artifactId>jersey-server</artifactId>
                <version>1.17.1</version>
            </dependency>
    
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-server</artifactId>
                <version>9.0.0.RC0</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-servlet</artifactId>
                <version>9.0.0.RC0</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-servlets</artifactId>
                <version>9.0.0.RC0</version>
                <scope>compile</scope>
            </dependency>
            <dependency>
                <groupId>org.eclipse.persistence</groupId>
                <artifactId>eclipselink</artifactId>
                <version>2.6.0-SNAPSHOT</version>
            </dependency>
    
        </dependencies>
        <repositories>
            <repository>
                <id>oss.sonatype.org</id>
                <name>OSS Sonatype Staging</name>
                <url>https://oss.sonatype.org/content/groups/staging</url>
            </repository>
        </repositories>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>1.6</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.resteasy.Star.Main</Main-Class>
    
                                        </manifestEntries>
    
                                    </transformer>
                                </transformers>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>
    
  • Admin
    Admin almost 11 years
    So when I enter localhost:8111/webapi/parties I get a 500 error (Note: I changed the port to 8111 because I was getting a NetBind Exception), how do I fix that (no stack strace is printed). Also, I couldn't find javadocs, would you mind explaining what setInitParameter does and what you mean by "static" content vs jersey content
  • Joakim Erdfelt
    Joakim Erdfelt almost 11 years
    Static content is content that is not dynamic, and remains static no matter who asks for it (such as images, javascript, css, etc). Jersey resources fall under the Dynamic content scenarios. Things generated by your code to be sent back to the end user (browser). As for the error 500, update your question with the stacktrace produced. Also know I cannot comment on Jersey specifics (as I really don't know them. I'm a Jetty developer)
  • Admin
    Admin almost 11 years
    I don't get a stack trace :(, I'm assuming I can just run the program from the main class? Or do I have to run from the project directory? Does that make sense
  • Admin
    Admin almost 11 years
    Noted, the fact that I don't get a stack trace though still pertains to the original question. I just get a 500 error Reason: request failed. No stack trace
  • Nikolay
    Nikolay over 9 years
    I've written a blog post/tutorial partially based on your discussion - wp.me/p48ema-6f. Hope you find it useful.
  • Admin
    Admin over 9 years
    @Nikolay Hey, I haven't had the time to work with Jersey/Jetty in a long time but I think it's awesome you took the time to document the process for other people (I eventually figured it out through painful trial/error)! I realize I never accepted an answer on this question...would you like to create an answer and I'll mark it as correct if you provide the link?
  • Maarten Boekhold
    Maarten Boekhold over 9 years
    @JoakimErdfelt, The above example works with Jersey 2.7, but fails with 2.9/2.14 (and Jetty 9.2.5.v20141112): java.lang.NoSuchMethodError:org.glassfish.jersey.internal.ut‌​il.PropertiesHelper.‌​getValue(Ljava/util/‌​Map;Ljavax/ws/rs/Run‌​timeType;Ljava/lang/‌​String;Ljava/lang/Ob‌​ject;Ljava/lang/Clas‌​s;)Ljava/lang/Object‌​; (Sorry, would provide more stacktrace details, but I don't know how to cleanly insert a stacktrace into this comment box!)
  • AlikElzin-kilaka
    AlikElzin-kilaka about 8 years
    Use ServerProperties.PROVIDER_PACKAGES instead of jersey.config.server.provider.packages.