title: URI Recognition in Java Using JAX-RS @Path Annotations at Class and Method Level
body: <p>I've created a situation in a Resource class where I'm receiving 404s for all 3 endpoints and was hoping someone could help explain why.  Here is my resource class:</p>
  
  <pre><code>@Path("/incidents")
  public class RegistrationResource {
  
      @GET
      @Path("/{incidentId}/registration")
      public Response getRegisteredIncidents(@PathParam("incidentId") String incidentId) {
             ...
      }
  
      @GET
      @Path("/registration/download")
      public Response downloadRegistrationIncidentsReport() {
             ...
      }
  
      @GET
      @Path("/registration/email")
      public Response emailRegistrationIncidentsReport() {
             ...
      }
  }
  </code></pre>
  
  <p>I'm also using the JAX-RS <a href="http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/Application.html" rel="nofollow">Application</a> class to register my resources and set a base "context" path across all of the endpoints:</p>
  
  <pre><code>@ApplicationPath("/context") 
  public class AdminApplication extends Application { 
  
      @Override
      public Set&lt;Class&lt;?&gt;&gt; getClasses() { 
  
          Set&lt;Class&lt;?&gt;&gt; resources = new HashSet&lt;Class&lt;?&gt;&gt;();
  
          resources.add(RegistrationResource.class);
  
          ...
  
          return resources;
      }
  }
  </code></pre>
  
  <p>Now if I split these methods into more than one resource class I can get each service to work fine, but my question is why won't the design above work?  The full endpoints I'm trying to call here in order of the methods above are:</p>
  
  <pre><code>/context/incidents/55/registration
  /context/incidents/registration/download
  /context/incidents/registration/email
  </code></pre>
  
  <p>Why are the mappings above not being found?  With this design I'm getting a 404 for each of the endpoints.</p>
  
  <blockquote>
    <p>org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (404 - Not Found) with message 'null' while processing GET request sent to <a href="http://localhost:9081/someapp/context/incidents/55/registration" rel="nofollow">http://localhost:9081/someapp/context/incidents/55/registration</a></p>
  </blockquote>
  
  <p>As a further point of clarification I'm using Wink 1.1 as my JAX-RS implementation since I'm bound to the packaged version that comes with WebSphere 8.5.5.5 at this time.</p>
  
  <p>Thanks for your time!</p>
  
  <p><strong>-----------UPDATE #1-----------</strong></p>
  
  <p>In light of the comments below I have modified some of the endpoints.  However I am still receiving random failures on certain endpoints with either 404 or, interestingly, 405 errors.  It's important to note that if I redeploy sometimes different endpoints will fail, or perhaps all will work.  Then if I redeploy again I will get similar, but different results of certain endpoints failing or all working.  The bottom line is that it is very inconsistent. </p>
  
  <p>Because of that it seems as if more endpoints are conflicting than in my original post so I am pasting <em>all</em> of my endpoints here for the sake of completeness.</p>
  
  <pre><code>/* Public Service Set */
  
  @ApplicationPath("/public") 
  public class PublicApplication extends Application { 
  
      @Override
      public Set&lt;Class&lt;?&gt;&gt; getClasses() { 
  
          Set&lt;Class&lt;?&gt;&gt; resources = new HashSet&lt;Class&lt;?&gt;&gt;();
  
          resources.add(IncidentResource.class);
          resources.add(IncidentDetailsResource.class);
          resources.add(TicketResource.class);
          resources.add(RegistrationResource.class);
  
          return resources;
      }
  }
  
  @Path("/incidents")
  public class IncidentResource { 
  
      @GET
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getIncidents() throws Exception {
      //...
      } 
  
  @Path("/")
  public class IncidentDetailsResource {
  
      @GET
      @Path("/v1/incidents/{incidentId}/details")
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getIncidentDetails(@PathParam("incidentId") String incidentId) throws Exception {
      //...
      }
  
      @GET
      @Path("/v2/incidents/{incidentId}/details")
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getIncidentDetailsAsJson(@PathParam("incidentId") String incidentId) throws Exception {
      //...
      }
  
  }
  
  @Path("/incidents/{incidentId}/tickets") 
  public class TicketResource {
  
      @GET
      @Produces(MediaType.APPLICATION_JSON)
      public Response getTickets(@PathParam("incidentId") String incidentId) throws Exception {
      //...
      }
  }
  
  
  @Path("/incidents")
  public class RegistrationResource {
  
      @POST
      @Path("/{incidentId}/registration")
      @Consumes(MediaType.APPLICATION_JSON)
      public Response register(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;IncidentRegistrationRequest&gt; baseRequestMessage) throws Exception {
      //...
      }
  }
  
  /* Admin Service Set */
  
  @ApplicationPath("/admin") 
  public class AdminApplication extends Application { 
  
      @Override
      public Set&lt;Class&lt;?&gt;&gt; getClasses() { 
  
          Set&lt;Class&lt;?&gt;&gt; resources = new HashSet&lt;Class&lt;?&gt;&gt;();
  
          resources.add(AdminIncidentResource.class);
          resources.add(AdminIncidentDetailsResource.class);
          resources.add(AdminRegistrationResource.class);
          resources.add(AdminRegistrationReportResource.class);
          resources.add(AdminTicketResource.class);
  
          return resources;
      }
  }
  
  @Path("/incidents")
  public class AdminIncidentResource { 
  
      @POST
      @Consumes(MediaType.APPLICATION_JSON)
      public Response addIncident(BaseRequestMessage&lt;IncidentRequest&gt; baseRequestMessage) throws Exception {
      //...
      }
  
      @PUT 
      @Path("/{incidentId}")
      @Produces(MediaType.APPLICATION_JSON)
      public Response updateIncident(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;IncidentRequest&gt; baseRequestMessage) throws Exception {
      //...
      }
  
      @DELETE 
      @Path("/{incidentId}")
      @Produces(MediaType.APPLICATION_JSON)
      public Response deleteIncident(@PathParam("incidentId") String incidentId) throws Exception {
      //...
      }
  }
  
  @Path("/")
  public class AdminIncidentDetailsResource {
  
      @PUT
      @Path("/v1/incidents/{incidentId}/details")
      @Consumes(MediaType.APPLICATION_JSON)
      public Response updateIncidentDetails(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;IncidentDetailRequest&gt; baseRequestMessage) throws Exception {
      //...    
      }
  
      @PUT
      @Path("/v2/incidents/{incidentId}/details")
      @Consumes(MediaType.APPLICATION_JSON)
      public Response updateIncidentDetailsAsJson(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;JsonNode&gt; baseRequestMessage) throws Exception {
      //...
      }
  }
  
  @Path("/incidents/{incidentId}/tickets")
  public class AdminTicketResource {
  
      @POST
      @Consumes(MediaType.APPLICATION_JSON) 
      public Response addTicket(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;TicketRequest&gt; baseRequestMessage) throws Exception {
      //...   
      }
  
      @PUT
      @Consumes(MediaType.APPLICATION_JSON) 
      public Response updateTicket(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;TicketRequest&gt; baseRequestMessage) throws Exception {
      //...    
      }
  
      @DELETE
      @Path("/{detailsUrn}")
      @Consumes(MediaType.APPLICATION_JSON) 
      public Response removeTicket(@PathParam("incidentId") String incidentId, @PathParam("detailsUrn") String detailsUrn) throws Exception {
      //...    
      }
  
  }
  
  @Path("/incidents/registration/report")
  public class AdminRegistrationReportResource {
  
      @GET
      @Path("/download")
      @Produces("application/vnd.ms-excel")
      public Response downloadRegistrationReport() throws Exception { 
      //...    
      }
  
      @GET
      @Path("/email")
      @Produces(MediaType.APPLICATION_JSON)
      public Response emailRegistrationReport() throws Exception { 
      //...    
      }
  }
  
  @Path("/incidents/{incidentId}/registration")
  public class AdminRegistrationResource {
  
      @GET
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getRegisteredUsers(@PathParam("incidentId") String incidentId) throws Exception { 
      //...    
      }
  
      @PUT
      @Consumes(MediaType.APPLICATION_JSON)
      public Response updateRegisteredUser(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;IncidentRegistrationRequest&gt; baseRequestMessage) throws Exception {
      //...    
      }
  }
  </code></pre>
  
  <p>For sake of expediency...the code above ends up generating these uris:</p>
  
  <ul>
  <li>GET    /public/incidents</li>
  <li>GET    /public/v1/incidents/{incidentId}/details</li>
  <li>GET    /public/v2/incidents/{incidentId}/details</li>
  <li>GET    /public/incidents/{incidentId}/tickets</li>
  <li><p>POST   /public/incidents/{incidentId}/registration</p></li>
  <li><p>POST   /admin/incidents</p></li>
  <li>PUT    /admin/incidents/{incidentId}</li>
  <li>DELETE /admin/incidents/{incidentId}</li>
  <li>PUT    /admin/v1/incidents/{incidentId}/details</li>
  <li>PUT    /admin/v2/incidents/{incidentId}/details</li>
  <li>POST   /admin/incidents/{incidentId}/tickets</li>
  <li>PUT    /admin/incidents/{incidentId}/tickets</li>
  <li>DELETE /admin/incidents/{incidentId}/tickets/{detailsUrn}</li>
  <li>GET    /admin/incidents/registration/report/download</li>
  <li>GET    /admin/incidents/registration/report/email</li>
  <li>GET    /admin/incidents/{incidentId}/registration</li>
  <li>PUT    /admin/incidents/{incidentId}/registration</li>
  </ul>
  
  <p>That's a lot of code; I wanted to avoid that originally but it seems it is necessary.  Also, for what it is worth, things seemed to be working until I added the <code>AdminRegistrationResource</code> class.  Perhaps something with one of the endpoints in that class began causing a conflict?</p>
  
  <p>Again...thanks for your time!</p>
  
  <p><strong>-----------UPDATE #2-----------</strong></p>
  
  <p>I'd thought I'd post one of my recent specific errors here in the hopes that it may help in solving the issue.  When I call this endpoint:</p>
  
  <blockquote>
    <p>GET    /public/incidents</p>
  </blockquote>
  
  <p>I'm receiving this error message:  </p>
  
  <pre><code>00000203 ResourceRegis I org.apache.wink.server.internal.registry.ResourceRegistry filterDispatchMethods The system cannot find any method in the com.somewhere.unimportant.rest.resource.external.RegistrationResource class that supports GET. Verify that a method exists.
  
  00000203 RequestProces I org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (405) with message 'null' while processing GET request sent to https://test.somewhere.com:88888/app777/public/events
  </code></pre>
  
  <p>Now what's even more interesting about this is that I receive this error locally, but I've also pushed my code up to a test environment where there are two load-balanced servers.  In the test environment I receive this error on one of the servers consistently but the other one works consistently.  So a 50% failure rate split on one successful server and one unsuccessful server.</p>
  
  <p>Strange...why is it looking in that class for the endpoint I'm hitting?</p>
  
  <p><strong>-----------UPDATE #3-----------</strong></p>
  
  <p>Ok, I've taken out the use of the @ApplicationPath annotation in my PublicApplication class completely (as suggested from the comments below) and replaced it with a mere "/" but still receive a 404 error in the following scenario (note that for this test I have completely removed the "admin" services):</p>
  
  <pre><code>/* Public (and only) Service Set */
  
  @ApplicationPath("/") 
  public class PublicApplication extends Application { 
  
      @Override
      public Set&lt;Class&lt;?&gt;&gt; getClasses() { 
  
          Set&lt;Class&lt;?&gt;&gt; resources = new HashSet&lt;Class&lt;?&gt;&gt;();
  
          resources.add(IncidentResource.class);
          resources.add(IncidentDetailsResource.class);
          resources.add(TicketResource.class);
          resources.add(RegistrationResource.class);
  
          return resources;
      }
  }
  
  @Path("/public")
  public class IncidentResource { 
  
      @GET
      @Path("/incidents")
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getIncidents() throws Exception {
      //...
      } 
  
  @Path("/public")
  public class IncidentDetailsResource {
  
      @GET
      @Path("/v1/incidents/{incidentId}/details")
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getIncidentDetails(@PathParam("incidentId") String incidentId) throws Exception {
      //...
      }
  
      @GET
      @Path("/v2/incidents/{incidentId}/details")
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getIncidentDetailsAsJson(@PathParam("incidentId") String incidentId) throws Exception {
      //...
      }
  
  }
  
  @Path("/public/incidents/{incidentId}/tickets") 
  public class TicketResource {
  
      @GET
      @Produces(MediaType.APPLICATION_JSON)
      public Response getTickets(@PathParam("incidentId") String incidentId) throws Exception {
      //...
      }
  }
  
  @Path("/public/incidents/{incidentId}/registration")
  public class RegistrationResource {
  
      @POST
      @Consumes(MediaType.APPLICATION_JSON)
      public Response register(@PathParam("incidentId") String incidentId, BaseRequestMessage&lt;IncidentRegistrationRequest&gt; baseRequestMessage) throws Exception {
      //...
      }
  }
  </code></pre>
  
  <p>In this scenario I am getting this error:</p>
  
  <pre><code>org.apache.wink.server.internal.RequestProcessor logException The following error occurred during the invocation of the handlers chain: WebApplicationException (404 - Not Found) with message 'null' while processing GET request sent to http://test.somewhere.com:88888/app777/public/events
  </code></pre>
  
  <p>when trying to call:</p>
  
  <blockquote>
    <p>GET    /public/incidents</p>
  </blockquote>
  
  <p>It may also be relevant that the other 4 endpoints above work just fine.  And, <em>more importantly</em>, if I change the IncidentResource class to look like the following (moving the @Path annotation at the method level completely to the class level) then <strong>all</strong> 5 endpoints work:</p>
  
  <pre><code>@Path("/public/incidents")
  public class IncidentResource { 
  
      @GET
      @Produces(MediaType.APPLICATION_JSON) 
      public Response getIncidents() throws Exception {
      //...
      } 
  </code></pre>
  
  <p>I appreciate everyone who has stayed with me this far!</p>