title: Jersey Returning a 405 on a PUT
body: <p>I am having issue with setting up and testing a REST call using embeded Jersey. I keep getting a 405 on a PUT request. </p>
  
  <p>Here are some requests. I used all of the query parameters except one and it has a default value. These URL was generated by the Jersey WebResource in my test client.</p>
  
  <pre><code>curl -i -X PUT "http://localhost:8080/hash/wes?hiddenDirs=false&amp;hiddenFiles=false&amp;id=3edf4867-1211-4ae7-a251-2af28ffac5a2&amp;recursive=false&amp;rehash=false&amp;hashType=SHA1"
  
  curl -i -X PUT "http://localhost:8080/hash/wes?hiddenDirs=false&amp;hiddenFiles=false&amp;id=3edf4867-1211-4ae7-a251-2af28ffac5a2&amp;recursive=false&amp;rehash=false"
  </code></pre>
  
  <p>Here is the basic response of the curl. It does not list PUT but using a OPTIONS request does list the PUT.</p>
  
  <pre><code>HTTP/1.1 405 Method Not Allowed
  Allow: GET,OPTIONS,HEAD
  Content-Length: 0
  Server: Jetty(8.1.17.v20150415)
  </code></pre>
  
  <p>Here is the controller class. I use a lot of constants so the client and service are using the same values. You can see the translation in the output of OPTIONS below.</p>
  
  <pre><code>@Path(Constants.HASH_PATH) // "/hash"
  public class HashController {
  </code></pre>
  
  <p>Here is the method I expect to handle the call.</p>
  
  <pre><code>@PUT
  @Path(Constants.PATH_REST) // "{path : .*}" - I want this to accept directory paths.
  @Produces(MediaType.APPLICATION_JSON)
  public Response hash(@PathParam("path") String path, @QueryParam(Constants.ID_PARAM) String id,
      @QueryParam(Constants.HASH_TYPE_PARAM) @DefaultValue(HashProcessor.DEFAULT_HASH_TYPE) String hashType,
      @QueryParam(Constants.HIDDEN_DIRS_PARAM) @DefaultValue("false") boolean hiddenDirectories,
      @QueryParam(Constants.HIDDEN_FILES_PARAM) @DefaultValue("false") boolean hiddenFiles,
      @QueryParam(Constants.RECURSIVE_PARAM) @DefaultValue("false") boolean recursive,
      @QueryParam(Constants.REHASH_PARAM) @DefaultValue("false") boolean reHashExisting) {
    Response ret = null;
  </code></pre>
  
  <p>I used an OPTIONS request to get the details of the contoller and see the PUT defined.</p>
  
  <pre><code>curl -i -X OPTIONS http://localhost.corp.int:8080/hash &gt; fileSync-hash.xml
  </code></pre>
  
  <p>Here is the output.</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;application xmlns="http://wadl.dev.java.net/2009/02"&gt;
    &lt;doc xmlns:jersey="http://jersey.java.net/" jersey:generatedBy="Jersey: 1.19 02/11/2015 03:25 AM" /&gt;
    &lt;grammars&gt;
      &lt;include href="http://localhost:8080/application.wadl/xsd0.xsd"&gt;
        &lt;doc title="Generated" xml:lang="en" /&gt;
      &lt;/include&gt;
    &lt;/grammars&gt;
    &lt;resources base="http://localhost:8080/"&gt;
      &lt;resource path="hash"&gt;
        &lt;resource path="{path : .*}"&gt;
          &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="path" style="template" type="xs:string" /&gt;
          &lt;method id="hash" name="PUT"&gt;
            &lt;request&gt;
              &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="id" style="query" type="xs:string" /&gt;
              &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="hashType" style="query" type="xs:string" default="SHA1" /&gt;
              &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="hiddenDirs" style="query" type="xs:boolean" default="false" /&gt;
              &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="hiddenFiles" style="query" type="xs:boolean" default="false" /&gt;
              &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="recursive" style="query" type="xs:boolean" default="false" /&gt;
              &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="rehash" style="query" type="xs:boolean" default="false" /&gt;
            &lt;/request&gt;
            &lt;response&gt;
              &lt;representation mediaType="application/json" /&gt;
            &lt;/response&gt;
          &lt;/method&gt;
        &lt;/resource&gt;
        &lt;resource path="{id : [\w\-]*}"&gt;
          &lt;param xmlns:xs="http://www.w3.org/2001/XMLSchema" name="id" style="template" type="xs:string" /&gt;
          &lt;method id="status" name="GET"&gt;
            &lt;response&gt;
              &lt;representation mediaType="application/json" /&gt;
            &lt;/response&gt;
          &lt;/method&gt;
        &lt;/resource&gt;
      &lt;/resource&gt;
    &lt;/resources&gt;
  &lt;/application&gt;
  </code></pre>
  
  <p>Here is the server output from the call.</p>
  
  <pre><code>2015-07-15 15:52:36 DEBUG nio:843 - created SCEP@6319a8b7{l(/10.20.67.195:56641)&lt;-&gt;r(/10.20.67.71:8080),s=0,open=true,ishut=false,oshut=false,rb=false,wb=false,w=true,i=0}-{AsyncHttpConnection@2993b935,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=0},r=0}
  2015-07-15 15:52:36 DEBUG HttpParser:281 - filled 271/271
  2015-07-15 15:52:36 DEBUG Server:365 - REQUEST /hash/wes on AsyncHttpConnection@2993b935,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-5,l=3,c=0},r=1
  2015-07-15 15:52:36 DEBUG ContextHandler:942 - scope null||/hash/wes @ o.e.j.s.ServletContextHandler{/,null}
  2015-07-15 15:52:36 DEBUG ContextHandler:1014 - context=||/hash/wes @ o.e.j.s.ServletContextHandler{/,null}
  2015-07-15 15:52:36 DEBUG ServletHandler:415 - servlet ||/hash/wes -&gt; com.sun.jersey.spi.container.servlet.ServletContainer-68e816f5
  2015-07-15 15:52:36 DEBUG ServletHandler:477 - chain=null
  2015-07-15 15:52:36 DEBUG Server:367 - RESPONSE /hash/wes  405 handled=true
  2015-07-15 15:52:36 DEBUG AsyncHttpConnection:211 - Enabled read interest SCEP@6319a8b7{l(/10.20.67.195:56641)&lt;-&gt;r(/10.20.67.71:8080),s=1,open=true,ishut=false,oshut=false,rb=false,wb=false,w=true,i=0r}-{AsyncHttpConnection@2993b935,g=HttpGenerator{s=4,h=0,b=-1,c=-1},p=HttpParser{s=0,l=3,c=0},r=1}
  2015-07-15 15:52:36 DEBUG ChannelEndPoint:118 - ishut SCEP@6319a8b7{l(/10.20.67.195:56641)&lt;-&gt;r(/10.20.67.71:8080),s=1,open=true,ishut=false,oshut=false,rb=false,wb=false,w=true,i=0r}-{AsyncHttpConnection@2993b935,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=-3},r=1}
  2015-07-15 15:52:36 DEBUG HttpParser:281 - filled -1/0
  2015-07-15 15:52:36 DEBUG AsyncHttpConnection:145 - Disabled read interest while writing response SCEP@6319a8b7{l(/10.20.67.195:56641)&lt;-&gt;r(/10.20.67.71:8080),s=1,open=true,ishut=true,oshut=false,rb=false,wb=false,w=true,i=0r}-{AsyncHttpConnection@2993b935,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=-3},r=1}
  2015-07-15 15:52:36 DEBUG ChannelEndPoint:209 - close SCEP@6319a8b7{l(/10.20.67.195:56641)&lt;-&gt;r(/10.20.67.71:8080),s=1,open=true,ishut=true,oshut=false,rb=false,wb=false,w=true,i=0!}-{AsyncHttpConnection@2993b935,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=-3},r=1}
  2015-07-15 15:52:36 DEBUG nio:852 - destroyEndPoint SCEP@6319a8b7{l(null)&lt;-&gt;r(0.0.0.0/0.0.0.0:8080),s=0,open=false,ishut=true,oshut=true,rb=false,wb=false,w=true,i=0!}-{AsyncHttpConnection@2993b935,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=-3},r=1}
  </code></pre>
  
  <p>I can make a GET call to the same controller. It returns a 404 as expected since the PUT failed but it is my code that is returning the 404 and not Jersey.</p>
  
  <pre><code>curl -i -X GET "http://dsk-107312:8080/hash/3edf4867-1211-4ae7-a251-2af28ffac5a2"
  </code></pre>
  
  <p>Here is some server output as Jersey configures itself in response to the first request. The GET would have failed too if Jersey had not discovered the controller.</p>
  
  <pre><code>Jul 15, 2015 3:46:13 PM com.sun.jersey.api.core.PackagesResourceConfig init
  INFO: Scanning for root resource and provider classes in the packages:
    com.wstrater.server.fileSync.server.handlers
  Jul 15, 2015 3:46:13 PM com.sun.jersey.api.core.ScanningResourceConfig logClasses
  INFO: Root resource classes found:
    class com.wstrater.server.fileSync.server.handlers.FileController
    class com.wstrater.server.fileSync.server.handlers.HelloWorldController
    class com.wstrater.server.fileSync.server.handlers.HashController
    class com.wstrater.server.fileSync.server.handlers.DirectoryController
  Jul 15, 2015 3:46:13 PM com.sun.jersey.api.core.ScanningResourceConfig init
  INFO: No provider classes found.
  Jul 15, 2015 3:46:14 PM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
  INFO: Initiating Jersey application, version 'Jersey: 1.19 02/11/2015 03:25 AM'
  </code></pre>
  
  <p>I have used PUT successfully in other controllers so it must be something simple. In fact I was hoping I would stumble on it writing this post so often happens but not this time.</p>
  
  <p>Thanks, Wes.</p>