1

I have one simple test to write for a POST method in a RestController. This post mapping works fine when i run the application. But, in it's test i always get HttpMessageNotReadableException with 400-Bad Request.

InternalCustomerController.class

@RestController
@RequestMapping(
        value = "/",
        consumes = {MediaType.APPLICATION_XML_VALUE},
        produces = {MediaType.APPLICATION_XML_VALUE})
@RequiredArgsConstructor
public class InternalCustomerController {

    private final CustomerService customerService;

    @PostMapping(value = "/cpdupdate")
    public Notification updateCustomerProduct(@NotNull @RequestBody Customer customer) {
        return customerService.handleUpdateCustomerProduct(customer);
    }
}

InternalCustomerControllerTest.class

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = InternalCustomerController.class)
@Import(TestObjectMapperConfig.class)
public class InternalCustomerControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private CustomerService customerService;

    @Test
    public void testUpdateCustomerProduct() throws Exception {
        Customer validCustomer = createValidCustomer("76d211bb680843c5b63afa1c13a0a5e5", "60");

        when(this.customerService.handleUpdateCustomerProduct(any()))
                .thenReturn(buildDummyNotification(messageId, "SUCCESS"));

        mockMvc.perform(post("/cpdupdate")
                .contentType(MediaType.APPLICATION_XML)
                .content(objectToString(validCustomer)))
                .andExpect(status().isOk()); // Fails Here as it gets 400 in return
    }

    // Customer Class Generated from Provided XSD on maven build
    private static Customer createValidCustomer(String internalProductId, int customerId) {
        Customer customer = new Customer();
        customer.setCustomerId(customerId);

        Customer.InternalProducts products = new Customer.InternalProducts();
        products.getProductIds().add(internalProductId);
        customer.setInternalProducts(products);

        return customer;
    }

    private Notification buildDummyNotification(String messageId, String message) {
        return Notification.builder()
                .messageId(messageId)
                .message(message)
                .build();
    }

    private static String objectToString(Object element) {
        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
            JAXBContext context = JAXBContext.newInstance(element.getClass());
            Marshaller marshaller = context.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            marshaller.marshal(element, outputStream);
            return outputStream.toString("UTF-8");
        } catch (JAXBException | IOException ex) {
            log.error(ex.getMessage(), ex);
            return "";
        }
    }

}

Error message contains JSON parse error: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token. So i tried adding a configuration for ObjectMapper and Import it into the test.

@Configuration
public class TestObjectMapperConfig {

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
        return objectMapper;
    }
}

But i still get the error.

What i am missing here?

Full Error Message

    Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of VALUE_STRING token
 at [Source: java.io.PushbackInputStream@53311681; line: 4, column: 49] (through reference chain: com.clps.Customer["internalProducts"]->com.clps.Customer$InternalProducts["productId"])]

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /cpdupdate
       Parameters = {}
          Headers = {Content-Type=[application/xml]}

Handler:
             Type = com.pt.controllers.InternalCustomerController
           Method = public com.pt.models.Notification com.pt.controllers.InternalCustomerController.updateCustomerProduct(com.clps.Customer)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = org.springframework.http.converter.HttpMessageNotReadableException

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = {}
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

java.lang.AssertionError: Status 
Expected :200
Actual   :400
Rajkishan Swami
  • 3,569
  • 10
  • 48
  • 68

0 Answers0