Primavera: Volviendo de vacío HTTP Respuestas con ResponseEntity<Vacío> no funciona

Estamos implementando una API REST con Spring (4.1.1.). Para ciertas solicitudes HTTP, nos gustaría volver una cabeza sin cuerpo como una respuesta. Sin embargo, el uso de ResponseEntity<Void> no parece funcionar. Cuando se llama con un MockMvc prueba, un 406 (No aceptable) que se devuelve. El uso de ResponseEntity<String> sin un valor de parámetro (new ResponseEntity<String>( HttpStatus.NOT_FOUND )) funciona bien.

Método:

@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 );
    }

}

Caso de prueba (TestNG):

public class TaxonomyQueryControllerTest {

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

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

@Test
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() );

}

}

Falla con este seguimiento de la pila:

FAILED: taxonomyPackageDoesNotExist
java.lang.AssertionError: Status expected:<404> but was:<406>
at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:60)
at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:89)
at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:652)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:153)
at de.zeb.control.application.xbrlstandalonevalidator.restservice.TaxonomyQueryControllerTest.taxonomyPackageDoesNotExist(TaxonomyQueryControllerTest.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
InformationsquelleAutor ScarOnTheSky | 2014-10-24

5 Kommentare

  1. 28

    NOTA: Esto es cierto para la versión mencionada en la pregunta, 4.1.1.De LIBERACIÓN.

    MVC de Spring maneja un ResponseEntity valor de retorno a través de HttpEntityMethodProcessor.

    Cuando el ResponseEntity valor no tiene un cuerpo conjunto, como es el caso en el fragmento, HttpEntityMethodProcessor intenta determinar un tipo de contenido para el cuerpo de la respuesta de la parametrización de la ResponseEntity tipo de retorno en la firma de la @RequestMapping método de controlador.

    Así que para

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

    de que tipo será Void. HttpEntityMethodProcessor entonces el bucle a través de todos sus registrado HttpMessageConverter instancias y encontrar uno que puede escribir un cuerpo para un Void tipo. Dependiendo de su configuración, puede o no puede encontrar ninguna.

    Si encuentra alguna, todavía es necesario asegurarse de que el organismo correspondiente será escrito con un Tipo de Contenido que coincida con el tipo(s) proporcionada en la solicitud del Accept encabezado, application/xml en su caso.

    Si después de todos estos controles, no HttpMessageConverter existe, Spring MVC decidir que no puede producir una respuesta aceptable y, por tanto, devolver un 406 No Aceptable de respuesta HTTP.

    Con ResponseEntity<String>, la Primavera va a utilizar String como el cuerpo de la respuesta y encontrar StringHttpMessageConverter como un controlador. Y desde StringHttpMessageHandler puede producir contenido para cualquier tipo de medios de comunicación (incluido en el Accept encabezado), será capaz de manejar el application/xml que su cliente está solicitando.

    Spring MVC se ha cambiado para devolver sólo 406 si el cuerpo en el ResponseEntity NO es null. Usted no verá el comportamiento en la pregunta original, si estás usando una versión más reciente de Spring MVC.


    En iddy85 la solución, lo que parece sugerir ResponseEntity<?>, el tipo para que el cuerpo se deducirá como Object. Si usted tiene el correcto de las bibliotecas en su ruta de clase, es decir,. Jackson (versión > 2.5.0) y su extensión XML, Spring MVC tendrá acceso a MappingJackson2XmlHttpMessageConverter que se puede utilizar para producir application/xml para el tipo Object. Su solución sólo funciona en estas condiciones. De lo contrario, se producirá por la misma razón que he descrito anteriormente.

    • Hola Sotirios, gracias por su respuesta. Sólo asegúrese de que: Usted está diciendo que tengo que usar ResponseEntity <Cadena>, derecho?
    • Una opción es establecer el tipo de retorno a ResponseEntity<?> y usar lo que a la hora de construir el real valor de retorno. También puede proporcionar HttpHeaders con un adecuado contenido de tipo para la ResponseEntity constructor. A pesar de que en realidad no tiene sentido establecer un tipo de contenido cuando usted no tiene ningún contenido.
    • Si utiliza ResponseEntity<?> y, a continuación, establezca un responseEntity sin el cuerpo, no el cuerpo todavía vacío? lo que significa que tienen el mismo problema?
    • De mis pruebas, la configuración de ResponseEntity<Vacío> escribir un «null» en responseBody que es bastante buggy. Si realmente la intención de tener un vacío responseBody, devolver un ResponseEntity<Cadena> con una Cadena vacía como «volver ResponseEntity<>(«», HttpStatus.ACEPTAR)»
    • Eso depende de lo que HttpMessageConverter casos se han registrado. Pero, seguro, una cadena vacía también funciona.
  2. 9

    Su método de aplicación es ambiguo, tratar el siguiente , editado el código un poco y utiliza HttpStatus.NO_CONTENT yo.e 204 Sin Contenido como en el lugar de HttpStatus.OK

    El servidor ha cumplido con la petición, pero no tiene que devolver un
    entidad-cuerpo, y puede ser que desee para volver actualizado de metainformación. El
    la respuesta PUEDE incluir nuevos o actualizados de metainformación en la forma de
    entidad-cabeceras, que si está presente DEBE estar relacionado con el
    solicitado variante.

    Cualquier valor de T será ignorado por 204, pero no para 404

      public ResponseEntity<?> 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<T>(HttpStatus.NO_CONTENT);
                } else {
                   LOG.debug( "Taxonomy package with key: {0} does NOT exist.", taxonomyKey ); //$NON-NLS-1$
                    return new ResponseEntity<T>( HttpStatus.NOT_FOUND );
                }
    
        }
    • T es una respuesta de tipo de cuerpo, podría ser cualquier cosa, una Cadena es una opción.tratar de que si lo hacet work share the new code with and the stack-trace. @SotiriosDelimanolis I am curious whats mal con el código?
    • Es T una variable de tipo? Donde se declaró? ¿Qué diferencias van a hacer sus sugerencias.
    • Yo no cambio nada de lo dramático de la el código original en lugar de lo que sugiere el uso de HttpStatus.NO_CONTENT en lugar de HttpStatus.ACEPTAR un no de respuesta de cuerpo
    • Así que por favor explique cómo que va a arreglar el OP del problema.
  3. 9

    También puede no especificar el tipo de parámetro que se parece un poco más claro y lo de la Primavera de la intención cuando se mira en el docs:

    @RequestMapping(method = RequestMethod.HEAD, value = Constants.KEY )
    public ResponseEntity taxonomyPackageExists( @PathVariable final String key ){
        //...
        return new ResponseEntity(HttpStatus.NO_CONTENT);
    }
  4. 1

    Personalmente, para lidiar con el vacío de respuestas, voy a usar en mis Pruebas de Integración el MockMvcResponse objeto como este :

    MockMvcResponse response = RestAssuredMockMvc.given()
                    .webAppContextSetup(webApplicationContext)
                    .when()
                    .get("/v1/ticket");
    
        assertThat(response.mockHttpServletResponse().getStatus()).isEqualTo(HttpStatus.NO_CONTENT.value());

    y en mi controlador vuelvo respuesta vacía en un caso específico como este :

    return ResponseEntity.noContent().build();

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Recent Articles

Python «set» con duplicados/elementos repetidos

Hay una forma estándar de representar un "conjunto" que puede contener elementos duplicados. Como yo lo entiendo, un conjunto tiene exactamente un cero o...

Python: generador de expresión vs rendimiento

En Python, ¿hay alguna diferencia entre la creación de un generador de objetos a través de un generador de expresión versus el uso de...

Cómo exportar/importar la Masilla lista de sesiones?

Hay una manera de hacer esto? O tengo que tomar manualmente cada archivo de Registro? InformationsquelleAutor s.webbandit | 2012-10-23

no distingue mayúsculas de minúsculas coincidentes en xpath?

Por ejemplo, para el xml a continuación <CATALOG> <CD title="Empire Burlesque"/> <CD title="empire burlesque"/> <CD...