title: Spring MVC, REST, JSON, and DispatcherServlet and @RequestMapping
body: <p>I cannot seem to get a simple REST client integration test going.  I am using Spring 3.1 MVC with a JavaConfig setup.  I use Maven, and I can build, run and deploy my current  webapp with no problems.  </p>
  
  <p>First, here's some code and config</p>
  
  <p>My controller</p>
  
  <pre><code>@Controller
  @RequestMapping("/rest")
  public class StubRestController {
  
  @Inject
  private TestData testData;
  
  @RequestMapping(value=Endpoints.GET_RESOURCES, method=RequestMethod.GET, produces="application/json")
  @ResponseStatus(HttpStatus.OK)
  public @ResponseBody JSONObject getResources(@RequestParam(value="q") String query, @RequestParam int indexFrom, @RequestParam int indexTo) throws JSONException {
      return makeRequest(query, indexFrom, indexTo, testData.getResources());
  }
  
  @RequestMapping(value=Endpoints.GET_LOCATIONS, method=RequestMethod.GET, produces="application/json")
  @ResponseStatus(HttpStatus.OK)
  public @ResponseBody JSONObject getLocations(@RequestParam(value="q") String query, @RequestParam int indexFrom, @RequestParam int indexTo) throws JSONException {
      return makeRequest(query, indexFrom, indexTo, testData.getLocations());
  }
  
  private JSONObject makeRequest(String query, int indexFrom, int indexTo, String[] data) throws JSONException {
      int count = 0;
      final JSONArray resources = new JSONArray();
      for (final String resourceName: data) {
          final String lowerColor = resourceName.toLowerCase();
          final int has = lowerColor.indexOf(query.toLowerCase());
  
          if (!query.isEmpty() &amp;&amp; (query.equals("*") || has &gt;= 0)) {
              final JSONObject resource = new JSONObject();
              resource.put("DisplayName", resourceName);
              resource.put("Value", resourceName);   // shouldn't this be a unique id?  e.g., resourceid
              resources.put(resource);
              count++;
          }
      }
  
      final JSONArray partial = new JSONArray();
      if (resources.length() &gt; 0) {
          final int end = count - 1 &gt; indexTo ? indexTo : count - 1;
          for (int i = indexFrom; i &lt;= end; i++) {
              partial.put(resources.get(i));
          }
      }
  
      final JSONObject result = new JSONObject();
      result.put("TotalSize", count);
      result.put("Options", partial);
      return result;
  }
  
  @ExceptionHandler(JSONException.class)
  @ResponseStatus(value = HttpStatus.NOT_FOUND, reason="No data found matching criteria")
  public void notFound() { }
  }
  </code></pre>
  
  <p>My test</p>
  
  <pre><code>@ContextConfiguration(classes={ RestClientContext.class }, loader=AnnotationConfigContextLoader.class)
  @RunWith(SpringJUnit4ClassRunner.class)
  public class StubRestClientITCase {
  
  private static final String SCHEME = "http";
  private static final String HOST = "localhost";
  private static final int PORT = 8081;
  
  // requests must match &lt;url-pattern&gt; in order to be handled by DispatcherServlet
  private static final String ENDPOINT_PREFIX = "spp-emkt-mui-experimental/EMKT/services/rest";
  
  private static final String QUERY_KEY = "q";
  private static final String INDEX_FROM_KEY = "indexFrom";
  private static final String INDEX_TO_KEY = "indexTo";
  private static final String TOTAL_SIZE_KEY = "TotalSize";
  
  private Logger log = LoggerFactory.getLogger(StubRestClientITCase.class);
  
  @Inject
  RestTemplate restTemplate;
  
  @Test
  public void testGetResources() {
  
      // Case 1:  Discover all resources using * (asterisk), first 25
      final URI uri = buildUri("*", 0, 24, Endpoints.GET_RESOURCES);
      final HttpEntity&lt;JSONObject&gt; response = obtainResponse(uri);
  
      try {
          Assert.assertTrue(response.hasBody());
          Assert.assertEquals(25, Integer.parseInt(response.getBody().getString(TOTAL_SIZE_KEY)));
      } catch (final JSONException je) {
          fail("Could not obtain \"" + TOTAL_SIZE_KEY + "\" from JSON payload for getResources().\n" + je.getMessage());
      }
  
  }
  
  private URI buildUri(String query, int indexFrom, int indexTo, String endPointUrl) {
      final UriComponents uriComponents =
              UriComponentsBuilder.newInstance()
              .scheme(SCHEME).host(HOST).port(PORT).path(ENDPOINT_PREFIX + endPointUrl)
              .queryParam(QUERY_KEY, query)
              .queryParam(INDEX_FROM_KEY, indexFrom)
              .queryParam(INDEX_TO_KEY, indexTo)
              .build()
              .encode();
  
      final URI uri = uriComponents.toUri();
      return uri;
  }
  
  private HttpEntity&lt;JSONObject&gt; obtainResponse(URI uri) {
      final HttpHeaders requestHeaders = new HttpHeaders();
      requestHeaders.setAccept(Arrays.asList(new MediaType[] {MediaType.APPLICATION_JSON}));
      requestHeaders.setAcceptCharset(Arrays.asList(new Charset[] {Charset.forName("UTF-8")}));
      final HttpEntity&lt;?&gt; requestEntity = new HttpEntity(requestHeaders);
      final HttpEntity&lt;JSONObject&gt; response = restTemplate.exchange(uri, HttpMethod.GET, requestEntity, JSONObject.class);
      return response;
  }
  }
  </code></pre>
  
  <p>My web.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"&gt;
  
  &lt;context-param&gt;
      &lt;param-name&gt;contextClass&lt;/param-name&gt;
      &lt;param-value&gt;
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      &lt;/param-value&gt;
  &lt;/context-param&gt;
  
  &lt;context-param&gt;
      &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
      &lt;param-value&gt;com.spp.mui.gwt.server.config.WebAppContextExperimental&lt;/param-value&gt;
  &lt;/context-param&gt;
  
  &lt;listener&gt;
      &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
  &lt;/listener&gt;
  
  &lt;listener&gt;
      &lt;listener-class&gt;
          org.springframework.web.context.request.RequestContextListener
      &lt;/listener-class&gt;
  &lt;/listener&gt;
  
  &lt;filter&gt;
      &lt;filter-name&gt;characterEncodingFilter&lt;/filter-name&gt;
      &lt;filter-class&gt;org.springframework.web.filter.CharacterEncodingFilter&lt;/filter-class&gt;
      &lt;init-param&gt;
          &lt;param-name&gt;encoding&lt;/param-name&gt;
          &lt;param-value&gt;UTF-8&lt;/param-value&gt;
      &lt;/init-param&gt;
      &lt;init-param&gt;
          &lt;param-name&gt;forceEncoding&lt;/param-name&gt;
          &lt;param-value&gt;true&lt;/param-value&gt;
      &lt;/init-param&gt;
  &lt;/filter&gt;
  
  &lt;filter-mapping&gt;
      &lt;filter-name&gt;characterEncodingFilter&lt;/filter-name&gt;
      &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
  &lt;/filter-mapping&gt;
  
  &lt;servlet&gt;
      &lt;servlet-name&gt;gwt&lt;/servlet-name&gt;
      &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
      &lt;init-param&gt;
          &lt;param-name&gt;contextClass&lt;/param-name&gt;
          &lt;param-value&gt;
              org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          &lt;/param-value&gt;
      &lt;/init-param&gt;
      &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
  &lt;/servlet&gt;
  &lt;servlet-mapping&gt;
      &lt;servlet-name&gt;gwt&lt;/servlet-name&gt;
      &lt;url-pattern&gt;/EMKT/service/*&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
  
  &lt;welcome-file-list&gt;
      &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;
  &lt;/welcome-file-list&gt;
  
  &lt;session-config&gt;
      &lt;session-timeout&gt;0&lt;/session-timeout&gt;
  &lt;/session-config&gt;
  &lt;/web-app&gt;
  </code></pre>
  
  <p>I can see my Controller methods mapped on server startup...</p>
  
  <pre><code>17:48:58,651 INFO  [RequestMappingHandlerMapping] Mapped "{[/rest/resources],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}"
  17:48:58,651 INFO  [RequestMappingHandlerMapping] Mapped "{[/rest/locations],methods=[GET],params=[],headers=[],consumes=[],produces=[application/json],custom=[]}"
  </code></pre>
  
  <p>When the test runs, I get...</p>
  
  <pre><code>17:49:00,617 DEBUG [AutowiredAnnotationBeanPostProcessor] Autowiring by type from bean name 'com.spp.mui.gwt.server.controller.stub.StubRestClientITCase' to bean named 'restTemplate'
  17:49:00,648 DEBUG [RestTemplate] Created GET request for "http://localhost:8080/EMKT/services/rest/resources?q=*&amp;indexFrom=0&amp;indexTo=24"
  17:49:00,680 DEBUG [RestTemplate] Setting request Accept header to [application/json]
  17:49:00,742 WARN  [RestTemplate] GET request for "http://localhost:8080/EMKT/services/rest/resources?q=*&amp;indexFrom=0&amp;indexTo=24" resulted in 404 (Not Found); invoking error handler
  </code></pre>
  
  <p>Finally...</p>
  
  <pre><code>Tests in error:
    testGetResources(com.spp.mui.gwt.server.controller.stub.StubRestClientITCase): 404 Not Found
  </code></pre>
  
  <p>What could be the matter?  Thinking it has something to do with <strong>url-pattern</strong> in <strong>servlet-mapping</strong>. I have tried to follow Spring docs on setup but have been unsuccessful.  Note: I am inflexible on that though as I have a GWT-SL setup to map RPC service interfaces.</p>
  
  <p><strong>UPDATE #1</strong></p>
  
  <p>If I try using </p>
  
  <pre><code>curl --verbose -H "Accept: application/json" "localhost:8081/spp-emkt-mui-experimental/EMKT/service/rest/resources?q=*&amp;indexFrom=0&amp;indexTo=24"
  </code></pre>
  
  <p>against a Tomcat 6 deployment (using cargo plugin), I get a different result:</p>
  
  <pre><code>* About to connect() to localhost port 8081 (#0)
  *   Trying 127.0.0.1... connected
  * Connected to localhost (127.0.0.1) port 8081 (#0)
  &gt; GET /spp-emkt-mui-experimental/EMKT/service/rest/resources?q=*&amp;indexFrom=0&amp;indexTo=24 HTTP/1.1
  &gt; User-Agent: curl/7.21.1 (i686-pc-mingw32) libcurl/7.21.1 OpenSSL/0.9.8r zlib/1.2.3
  &gt; Host: localhost:8081
  &gt; Accept: */*
  &gt;
  &lt; HTTP/1.1 406 Not Acceptable
  &lt; Server: Apache-Coyote/1.1
  &lt; Content-Type: text/html;charset=utf-8
  &lt; Content-Length: 1070
  &lt; Date: Tue, 28 Feb 2012 05:00:26 GMT
  </code></pre>
  
  <p>Which seems to indicate I'm not sending appropriate header info in my request.  Hmmmmmm.</p>
  
  <p><strong>UPDATE #2</strong></p>
  
  <p>The test as written returns a 404.  And the curl a 406.</p>
  
  <p>I've scoured so many seemingly related posts and tried so many things that I'm wondering if Spring MVC, GWT-RPC and GWT-SL are able to be combined in the same container.  Considering a move to RestyGWT with server-side being Spring MVC.  Comments?</p>