How to set up JAX-RS Application using annotations only (no web.xml)?

JavaJakarta EeJax RsServlet 3.0

Java Problem Overview


Is it possible to set up a JAX-RS application using annotations only? (using Servlet 3.0 and JAX-RS Jersey 1.1.0)

I tried and had no luck. Using some web.xml seems required.


Configuration A (working, but has web.xml configuration)

web.xml

   ...
   <servlet>
      <servlet-name>org.foo.rest.MyApplication</servlet-name>
   </servlet>
   <servlet-mapping>
       <servlet-name>org.foo.rest.MyApplication</servlet-name>
       <url-pattern>/*</url-pattern>
   </servlet-mapping>
   ...

Java

@ApplicationPath("/")
public class MyApplication extends Application {
	...
}

Configuration B (not working, exception thrown)

@ApplicationPath("/")
@WebServlet("/*") // <-- 
public class MyApplication extends Application {
	...
}

The latter seems to insist that the Application will be a subclass of Servlet (the exception leaves no guesswork)

java.lang.ClassCastException: org.foo.rest.MyApplication cannot be cast to javax.servlet.Servlet

Questions

  1. Why the web.xml definition worked but the annotation didn't? What's the difference?

  2. Is there a way to have it worked, e.g. have a JAX-RS Application with no web.xml?

Java Solutions


Solution 1 - Java

** PLEASE READ IF YOU USE TOMCAT OR JETTY! **

The accepted answer does work, but only if the webapp is deployed to an app server like Glassfish or Wildfly, and possibly servlet containers with EE extensions like TomEE. It doesn't work on standard servlet containers like Tomcat, which I'm sure most people looking for a solution here want to use.

If you're using a standard Tomcat install (or some other servlet container), you need to include a REST implementation since Tomcat doesn't come with one. If you're using Maven, add this to the dependencies section:

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.bundles</groupId>
    <artifactId>jaxrs-ri</artifactId>
    <version>2.13</version>
  </dependency>
  ...
</dependencies>

Then just add an application config class to your project. If you don't have any special configuration needs aside from setting the context path for the rest services, the class can be empty. Once this class is added, you don't need to configure anything in web.xml (or have one at all):

package com.domain.mypackage;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("rest") // set the path to REST web services
public class ApplicationConfig extends Application {}

After this, declaring your web services is straight forward using the standard JAX-RS annotations in your Java classes:

package com.domain.mypackage;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;

// It's good practice to include a version number in the path so you can have
// multiple versions deployed at once. That way consumers don't need to upgrade
// right away if things are working for them.
@Path("calc/1.0")
public class CalculatorV1_0 {
  @GET
  @Consumes("text/plain")
  @Produces("text/plain")
  @Path("addTwoNumbers")
  public String add(@MatrixParam("firstNumber") int n1, @MatrixParam("secondNumber") int n2) {
    return String.valueOf(n1 + n2);
  }
}

This should be all you need. If your Tomcat install is running locally on port 8080 and you deploy your WAR file to the context myContext, going to...

http://localhost:8080/myContext/rest/calc/1.0/addTwoNumbers;firstNumber=2;secondNumber=3

...should produce the expected result (5).

Solution 2 - Java

It seems that all I needed to do is this (Servlet 3.0 and above)

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/*")
public class MyApplication extends Application {
    ...
}

And no web.xml configuration was apparently needed (tried on Tomcat 7)

Solution 3 - Java

Chapter 2 of the JAX-RS: Java™ API for RESTful Web Services specification describes the publication process of a JAX-RS application in Servlet environment (section 2.3.2 Servlet in the specification).

Please note that Servlet 3 environment is recommended only (section 2.3.2 Servlet, page 6):

> It is RECOMMENDED that implementations support the Servlet 3 > framework pluggability mechanism to enable portability between > containers and to avail themselves of container-supplied class > scanning facilities.

In short, if you want to use a no-web.xml approach, it's possible with a custom implementation of javax.ws.rs.core.Application that registers RESTful service resources with the javax.ws.rs.ApplicationPath annotation.

@ApplicationPath("/rest")

Although you asked specifically about Jersey you may also like to read the article Implementing RESTful services with JAX-RS and WebSphere 8.5 Liberty Profile in which I described the no-web.xml publication process for WebSphere Liberty Profile (with Apache Wink as the implementation of JAX-RS).

Solution 4 - Java

You need to setup the right dependencies in pom.xml

<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
		<version>3.0.1</version>
		<scope>provided</scope>
	</dependency>
	<dependency>
		<groupId>org.glassfish.jersey.containers</groupId>
		<artifactId>jersey-container-servlet</artifactId>
	</dependency>

More details here: Starter example for jax-rs

Solution 5 - Java

The previously mentioned dependencies did not work for me. From the Jersey User guide:

> Jersey provides two Servlet modules. The first module is the Jersey core Servlet module that provides the core Servlet integration support and is required in any Servlet 2.5 or higher container:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet-core</artifactId>
</dependency>

> To support additional Servlet 3.x deployment modes and asynchronous JAX-RS resource programming model, an additional Jersey module is required:

<dependency>
 <groupId>org.glassfish.jersey.containers</groupId>
 <artifactId>jersey-container-servlet</artifactId>
</dependency>

> The jersey-container-servlet module depends on jersey-container-servlet-core module, therefore when it is used, it is not necessary to explicitly declare the jersey-container-servlet-core dependency.

https://jersey.github.io/documentation/latest/deployment.html#deployment.servlet.3

Solution 6 - Java

As @Eran-Medan pointed out, JBoss EAP 7.1 (note without a Web Application so no servlet, I was doing it in a EJB 3.2 project) I had to add the "value" attribute as such as I was getting an exception that the value attribute was required.

This worked for me

    @ApplicationPath(value="/*")
public class MyApplication extends Application {



        private Set<Object> singletons = new HashSet<Object>();
    
        public MyApplication() {
            singletons.add(new MyService());
        }
        
        ...
}</code></pre>




Stack Trace


    Caused by: java.lang.annotation.IncompleteAnnotationException: javax.ws.rs.ApplicationPath missing element value
at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:80)
at com.sun.proxy.$Proxy141.value(Unknown Source)
... 21 more


Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEran MedanView Question on Stackoverflow
Solution 1 - JavaAlvin ThompsonView Answer on Stackoverflow
Solution 2 - JavaEran MedanView Answer on Stackoverflow
Solution 3 - JavaJacek LaskowskiView Answer on Stackoverflow
Solution 4 - JavaACVView Answer on Stackoverflow
Solution 5 - JavabzakView Answer on Stackoverflow
Solution 6 - JavaJGlassView Answer on Stackoverflow