4

I have read that from JavaEE 6 web.xml is optional.

So without web.xml, how can I tell the application server to use Jersey as the implementation for JAX-RS specification?

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
DesirePRG
  • 6,122
  • 15
  • 69
  • 114

2 Answers2

20

What @AlexNevidomsky wrote in his answer is correct, as far as how to implement the app configuration with no web.xml; you use an @ApplicationPath annotation on an Application subclass.

@ApplicationPath("/api")
public class AppConfig extends Application {}

For more information on deployment options, see the Jersey Docs: Chapter 4. Application Deployment and Runtime Environments

Or more commonly, with Jersey as implementation, we would extend ResourceConfig (which extends Application).

@ApplicationPath("api")
public class AppConfig extends ResourceConfig {
    public AppConfig() {
        packages("package.to.scan");
    }
}

So how is this implemented...

First things first, not all Java EE servers use Jersey. Actually the only ones I know that use Jersey are Glassfish and WebLogic. JBoss uses Resteasy. Tom EE uses CXF. WebSphere uses Apache Wink. Those are the only ones I can think of.

So I guess the question is "How does the Server know how to load the JAX-RS application?"

Servlet 3.0 introduced the pluggability mechanism, which makes use of a ServletContainerInitializer. How it works is that when the Server/Servlet container is started, it scans jars for a META-INF/services folder with a file named javax.servlet.ServletContainerInitializer. This file should include one or more fully qualified names of implementations of the ServletContainerInitializer.

This interface has only one method

void onStartup(java.util.Set<java.lang.Class<?>> c, ServletContext ctx)

The Set<Class<?> will be a list of classes, fitting the criteria in the @HandlesTypes annotation on the ServletContainerInitializer implementation. If you look at Jersey's implementation

@HandlesTypes({ Path.class, Provider.class, Application.class, ApplicationPath.class })
public final class JerseyServletContainerInitializer 
                   implements ServletContainerInitializer {

You should notice some familiar annotation classes, as well as the Application.class. All these classes matching the criteria, while scanning, are added to the Set passed to the onStartup method.

If you scan the rest of the source code, you will see all the registration being done with all of those classes.

Resteasy uses

@HandlesTypes({Application.class, Path.class, Provider.class})
public class ResteasyServletInitializer implements ServletContainerInitializer

I won't get into to others.

Some source you can look at...

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • So, can I delete web.xml in my Jersey project? – BAE Dec 14 '17 at 15:24
  • @mFeinstein You need a _complete_ JAX-RS implementation. Tomcat does not have one. – Paul Samsotha Apr 02 '19 at 05:31
  • After lots of searching, I made it work with HK2 DI, In my case (I am using the AWS Lambda Serverless Framework for Jersey and Tomcat for local testing) I needed to add `implementation 'org.glassfish.jersey.containers:jersey-container-servlet:2.28'` and change Tomcat `webapp` folder permission on Windows 10, because IntelliJ can't deploy inside `Program Files`. – Michel Feinstein Apr 02 '19 at 05:36
  • @PaulSamsotha curiously, I can't make it work on GlassFish 5. it crashes if I add HK2 DI, I guess GlassFish CDI doesn't play well with it. – Michel Feinstein Apr 02 '19 at 05:38
  • @mFeinstein If you are using Maven, make all your Jersey dependencies `provided` in scope. Glassfish already has all the jars in its library. You will just need them for your app to compile. – Paul Samsotha Apr 02 '19 at 05:46
  • Yes, they were like this (but in Gradle), but I changed them for Tomcat, as Tomcat needs them at runtime. – Michel Feinstein Apr 02 '19 at 05:48
1

You don't have to specify anything in web.xml. Define an activator class:

@ApplicationPath("/rest")
public class _JaxRsActivator extends javax.ws.rs.core.Application {

  static {
      //Check some system init on REST init.
      Config.initCheck();
  }
}
Alex Nevidomsky
  • 668
  • 7
  • 14
  • But how does the server know to use jersey? – DesirePRG Apr 19 '15 at 12:37
  • If you are interested in technical details, take note that you define a path mapping there. So on the first request for this path prefix the initialization happens: the servlet container calls ResteasyDeployment.start(). At least that's what JBoss does. – Alex Nevidomsky Apr 19 '15 at 13:00