Printemps: les retours à vide des Réponses HTTP avec ResponseEntity<Void> ne fonctionne pas
Nous mettons en place une API REST avec Spring (4.1.1.). Pour certaines requêtes HTTP, nous aimerions revenir une tête sans corps comme une réponse. Cependant, l'utilisation de ResponseEntity<Void>
ne semble pas fonctionner. Lorsqu'elle est appelée avec un MockMvc
test, une 406 (Non acceptable) est retourné. À l'aide de ResponseEntity<String>
sans la valeur d'un paramètre (new ResponseEntity<String>( HttpStatus.NOT_FOUND )
) fonctionne très bien.
Méthode:
@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 );
}
}
Cas de Test (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() );
}
}
Échoue avec cette trace de la pile:
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)
En fait ResponseEntity<Void> fonctionne parfaitement. Voir les exemples ici: concretepage.com/spring-4/...
OriginalL'auteur ScarOnTheSky | 2014-10-24
Vous devez vous connecter pour publier un commentaire.
Lorsque vous revenez à un
ResponseEntity
sans corps, Printemps utilise l'argument de type fourni dans leResponseEntity
type de retour de la déclaration de décider sur un type de corps.Donc pour
ce type seront
Void
. Le printemps sera ensuite en boucle au travers de tous ses inscritsHttpMessageConverter
instances et en trouver un qui peut écrire un corps pour unVoid
type. Car aucuneHttpMessageConverter
existe (pour une configuration par défaut), elle décide qu'il ne peut pas produire une réponse acceptable et, par conséquent, de retour d'une 406 not Acceptable de la réponse HTTP.Avec
ResponseEntity<String>
, le Printemps sera utiliserString
que le corps de la réponse et de trouverStringHttpMessageConverter
en tant que gestionnaire. Et depuisStringHttpMessageHandler
peuvent produire du contenu pour toutAccepted
type de média, il sera capable de gérer laapplication/xml
que votre client demande.Dans iddy85 de la solution (qui est actuellement de mal, mais semble suggérer
ResponseEntity<?>
), le type pour le corps devra être déduit queObject
. Si vous avez les bonnes bibliothèques dans votre classpath, Printemps auront accès à un XMLHttpMessageConverter
qu'il peut utiliser pour produireapplication/xml
pour le typeObject
.Une option est de définir le type de retour de
ResponseEntity<?>
et utilisez ce que lors de la construction de la valeur de retour. Vous pouvez également fournir desHttpHeaders
avec un type de contenu pour leResponseEntity
constructeur. Si il ne fait pas vraiment sens pour définir un type de contenu lorsque vous n'avez pas de contenu.Si vous utilisez ResponseEntity<?>, puis de définir un responseEntity sans corps, n'est-ce pas le corps encore vide? ce qui signifie que vous avez le même problème?
De mes tests, réglage ResponseEntity<Void> écrira un "null" sur responseBody ce qui est assez buggé. Si vous avez vraiment l'intention d'avoir un vide responseBody, de retour d'un ResponseEntity<String> avec une Chaîne vide comme "retour ResponseEntity<>("", HttpStatus.OK)"
Cela dépend de ce que
HttpMessageConverter
instances que vous avez enregistré. Mais, bien sûr, une chaîne vide fonctionne également.OriginalL'auteur Sotirios Delimanolis
Votre méthode de la mise en œuvre est ambigu, essayez ce qui suit , de la modification de votre code un peu et utilisé
HttpStatus.NO_CONTENT
je.e 204 Aucun Contenu à la place deHttpStatus.OK
N'importe quelle valeur de T sera ignoré pour 204, mais pas pour 404
T
dans votre code et que faut-il changer?T est un corps de réponse type, pourrait être n'importe quoi, la Chaîne est une option.essayer si elle ne
t work share the new code with and the stack-trace. @SotiriosDelimanolis I am curious what
s mal avec le code?Est
T
un type de variable? Où est-il déclaré? Quelles différences vos suggestions à faire.Je n'ai pas changer quoi que ce soit dramatique de la le code d'origine plutôt que de proposer l'utilisation de HttpStatus.NO_CONTENT au lieu de HttpStatus.OK pour un pas de corps de la réponse
Veuillez donc vous expliquer comment cela va corriger l'OP du problème.
OriginalL'auteur iamiddy
Vous pouvez également spécifiez pas le paramètre de type, ce qui semble un peu plus propre et ce Printemps prévu lors de la recherche à la docs:
OriginalL'auteur adanilev
Selon Spring MVC 4 ResponseEntity.BodyBuilder et ResponseEntity Améliorations Exemple il peut être écrite comme:
OriginalL'auteur GKislin
Personnellement, pour faire face avec vide réponses, que j'utilise dans mes Tests d'Intégration de la MockMvcResponse objet comme ceci :
et dans mon contrôleur, je de retour à vide de réponse dans un cas comme celui-ci :
OriginalL'auteur Alex