title: Why is it that @MatrixParam values seem to only come from the final segment?
body: <p>I am exploring the use of <a href="http://www.w3.org/DesignIssues/MatrixURIs.html" rel="noreferrer">MatrixURIs</a> in a JAX-RS application. In the process I've noticed that the <a href="http://jsr311.java.net/nonav/releases/1.1/javax/ws/rs/MatrixParam.html" rel="noreferrer">@MatrixParam</a> annotated parameters seem to only get the matrix parameters from the final segment (which makes trying to use <a href="http://jersey.java.net/nonav/documentation/1.15/user-guide.html#d4e374" rel="noreferrer">sub-resource locators</a> a bit painful). I would like to know if this is a bug, or is part of the spec (and why?), or is simply an undefined crack. </p>
  
  <p>I know that I likely could devise a way to use the @Context injected <a href="http://jsr311.java.net/nonav/releases/1.1/javax/ws/rs/core/UriInfo.html" rel="noreferrer">UriInfo</a> object (which does change depending upon where in the locator chain one finds oneself), but this feels ugly.</p>
  
  <p>Thumbing quickly through the <a href="http://jcp.org/aboutJava/communityprocess/mrel/jsr311/index.html" rel="noreferrer">JAX-RS 1.1 spec</a>... the closest I could find to this not being supported was around: §3.2 </p>
  
  <blockquote>
    <p>Because injection occurs at object creation time, use of these annotations (with the exception of @Context) on resource class fields and bean properties is only supported for the default per-request resource class lifecycle.</p>
  </blockquote>
  
  <p>But that's talking about Constructor/Field injection, not method parameters like in §3.3.2: </p>
  
  <blockquote>
    <p>When a resource method is invoked, parameters annotated with @FormParam or one of the annotations listed in section 3.2 are mapped from the request according to the semantics of the annotation.</p>
  </blockquote>
  
  <p>But of course the semantics of the annotation are seemingly vague. </p>
  
  <h1>Runtime Environment Details:</h1>
  
  <ul>
  <li>Jersey 1.13, 1.15</li>
  <li>Tomcat 7.0.29</li>
  <li>Java 1.6.0_31 (Apple)</li>
  <li>MacOS X 10.7.5</li>
  </ul>
  
  <h1>Example resources:</h1>
  
  <pre><code>public class Zero {
  
      public static final String[] IDS = { "1", "2", "3" };
  
      @GET
      @Produces(MediaType.APPLICATION_JSON)
      public Map&lt;String, Object&gt; getMe(@Context final UriInfo info) {
          final UriBuilder builder = info.getAbsolutePathBuilder().path("one");
          final UriBuilder two = builder.clone().matrixParam("id", "{one}", "{two}");
  
          final List&lt;String&gt; links = new ArrayList&lt;String&gt;();
          for (int i = 0; i &lt; IDS.length; i++) {
              final String first = IDS[i];
              for (int j = i + 1; j &lt; IDS.length; j++) {
                  final String second = IDS[j];
                  links.add(two.build(first, second).toASCIIString());
              }
          }
  
          final Map&lt;String, Object&gt; toReturn = new HashMap&lt;String, Object&gt;();
          toReturn.put("class", getClass().getSimpleName());
          toReturn.put("next", builder.build().toASCIIString());
          toReturn.put("skip", links);
  
          return toReturn;
      }
  
      /*************************/
      /**** &lt;PROBLEM CHILD&gt; ****/
      /*************************/
      @Path("one")
      public Object getNext(@MatrixParam("id") final Set&lt;String&gt; ids) {
          if (ids.isEmpty()) {
              return new One();
          }
          return new Two(ids.toArray(new String[ids.size()]));
      }
      /*************************/
      /**** &lt;/PROBLEM CHILD&gt; ***/
      /*************************/
  
      public static class One {
          @GET
          @Produces(MediaType.APPLICATION_JSON)
          public Map&lt;String, Object&gt; getMe(@Context final UriInfo info) {
              final UriBuilder builder = info.getAbsolutePathBuilder().path("{id}");
              final List&lt;String&gt; links = new ArrayList&lt;String&gt;();
              for (final String id : IDS) {
                  links.add(builder.build(id).toASCIIString());
              }
              final Map&lt;String, Object&gt; toReturn = new HashMap&lt;String, Object&gt;();
              toReturn.put("class", getClass().getSimpleName());
              toReturn.put("next", links);
              toReturn.put("last", getLastURI(info));
              return toReturn;
          }
  
          @Path("{id}")
          public Two getNext(@PathParam("id") final String id) {
              return new Two(id);
          }
      }
  
      public static class Two {
  
          private final String[] myids;
          private final Three three;
  
          public Two(final String... ids) {
              three = new Three(ids);
              myids = ids;
          }
  
          @GET
          @Produces(MediaType.APPLICATION_JSON)
          public Map&lt;String, Object&gt; getMe(@Context final UriInfo info) {
              final UriBuilder builder = info.getAbsolutePathBuilder().path("three");
              final Map&lt;String, Object&gt; toReturn = new HashMap&lt;String, Object&gt;();
              toReturn.put("class", getClass().getSimpleName());
              toReturn.put("ids", myids);
              toReturn.put("next", builder.build().toASCIIString());
              toReturn.put("last", getLastURI(info));
              return toReturn;
          }
  
          @Path("three")
          public Three getNext() {
              return three;
          }
      }
  
      public static class Three {
          private final String[] myids;
  
          public Three(final String... ids) {
              myids = ids;
          }
  
          @GET
          @Produces(MediaType.APPLICATION_JSON)
          public Map&lt;String, Object&gt; getMe(@Context final UriInfo info) {
              final Map&lt;String, Object&gt; toReturn = new HashMap&lt;String, Object&gt;();
              toReturn.put("class", getClass().getSimpleName());
              toReturn.put("ids", myids);
              toReturn.put("last", getLastURI(info));
              return toReturn;
          }
      }
  
      /**
       * Helper method since info.getMatchedURIs doesn't play nice with Matrix Params
       * @param info info object
       * @return parent URI
       */
      public static final String getLastURI(final UriInfo info) {
          final List&lt;PathSegment&gt; segments = info.getPathSegments(false);
          final UriBuilder builder = info.getBaseUriBuilder();
          for (int i = 0; i &lt; segments.size() - 1; i++) {
              final PathSegment segment = segments.get(i);
              builder.path(segment.getPath());
              final MultivaluedMap&lt;String, String&gt; matrixParams = segment.getMatrixParameters();
              if (!matrixParams.isEmpty()) {
                  for (final Map.Entry&lt;String, List&lt;String&gt;&gt; param : matrixParams.entrySet()) {
                      final String name = param.getKey();
                      final String[] values = param.getValue().toArray(new String[param.getValue().size()]);
                      builder.matrixParam(name, values);
                  }
              }
          }
          return builder.build().toASCIIString();
      }
  }
  </code></pre>
  
  <h1>Example Outputs from above:</h1>
  
  <h2><code>http://localhost:8080/context/zero/one/2</code></h2>
  
  <pre><code>{
  "last":"http://localhost:8080/context/zero/one",
  "ids":["2"],
  "next":"http://localhost:8080/context/zero/one/2/three",
  "class":"Two"
  }
  </code></pre>
  
  <h2><code>http://localhost:8080/context/zero/one/2/three</code></h2>
  
  <pre><code>{
  "last":"http://localhost:8080/context/zero/one/2",
  "ids":["2"],
  "class":"Three"
  }
  </code></pre>
  
  <h2><code>http://localhost:8080/context/zero/one;id=1;id=2</code></h2>
  
  <pre><code>{
  "last":"http://localhost:8080/context/zero",
  "ids":["2","1"],
  "next":"http://localhost:8080/context/zero/one;id=1;id=2/three",
  "class":"Two"
  }
  </code></pre>
  
  <h2><code>http://localhost:8080/context/zero/one;id=1;id=2/three</code></h2>
  
  <pre><code>{
  "last": "http://localhost:8080/context/zero/one;id=1;id=2",
  "ids": ["three"],
  "next": "http://localhost:8080/context/zero/one;id=1;id=2/three/three",
  "class": "Two"
  }
  </code></pre>