REST POST controller saying: Could not read JSON: No content to map due to end-of-input

匿名 (未验证) 提交于 2019-12-03 02:14:01

问题:

I'm doing an integration test against a REST controller POST handler. Well, I'm trying to.

It gives me the HttpMessageNotReadableException exception: Could not read JSON: No content to map due to end-of-input

Here is my controller:

@Controller @RequestMapping("admin") public class AdminController {      private static Logger logger = LoggerFactory.getLogger(AdminController.class);      private static final String TEMPLATE = "Hello, %s!";      @Autowired      private AdminService adminService;      @Autowired     private AdminRepository adminRepository;      @RequestMapping(value = "crud", method = RequestMethod.POST, produces = "application/json; charset=utf-8")     @ResponseBody     public ResponseEntity<Admin> add(@RequestBody Admin admin, UriComponentsBuilder builder) {         AdminCreatedEvent adminCreatedEvent = adminService.add(new CreateAdminEvent(admin.toEventAdmin()));         Admin createdAdmin = Admin.fromEventAdmin(adminCreatedEvent.getEventAdmin());         HttpHeaders responseHeaders = new HttpHeaders();         responseHeaders.add("Content-Type", "application/json; charset=utf-8");         responseHeaders.setLocation(builder.path("/admin/{id}").buildAndExpand(adminCreatedEvent.getAdminId()).toUri());         return new ResponseEntity<Admin>(createdAdmin, responseHeaders, HttpStatus.CREATED);     }      @ExceptionHandler(HttpMessageNotReadableException.class)     @ResponseBody     public String handleException(HttpMessageNotReadableException e) {         return e.getMessage();     }  } 

The base test class:

@RunWith(SpringJUnit4ClassRunner.class) @WebAppConfiguration @ContextConfiguration( classes = { ApplicationConfiguration.class, WebSecurityConfig.class, WebConfiguration.class, WebTestConfiguration.class }) @Transactional public abstract class AbstractControllerTest {      @Autowired     private WebApplicationContext webApplicationContext;      @Autowired     private FilterChainProxy springSecurityFilterChain;      protected MockHttpSession session;      protected MockHttpServletRequest request;      protected MockMvc mockMvc;      @Before     public void setup() {         this.mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext).addFilters(this.springSecurityFilterChain).build();     }  } 

The integration test:

@Test public void testAdd() throws Exception {     HttpHeaders httpHeaders = Common.createAuthenticationHeaders("stephane" + ":" + "mypassword");     this.mockMvc.perform(         post("/admin/crud").headers(httpHeaders)         .param("firstname", "Stephane")         .param("lastname", "Eybert")         .param("login", "stephane")         .param("password", "toto")     ).andDo(print())     .andExpect(         status().isOk()     ).andReturn(); } 

What the console log has to say:

2013-11-04 19:31:23,168 DEBUG  [HttpSessionSecurityContextRepository] SecurityContext stored to HttpSession: 'org.springframework.security.core.context.SecurityContextImpl@158ddda0: Authentication: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@158ddda0: Principal: org.springframework.security.core.userdetails.User@552e813c: Username: stephane; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ADMIN' 2013-11-04 19:31:23,168 DEBUG  [RequestResponseBodyMethodProcessor] Written [Could not read JSON: No content to map due to end-of-input  at [Source: UNKNOWN; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input  at [Source: UNKNOWN; line: 1, column: 1]] as "application/json;charset=utf-8" using [org.springframework.http.converter.StringHttpMessageConverter@10d328] 2013-11-04 19:31:23,169 DEBUG  [TestDispatcherServlet] Null ModelAndView returned to DispatcherServlet with name '': assuming HandlerAdapter completed request handling 2013-11-04 19:31:23,169 DEBUG  [TestDispatcherServlet] Successfully completed request 2013-11-04 19:31:23,169 DEBUG  [ExceptionTranslationFilter] Chain processed normally 2013-11-04 19:31:23,169 DEBUG  [SecurityContextPersistenceFilter] SecurityContextHolder now cleared, as request processing completed MockHttpServletRequest:          HTTP Method = POST          Request URI = /admin/crud           Parameters = {firstname=[Stephane], lastname=[Eybert], login=[stephane], password=[toto]}              Headers = {Content-Type=[application/json], Accept=[application/json], Authorization=[Basic c3RlcGhhbmU6bXlwYXNzd29yZA==]}               Handler:                 Type = com.thalasoft.learnintouch.rest.controller.AdminController               Method = public org.springframework.http.ResponseEntity<com.thalasoft.learnintouch.rest.domain.Admin> com.thalasoft.learnintouch.rest.controller.AdminController.add(com.thalasoft.learnintouch.rest.domain.Admin,org.springframework.web.util.UriComponentsBuilder)                 Async:    Was async started = false         Async result = null    Resolved Exception:                 Type = org.springframework.http.converter.HttpMessageNotReadableException          ModelAndView:            View name = null                 View = null                Model = null              FlashMap: MockHttpServletResponse:               Status = 200        Error message = null              Headers = {Content-Type=[application/json;charset=utf-8], Content-Length=[254]}         Content type = application/json;charset=utf-8                 Body = Could not read JSON: No content to map due to end-of-input  at [Source: UNKNOWN; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input  at [Source: UNKNOWN; line: 1, column: 1]        Forwarded URL = null       Redirected URL = null              Cookies = [] 2013-11-04 19:31:23,177 DEBUG  [TransactionalTestExecutionListener] No method-level @Rollback override: using default rollback [true] for test context [TestContext@ce4625 testClass = AdminControllerTest, testInstance = com.thalasoft.learnintouch.rest.AdminControllerTest@1b62fcd, testMethod = testAdd@AdminControllerTest, testException = [null], mergedContextConfiguration = [WebMergedContextConfiguration@9be79a testClass = AdminControllerTest, locations = '{}', classes = '{class com.thalasoft.learnintouch.rest.config.ApplicationConfiguration, class com.thalasoft.learnintouch.rest.config.WebSecurityConfig, class com.thalasoft.learnintouch.rest.config.WebConfiguration, class com.thalasoft.learnintouch.rest.config.WebTestConfiguration}', contextInitializerClasses = '[]', activeProfiles = '{}', resourceBasePath = 'src/main/webapp', contextLoader = 'org.springframework.test.context.web.WebDelegatingSmartContextLoader', parent = [null]]] 

Any clue?

回答1:

In my opinion the problem is with content format. Your endpoint expect that data will be sent as application/json but in test you send it as application/x-www-form-urlencoded (it doesn't matter that you set proper content type header in request). Try to send admin object in json format (as a body of a request):

{  "firstname" : "Stephane",  "lastname" : "Eybert",  "login" : "stephane",  "password" : "toto" } 

BTW the /admin/crud does not fallow REST resource addressing rules, you should change it to /admin. The crud (CREATE, READ, UPDATE, DELETE) will map to HTTP methods (POST, GET, PUT, DELETE)



回答2:

I replaced the .param() methods in favor of the .content() one:

        post("/admin/crud").headers(httpHeaders)         .contentType(MediaType.APPLICATION_JSON)         .accept(MediaType.APPLICATION_JSON)         .content("{ \"firstname\" : \"" + admin0.getFirstname() + "\", \"lastname\" : \"" + admin0.getLastname() + "\", \"email\" : \"" + admin0.getEmail() + "\", \"login\" : \"" + admin0.getLogin() + "\", \"password\" : \"" + admin0.getPassword() + "\", \"passwordSalt\" : \"" + admin0.getPasswordSalt() + "\" }")     ).andDo(print())     .andExpect(status().isCreated())     .andExpect(jsonPath("$.firstname").value(admin0.getFirstname()))     .andExpect(jsonPath("$.lastname").value(admin0.getLastname()))     .andExpect(jsonPath("$.email").value(admin0.getEmail()))     .andExpect(jsonPath("$.login").value(admin0.getLogin()))     .andExpect(jsonPath("$.password").value(admin0.getPassword()))     .andExpect(jsonPath("$.passwordSalt").value(admin0.getPasswordSalt()))     .andReturn(); 

And it now works as expected.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!