Search code examples
jersey-test-framework

Test case for testing a jersey web resource using grizzle is giving me 404


I tried below way which is working fine

package test;

import static org.junit.Assert.assertEquals;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;

    import org.glassfish.jersey.server.ResourceConfig;
    import org.glassfish.jersey.test.DeploymentContext;
    import org.glassfish.jersey.test.JerseyTest;
    import org.glassfish.jersey.test.ServletDeploymentContext;
    import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
    import org.glassfish.jersey.test.spi.TestContainerException;
    import org.glassfish.jersey.test.spi.TestContainerFactory;
    import org.junit.Test;

    import com.mkyong.rest.HelloWorldService;

    public class HelloWorldServiceTest extends JerseyTest{

        @Path("hello")
        public static class HelloResource {
            @GET
            public String getHello() {
                return "Hello World!";
            }
        }

        @Override
        protected Application configure() {
            return new ResourceConfig(HelloResource.class);
        }

        @Override
        protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
            return new GrizzlyWebTestContainerFactory();
        }

        @Override
        protected DeploymentContext configureDeployment() {
            return ServletDeploymentContext.forPackages(
                    getClass().getPackage().getName()).build();
        }

        @Test
        public void testSingleNode() throws Exception {
            final String hello = target("hello").request().get(String.class);
            assertEquals("Hello World!", hello);
        }
        }

When i tried to replace the resource with resource which is outside of this test class and package like below

   package test;

import static org.junit.Assert.assertEquals;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.ServletDeploymentContext;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.glassfish.jersey.test.spi.TestContainerException;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.junit.Test;

import com.mkyong.rest.HelloWorldService;

public class HelloWorldServiceTest extends JerseyTest{

    @Path("hello")
    public static class HelloResource {
        @GET
        public String getHello() {
            return "Hello World!";
        }
    }

    @Override
    protected Application configure() {
        return new ResourceConfig(HelloWorldService.class);
    }

    @Override
    protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
        return new GrizzlyWebTestContainerFactory();
    }

    @Override
    protected DeploymentContext configureDeployment() {
        return ServletDeploymentContext.forPackages(
                getClass().getPackage().getName()).build();
    }

    @Test
    public void testSingleNode() throws Exception {
        final String hello = target("hello").path("Test").request().get(String.class);
        assertEquals("Jersey say : Test", hello);
    }
    }

HelloWorldService.java

package com.mkyong.rest;

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

@Path("/hello")
public class HelloWorldService {

    @GET
    @Path("/{param}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getMsg(@PathParam("param") String msg) {

        String output = "Jersey say : " + msg;

        return Response.status(200).entity(output).build();

    }

}

RestApplication.java

      package rest;

import java.util.HashSet;
import java.util.Set;

import javax.ws.rs.core.Application;

import com.mkyong.rest.HelloWorldService;

public class RestApplication extends Application{

      @Override
        public Set<Class<?>> getClasses() {
            Set<Class<?>> s = new HashSet<Class<?>>();

            s.add(HelloWorldService.class);
            return s;
        }


}

web.xml

<web-app id="WebApp_ID" version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>Restful Web Application</display-name>

     <servlet>
    <servlet-name>rs-servlet</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>rest.RestApplication</param-value>
</init-param>
  </servlet>
  <servlet-mapping>
  <servlet-name>rs-servlet</servlet-name>
  <url-pattern>/rest/*</url-pattern>
</servlet-mapping>

</web-app>

I got an exception

   javax.ws.rs.NotFoundException: HTTP 404 Not Found
at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:917)
at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:770)
at org.glassfish.jersey.client.JerseyInvocation.access$500(JerseyInvocation.java:90)
at org.glassfish.jersey.client.JerseyInvocation$2.call(JerseyInvocation.java:671)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:423)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:667)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:396)
at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:296)
at test.HelloWorldServiceTest.testSingleNode(HelloWorldServiceTest.java:48) 

Can any one correct me where i went wrong...


Solution

  • Look at this

    @Override
    protected DeploymentContext configureDeployment() {
        return ServletDeploymentContext.forPackages(
                getClass().getPackage().getName()).build();
    }
    

    The forPackages is saying what package to scan for @Path and @Provider annotated classes, and automatically register them. The reason it works in the first example is that the resource class (the class annotated with @Path is in the getClass().getPackage().getName() package.

    This method

    @Override
    protected Application configure() {
        return new ResourceConfig(HelloWorldService.class);
    }
    

    is never called, because you override the getDeploymentContext(). Normally, if you don't override that method, it will call the configure method to register the application with the deployment context. But you neve do this.

    So instead of the forPackages, you should use one of the ServletDeploymentContext.builder methods, that accept an Application class

    return ServletDeploymentContext.builder(configure()).build()
    
    return ServletDeploymentContext.builder(RestApplication.class).build();
    

    OR

    @Override
    public ResourceConfig configure() {
        return new ResourceConfig(HelloWorldService.class);
    }
    
    @Override
    public ServletDeploymentContext configureDeployment() {
        return SerlvetDeploymentContext.forServlet(new ServletContainer(configure));
    }
    

    One thing to note it that you only need to override the getTestContainerFactory and the configureDeployment if you wan to set up a servlet environment. Meaning, you need to use servlet APIs like HttpServletRequest, ServletContext, etc, in your application. If you don't need a servlet environment, just overriding configure is enough.