6

I'm trying to create and deploy a RESTful Web Service using JAX-RS and deploy it to tomcat. I don't want to use any IDE. In Tomcat I have the following directory structure inside webapps\

notifire\WEB-INF\
                 |
                 ---> web.xml
                 |
                 ---> \classes/Notifier.class
                 |
                 ---> \lib\javax.ws.rs-api-2.0

my web.xml contains:

<servlet>
<servlet-name>Web Service Servlet</servlet-name>
<servlet-class>javax.ws.rs.core.Application</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Web Service Servlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>

and the class file Notifier.class was compiled from the file Notifier.java.

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;

@Path("notifier")
public class Notifier {

    @Context
    private UriInfo context;

    @GET
    @Produces("text/html")
    public String getHTML() {

         return "<p></p>";
    }
}

When I try to access the Web Service at http://localhost:8080/notifire/webservice/notifier I get the following error:

--type Exception report

--message Class javax.ws.rs.core.Application is not a Servlet

--description The server encountered an internal error that prevented it from fulfilling this request.

Any help is appreciated.

giannis christofakis
  • 8,201
  • 4
  • 54
  • 65
amedeo avogadro
  • 595
  • 2
  • 7
  • 14

2 Answers2

3

You have the wrong class for your Servlet. Not sure why you are not wanting to use an IDE, but there is a maven archetype that will layout your project structure for you using the appropriate classes that the Jersey developers have defined. My web.xml looks like this:

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>com.pluralsight</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>Jersey Web Application</servlet-name>
    <url-pattern>/webapi/*</url-pattern>
</servlet-mapping>

I cover all of this in this course here.

bh5k
  • 873
  • 6
  • 13
  • BTW, the provider package are just packages in your project. – bh5k Dec 07 '13 at 15:01
  • I changed my web.xml and now I have "HTTP Status 404 - Not Found". I also downloaded the "Jersey JAX-RS 2.0 RI" bundle and put all of its content inside the folder \lib. I don't want to use an IDE for now because I want to learn what happens behind the scene. – amedeo avogadro Dec 07 '13 at 18:09
  • ok now it works...i forgot the package declaration inside the file Notifier.java – amedeo avogadro Dec 07 '13 at 19:54
  • Hi, I am facing same problem. Could you please tell me what exactly did you change in the web.xml? – Bosco Sep 15 '14 at 04:15
  • Are you getting the exact same error? What is the "same problem" that you are facing? – bh5k Sep 15 '14 at 05:54
2

I had trouble getting this to work as well. Since you have to use web.xml anyway, the simplest way to get restful web services working is to forget extending javax.ws.rs.core.Application entirely and just specify the context path there. You can still use standard jax-rs annotations to declare the actual web services.

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app
  xmlns="http://java.sun.com/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
  version="3.0"
>
  <servlet>
    <servlet-name>rest-test</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
      <param-name>com.sun.jersey.config.property.packages</param-name>
      <param-value>com.domain.mypackage</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name> rest-test</servlet-name>
    <url-pattern>/rest/*</url-pattern>
  </servlet-mapping>
</web-app>

Two noteworthy points:

  1. You will need to bundle a REST implementation in your WAR file, since servlet containers don't usually contain one. Since Jersey is the reference implementation for JAX-RS, that's the one I'm using in the servlet-class element above. You can replace this with Apache CXF implementation if you want.

  2. The init-param element tells Jersey which of your packages to search for Java files with web service annotations. Edit this to point to your web services. Note that if you opt to use apache CXF instead of Jersey, the stuff needed in any init-param elements will be different. Someone who knows CXF please post what they would be.

If you're using Maven, just add a dependency to jersey-servlet in the dependencies section of your pom.xml file:

<dependencies>
  <dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-servlet</artifactId>
    <version>1.18.2</version>
  </dependency>
  ...
</dependencies>

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).

Cheers!

* Someone please correct me if you know of a way to a add the Jersey servlet to the context in Tomcat without using web.xml--maybe by using a context or life cycle listener?

Alvin Thompson
  • 5,388
  • 3
  • 26
  • 39
  • See my answer [here](http://stackoverflow.com/questions/9373081/how-to-set-up-jax-rs-application-using-annotations-only-no-web-xml/26721737#26721737) for how to create REST services using annotations only (no web.xml needed). – Alvin Thompson Dec 11 '14 at 20:01