ScarOnTheSky ScarOnTheSky - 1 year ago 492
Java Question

Spring: Returning empty HTTP Responses with ResponseEntity<Void> doesn't work

We are implementing a REST API with Spring (4.1.1.). For certain HTTP requests, we would like to return a head with no body as a response. However, using

doesn't seem to work. When called with a
test, a 406 (Not acceptable) is returned. Using
without a parameter value (
new ResponseEntity<String>( HttpStatus.NOT_FOUND )
) works fine.


@RequestMapping( method = RequestMethod.HEAD, value = Constants.KEY )
public ResponseEntity<Void> taxonomyPackageExists( @PathVariable final String key ) {

LOG.debug( "taxonomyPackageExists queried with key: {0}", key ); //$NON-NLS-1$

final TaxonomyKey taxonomyKey = TaxonomyKey.fromString( key );

LOG.debug( "Taxonomy key created: {0}", taxonomyKey ); //$NON-NLS-1$

if ( this.xbrlInstanceValidator.taxonomyPackageExists( taxonomyKey ) ) {

LOG.debug( "Taxonomy package with key: {0} exists.", taxonomyKey ); //$NON-NLS-1$

return new ResponseEntity<Void>( HttpStatus.OK );

} else {

LOG.debug( "Taxonomy package with key: {0} does NOT exist.", taxonomyKey ); //$NON-NLS-1$

return new ResponseEntity<Void>( HttpStatus.NOT_FOUND );


Test case (TestNG):

public class TaxonomyQueryControllerTest {

private XbrlInstanceValidator xbrlInstanceValidatorMock;
private TaxonomyQueryController underTest;
private MockMvc mockMvc;

public void setUp() {
this.xbrlInstanceValidatorMock = createMock( XbrlInstanceValidator.class );
this.underTest = new TaxonomyQueryController( this.xbrlInstanceValidatorMock );
this.mockMvc = MockMvcBuilders.standaloneSetup( this.underTest ).build();

public void taxonomyPackageDoesNotExist() throws Exception {
// record
expect( this.xbrlInstanceValidatorMock.taxonomyPackageExists( anyObject( TaxonomyKey.class ) ) ).andStubReturn(
false );

// replay
replay( this.xbrlInstanceValidatorMock );

// do the test
final String taxonomyKey = RestDataFixture.taxonomyKeyString;

this.mockMvc.perform( head( "/taxonomypackages/{key}", taxonomyKey ).accept( //$NON-NLS-1$
MediaType.APPLICATION_XML ) ).andExpect( status().isNotFound() );



Fails with this stack trace:

FAILED: taxonomyPackageDoesNotExist
java.lang.AssertionError: Status expected:<404> but was:<406>
at org.springframework.test.util.AssertionErrors.assertEquals(
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(
at org.springframework.test.web.servlet.MockMvc$1.andExpect(
at de.zeb.control.application.xbrlstandalonevalidator.restservice.TaxonomyQueryControllerTest.taxonomyPackageDoesNotExist(
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(
at sun.reflect.DelegatingMethodAccessorImpl.invoke(
at java.lang.reflect.Method.invoke(
at org.testng.internal.MethodInvocationHelper.invokeMethod(
at org.testng.internal.Invoker.invokeMethod(
at org.testng.internal.Invoker.invokeTestMethod(
at org.testng.internal.Invoker.invokeTestMethods(
at org.testng.internal.TestMethodWorker.invokeTestMethods(
at org.testng.TestRunner.privateRun(
at org.testng.SuiteRunner.runTest(
at org.testng.SuiteRunner.runSequentially(
at org.testng.SuiteRunner.privateRun(
at org.testng.SuiteRunnerWorker.runSuite(
at org.testng.TestNG.runSuitesSequentially(
at org.testng.TestNG.runSuitesLocally(
at org.testng.remote.RemoteTestNG.initAndRun(
at org.testng.remote.RemoteTestNG.main(

Answer Source

When you return a ResponseEntity without a body, Spring uses the type argument provide in the ResponseEntity's return type declaration to decide on a body type.

So for

public ResponseEntity<Void> taxonomyPackageExists( @PathVariable final String key ) {

that type will be Void. Spring will then loop through all its registered HttpMessageConverter instances and find one that can write a body for a Void type. Since no such HttpMessageConverter exists (for a default configuration), it will decide that it cannot produce an acceptable response and therefore return a 406 Not Acceptable HTTP response.

With ResponseEntity<String>, Spring will use String as the response body and find StringHttpMessageConverter as a handler. And since StringHttpMessageHandler can produce content for any Accepted media type, it will be able to handle the application/xml that your client is requesting.

In iddy85's solution (which is currently wrong, but seems to suggest ResponseEntity<?>), the type for the body will be inferred as Object. If you have the correct libraries in your classpath, Spring will have access to a XML HttpMessageConverter which it can use to produce application/xml for the type Object.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download