Search code examples
jerseyjettyjersey-2.0embedded-jettyhk2

What's the right way to bootstrap Jersey 2 (with Jetty)?


I've managed to hack my way to a working Jersey/Jetty setup with HK2 injection, but given the vast number of somewhat confusing (and at times inconsistent) docs I'm finding, I'm not sure if I've missed some salient detail of getting it right.. As it stands, I'm bootstrapping the servlet like this;

        // Jersey
        ServletContextHandler servletContextHandler = new ServletContextHandler(ServletContextHandler.NO_SESSIONS);
        ServletContainer jerseyServletContainer = new ServletContainer(new AppResourceConfig());
        ServletHolder jerseyServletHolder = new ServletHolder(jerseyServletContainer);
        servletContextHandler.setContextPath("/");
        servletContextHandler.addServlet(jerseyServletHolder, "/api/*");

        // Wire up Jetty
        HandlerCollection handlerList = new HandlerCollection();
        handlerList.setHandlers(new Handler[]{ servletContextHandler });
        Server server = new Server(configuration.getInt("Server.Port"));
        server.setHandler(handlerList);
        server.start();
        server.join();

I define my AppResourceConfig as;

public class AppResourceConfig extends ResourceConfig {
    public AppResourceConfig() {
        register(new AppBinder());
        packages("org.sandbox.resources");
    }
}

And my AppBinder as;

public class AppBinder extends AbstractBinder {
    @Override
    protected void configure() {
        bind(new StringService()).to(StringService.class);
    }
}

This all works for my simple test-case, but I'm unclear on a couple of things. The Jersey docs reference an Application class I should extend, and set up bindings using Injections.addBinding. However to do this they somehow are using @Inject to get a ServiceLocator instance into their constructor. And then they appear to not even create a Binder at all? (https://jersey.java.net/documentation/latest/migration.html -- 26.14.1.1. Injecting custom objects).

Could someone shed some light on whether or not my approach is correct, and perhaps enlighten me as to what the difference is between Application and ResourceConfig and what I should actually be doing to stay consistent with what's intended by the framework?


Solution

  • Application is part of JAX-RS, the REST API defined by Java EE specifications. Jersey is one implementations of that API. You therefore can use the standard Application to set up REST applications with Jersey, as defined by JAX-RS. ResourceConfig extends Application and is an implementation specific enhancement by Jersey. It allows for easier setup, for example adding injections or adding packages to be scanned, like you did in your code.

    The linked documentation does use binders. The examples that don't are referring to the old Jersey 1.x. I think the other examples uses the org.glassfish.jersey.internal.inject.Injections class which is (as the package name implies) an internal class that should not be used. I don't know why they included that in the documentation, it think shouldn't be there. Maybe it once was part of the public API or there is no other way for what is done the example. Anyways, better don't use that class.

    Your approach looks fine. Using features of the Jersey API instead of restricting yourself to pure JAX-RS can make running of your app in containers environment more difficult, if they only provide other JAX-RS frameworks like RestEasy or Apache CFX. If you don't plan to support other frameworks, then leveraging the advantages of Jersey is the way to go.