devnull69
devnull69

Reputation: 16544

Cannot get simple RS webservice to work with Eclipse Mars

I followed a few tutorials for settings up a very simple Jersey Webservice which were more than unclear to me.

Sometimes the tutorial was talking about changing the web.xml, others were saying that it is only necessary to have certain annotations in your service class.

So I ended up with the following conclusion:

Using Jersey 2.x you won't have to do anything specific in your web.xml, just have the jersey-container-servlet.jar in your classpath and create your service class as follows:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

@ApplicationPath("rest")
public class RestService extends Application {

    @GET
    @Path("/sayhello")
    @Produces(MediaType.TEXT_PLAIN)
    public Response sayHello() {
        return Response.ok("Hello World").build();
    }

}

This should allow me to access the API using http://localhost:8080/EETest/rest/sayhello

I double checked that the project has been deployed with no error and the Tomcat7 server is running. All the jersey jars and dependencies are in my lib folder and have been added to the project libraries. The modified index.html is showing fine when calling http://localhost:8080/EETest

But the web service is not responding (404 page is showing instead).

I know it must be something very basic I'm doing wrong here ... I'm running out of options.

EDIT: This is my web.xml for what it's worth

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>EETest</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>
</web-app>

Upvotes: 1

Views: 56

Answers (1)

Paul Samsotha
Paul Samsotha

Reputation: 208984

Not sure where you learned to do this

@ApplicationPath("rest")
public class RestService extends Application {

    @GET
    @Path("/sayhello")
    @Produces(MediaType.TEXT_PLAIN)
    public Response sayHello() {
        return Response.ok("Hello World").build();
    }
}

But it's wrong. In JAX-RS, we have resource classes. The resource class should be annotated with @Path, not @ApplicationPath. The Latter is for the application configuration class. So you should have something like

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

@Path("/")
public class RestService {
    @GET
    @Path("/sayhello")
    @Produces(MediaType.TEXT_PLAIN)
    public Response sayHello() {
        return Response.ok("Hello World").build();
    }
}

What the empty class with the @ApplicationPath does is trigger classpath scanning. So the classpath will be scanned for classes that are annotated with @Path and @Provider, and those classes will be registered.

In the example, I used @Path("/") so that you can still use the same URL /rest/sayHello. But generally, the resource class will be have a path mapped to a collection URL, like /rest/animals, so you would use @Path("animals") on the class, and you can add sub-resources with methods in that class also annotated with @Path. Any method not annotated with @Path, but has a method like @GET, will be mapped to the root resource path /rest/animals.

A couple other things. Remember I mentioned the classpath scanning being triggered with the empty Application class annotated with @ApplicationPath. Well this is kind of discouraged. You could register classes explicitly instead

@ApplicationPath("/rest")
public class AppConfig extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        final Set<Class<?>> classes = new HashSet<>();
        classes.add(RestService.class);
        return classes;
    }
}

But when we're using Jersey, it's preferred to use the Jersey specific classes (unless you have a requirement to keep it portable between JAX-RS implementations). With Jersey, you would use it's ResourceConfig class (which is a subclass of Application). You could register individual classes with the register method, of you can trigger package scanning (which is not the same as classpath scanning) using the packages method

@ApplicationPath("/rest")
public class AppConfig extends ResourceConfig {
    public AppConfig() {
        packages("the.packages.to.scan");

        register(RestService.class);
    }
}

Upvotes: 2

Related Questions