Spring – RestTemplate GET request throws 400 Bad Request

resttemplatespring

I am getting 400 Bad Request when I send a request to Rest Service from JUnit Test case. PFB my code. The error log is towards the end. Kindly help me in resolving the issue. I am not getting any error when I call the server as: restTemplate.getForObject(BASE_URL + "/remote?serviceName=simpleService&source=WEB", HelloWorld.class) by passing the parameters directly in the URL. But how to pass using the map, that is where issue is coming.

My Controller:

@Controller
@RequestMapping("/remote")

public class RESTController implements IController{

@RequestMapping(method = RequestMethod.GET, headers = "Accept=application/xml,  application/json")
public @ResponseBody HelloWorld getMessage(@RequestParam("serviceName") String serviceName, @RequestParam("source") String source) throws ApplicationException{
    System.out.println("got the request:");
    serviceLocator serviceLocator = new serviceLocator();
    HelloWorld helloWorld = new HelloWorld();
    helloWorld.setMessage(serviceLocator.getMessage(serviceName));
    return helloWorld;
}

My Config:

<context:annotation-config />

<context:component-scan base-package="com" />

<mvc:annotation-driven />

<bean
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
            <bean
                class="org.springframework.http.converter.StringHttpMessageConverter" />
            <bean id="jsonViewResolver"
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper" ref="JacksonObjectMapper" />
                <property name="supportedMediaTypes">
                    <list>
                        <bean class="org.springframework.http.MediaType">
                            <constructor-arg value="application" />
                            <constructor-arg value="json" />
                            <constructor-arg
                                value="#{T(java.nio.charset.Charset).forName('UTF-8')}" />
                        </bean>
                    </list>
                </property>
            </bean>

        </list>
    </property>
</bean>
<bean id="JacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />

My Controller Test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("applicationContextTest.xml")
public class RESTControllerTest {

private static final String BASE_URL = "http://localhost:8080/SimpleServiceWeb/rest";

@Autowired
private RestTemplate restTemplate;

@Test
public void getMessage() throws Exception { 

    String expected = "Hello Spring!";
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setAccept(Collections
            .singletonList(MediaType.APPLICATION_XML));     

    MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
    map.add("serviceName", "simpleService");
    map.add("source", "WEB");

    ObjectMapper mapper = new ObjectMapper();
    ObjectWriter normalWriter = mapper.writer();
    String jsonString = normalWriter.writeValueAsString(map);;
    HttpEntity<Object> requestEntity = new HttpEntity<Object>(httpHeaders);     

    HelloWorld helloWorld = restTemplate.exchange(BASE_URL + "/remote",
             HttpMethod.GET, requestEntity, HelloWorld.class, map) .getBody();

    assertThat(helloWorld.getMessage(), is(expected));
}

}

My Test Config:

.simple" />

<mvc:annotation-driven />

<bean id="springServiceLocator" class="com.servicelocator.simple.SpringServiceLocator">
    <property name="simpleService" ref="simpleService" />
</bean>

<bean id="simpleService" class="com.service.simple.SimpleService" />

<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">

    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.FormHttpMessageConverter" />
            <bean
                class="org.springframework.http.converter.StringHttpMessageConverter" />
            <bean id="jsonViewResolver"
                class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
                <property name="objectMapper" ref="JacksonObjectMapper" />
                <property name="supportedMediaTypes">
                    <list>
                        <bean class="org.springframework.http.MediaType">
                            <constructor-arg value="application" />
                            <constructor-arg value="json" />
                            <constructor-arg
                                value="#{T(java.nio.charset.Charset).forName('UTF-8')}" />
                        </bean>
                    </list>
                </property>
            </bean>

        </list>
    </property>
</bean>
<bean id="JacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper" />

<bean id="httpClient" class="org.apache.commons.httpclient.HttpClient">
    <constructor-arg ref="httpClientParams" />
</bean>

<bean id="httpClientParams" class="org.apache.commons.httpclient.params.HttpClientParams">

    <property name="connectionManagerClass"
        value="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" />
</bean>

<bean id="httpClientFactory"
    class="org.springframework.http.client.CommonsClientHttpRequestFactory">
    <constructor-arg ref="httpClient" />
</bean>

Error:

org.springframework.web.client.HttpClientErrorException: 400 Bad Request
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:75)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:409)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:384)
at test.com.servicefacade.simple.RESTControllerTest.getMessage(RESTControllerTest.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

Best Answer

  1. Your controller accepts application/xml and application/json types.
  2. Only JSON converter configured in messageConverters and I don't see any XML converters.
  3. In the test case, you're setting the media type as application/xml.

Could it be due to the missing xml converter that Spring is not able to marshal your request appropriately and hence giving the 400? The media type is supported though as mentioned in the controller and that's why you're not getting a 415.

Related Topic