citrusframework / citrus

Framework for automated integration tests with focus on messaging integration
https://citrusframework.org
Apache License 2.0
456 stars 134 forks source link

Conversion from byte array payload to String fails using JsonMappingValidationCallback #529

Closed lmeyer4 closed 2 years ago

lmeyer4 commented 5 years ago

Citrus Version 2.7.7

Expected behavior In JsonMappingValidationCallback the method T readJson(Message message) should convert the payload in the message parameter into an object of type T.

Actual behavior If the payload is a byte array representing a json string, the method throws an MismatchedInputException. This happens because message.getPayload(String.class) returns a numeric representation of the byte array (e.g. "[123, 34, 105, 100, 34, 58, 32, 34, 49, 50, 51, 34, 125]") instead of a direct representation (e.g. "{"id":"123"}"). This numeric representation is used as parameter to a readValue method from ObjectMapper, which throws the Exception. The readValue method can only convert strings, if they are formatted in json.

Test case sample

static class Product {

        private String id;

        public Product() {
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }
    }

    @Test
    @CitrusTest
    public void validateJsonPayload() {
        String id = "123";
        String json = String.format("{\"id\": \"%s\"}", id);

        Message message = new JmsMessage();
        message.setPayload(json.getBytes());

        (new JsonMappingValidationCallback<Product>(Product.class, new ObjectMapper()) {
            @Override
            public void validate(Product payload, Map<String, Object> headers, TestContext context) {
                assertThat(payload.getId()).isEqualTo(id);
            }
        }).validate(message, null);

    }
svettwer commented 5 years ago

Hi!

I see that the JsonMappingValidationCallback is currently not able to convert message payloads which are byte arrays to T. I'm currently missing the context in which you are using such a validation callback.

You mentioned that you used the jms endpoint. So you've something in place like:

@CitrusTest
public void receiveMessageTest() {
     //Trigger something in the SUT

    String id = "42";

    receive(jmsEndpoint)
        .validationCallback(new JsonMappingValidationCallback<Product>(Product.class, new ObjectMapper()) {
            @Override
            public void validate(Product payload, Map<String, Object> headers, TestContext context) {
                assertThat(payload.getId()).isEqualTo(id);
            }
        });
}

While the message payload is not a String but a byte array, right?

In addition: Your initial PR for this issue was concerning the type conversion utils. So I assume that the original problem was different from the one described here.

Would it be possible for you to provide a sample of the test case with the initial problem?

BR, Sven

lmeyer4 commented 5 years ago

Yes, that's about right: I put something in a RabbitMQ queue, which is processed by some services and in the end I receive some output from another queue. The implementation of the receive part is basically what you wrote.

My original problem is actually same as the one proposed here. readJson in JsonMappingValidionCallback calls message.getPayload(String.class) and getPayload calls TypeConversionUtils.convertIfNecessary(getPayload(), type).

svettwer commented 5 years ago

Okay, got your point!

Thx for the explanation! :+1:

christophd commented 2 years ago

You can transform/convert message payloads prior to validation now in Citrus 3.0