6

I have written a sample REST service using Jersey2.

Here is my web.xml:

<web-app>
  <display-name>jerseysample</display-name>
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.adaequare.rest.config.JerseyResourceInitializer</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey REST Service</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>

Here is my sample class:

package com.adaequare.resource;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/hello")
public class Hello {
    @GET
    @Produces(MediaType.TEXT_HTML)
    public String sayHtmlHello(){
        return "<html><title>Hello Jersey</title><body><h1>Hello Jersey</h1></body></html>";
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayPlainTextHello() {
        return "Hello Jersey";
    }

    // This method is called if XML is request
    @GET
    @Produces(MediaType.TEXT_XML)
    public String sayXMLHello() {
        return "<?xml version=\"1.0\"?>" + "<hello> Hello Jersey" + "</hello>";
    }

}

I have deployed it to Tomcat and am able to access the following URL:

http://localhost:8080/jerseysample/rest/hello

I tried writing a unit test this way:

package com.adaequare.client;

public class MyResourceTest {
    public static final URI BASE_URI = UriBuilder.fromUri("http://localhost").port(8080).build();
    private HttpServer server;
    private WebTarget target;

    @Before
    public void setUp() throws Exception {

        ResourceConfig rc = new ResourceConfig(Hello.class);
        server = GrizzlyHttpServerFactory.createHttpServer(BASE_URI, rc);

        server.start();
        Client c = ClientBuilder.newClient();
        target = c.target(BASE_URI);
    }

    @After
    public void tearDown() throws Exception {
        server.shutdownNow();
    }


    @Test
    public void testGetIt() {
        String responseMsg = target.path("jerseysample").path("rest").path("hello").request().get(String.class);
        System.out.println("I am here");
        assertEquals("Got it!", responseMsg);
    }
}

This class also throws the exception.

On executing this class, I am getting the following exception:

Exception in thread "main" 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 com.adaequare.client.TestClient.main(TestClient.java:14)

I am sure I am missing some configuration stuff. I have browsed to see the root cause of the issue but to no avail. Can someone please let me know if I am missing something?

The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
Prasanth
  • 1,005
  • 5
  • 19
  • 39

4 Answers4

4

Your service is mapped to (and you are saying you can access it): http://localhost:8080/jerseysample/rest/hello but using your client you are calling http://localhost:8080/restserver/rest/hello which is different URL. What is the surprise?

Try

WebTarget target = ClientBuilder.newClient().target("http://localhost:8080/jerseysample/rest/").path("hello");

As for the second test, try calling getUri() on your WebTarget to see what URL you are actually calling, it should help you see where is the problem.

After your update:

Well first thing is, you haven't specified (in terms of content negotiation) what content your client accepts (you did this in your previous example, which you deleted). But that should not be a problem since in that case server should send you any of implemented ones since by not specifying it you are stating you are supporting all kind of responses. But the problem probably is putting String.class into get() method. There should go an entity you want Jersey to transform the response into. If you want to get String I would do something like this:

Response response = target.path("jerseysample").path("rest").path("hello").
      request().get();
StringWriter responseCopy = new StringWriter();
IOUtils.copy((InputStream) response.getEntity(), responseCopy);

But you can't tell for sure which one of your three method is going to be called since it is on the same PATH, so you should also specify the content by passing it to request method.

TondaCZE
  • 2,590
  • 1
  • 19
  • 20
  • Yes.That's the problem with URI in main method. Thanks for pointing out. After correcting it, it works fine now. But still the unit test is not working. Also it uses the right URL. I checked out the URL and it is http://localhost:8080/jerseysample/rest/hello. Not sure why this works in one case and fails in another one. – Prasanth Mar 08 '14 at 11:12
  • Modified the question accordingly – Prasanth Mar 08 '14 at 11:18
  • I tried target.path("jerseysample").path("rest").path("hello").request().get() and it is still the same. Also I tried target.path("jerseysample").path("rest").path("hello").request(MediaType.TEXT_HTML).get(). In both the cases, here is what I got when I printed the response: 'InboundJaxrsResponse{ClientResponse{method=GET, uri=http://localhost:8080/jerseysample/rest/hello, status=404, reason=Not Found}}' – Prasanth Mar 09 '14 at 05:15
  • But one change is previously when I was doing request().get(String.class), junit is failing. Now after removing it, junit is not failing. But still from the response element, I can see it is a 404 – Prasanth Mar 09 '14 at 05:19
  • Also when I am just using a main method instead of Grizzly, it is working fine. Here is the code of main method: WebTarget target = ClientBuilder.newClient().target("http://localhost:8080/jerseysample/rest/hello"); System.out.println(target.request(MediaType.TEXT_HTML).get(String.class)); And here is the output I got: Hello Jersey

    Hello Jersey

    Just wondering if it is some problem with Grizzly.
    – Prasanth Mar 09 '14 at 05:26
  • It probably is, I tried this example (on Tomcat because that's the set up I have running ATM) and it's working, I get 200 response with content. It would be nice to see whole HTTP request, which is actually being send to the server. Do you have a way to print it out either on client side before sending it or server side after receiving it? – TondaCZE Mar 09 '14 at 11:08
  • I am actually running this as a junit once my jersey rest sample is deployed to tomcat.So I doubt if there is a way that I can get the whole http request. – Prasanth Mar 09 '14 at 11:21
  • Ok, now we are getting somewhere. So you are saying you have your service deployed to Tomcat but at the same time you are deploying it to Grizzly server in the `setUp()` method in your JUnit. Why? Your main method works because you are testing against the service deployed to Tomcat. JUnit doesn't because of that @Before block. Try deleting it and after starting up Tomcat, run the test again. There is of course the question whether you want to do the test against the Grizzly but I don't see much point in testing against something you won't be using in "production". – TondaCZE Mar 09 '14 at 14:05
  • You can also check the port of Grizzly it is starting at. If it is the same as Tomcat, is should not start at all. – TondaCZE Mar 09 '14 at 14:06
0

Hope this helps anyone who can be facing the same problem. In my case, I created my web service RESTful project with the Netbeans Wizard. By any reason, I didn't know why, it missed the ApplicationConfig.java class which contains the annotation @javax.ws.rs.ApplicationPath("webresources"). I don't know why when I generated the client it showed me the correct path that I was expecting.

So, the solution for me was to copy another ApplicationConfig.java from other project and add my facade to the resources.

jmoran
  • 164
  • 1
  • 5
0

if you don't config web.xml to lookup the rest classes you need use @ApplicationPath to indicate the classes that keep the Rest resources.

@ApplicationPath("/rest")
public class AplicationRest extends Application
{
  @Override
  public Set<Class<?>> getClasses()
  {
      Set<Class<?>> resources = new java.util.HashSet<>();
      resources.add(com.acme.SomeRestService.class);
      return resources;
  }
}
Isma
  • 14,604
  • 5
  • 37
  • 51
Alisson Gomes
  • 1,029
  • 14
  • 30
-1

There is an error in web.xml

    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>
            com.adaequare.rest.config.JerseyResourceInitializer
        </param-value>
    </init-param>

please try below

    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>
            com.adaequare.resource.config.JerseyResourceInitializer
        </param-value>
    </init-param>
kiran
  • 1
  • 2
    Why are you sure that that's the problem? Do you know something about his package structure, that we don't know? – Alexander Mar 20 '15 at 11:32