0

For writing a test for a certain feature I have to cast a String containing [] into a JsonNode.

The problem is when mapping it to JsonNode it seems to be adding extra quotes to it.

What I expect "[]", but what I get ""[]"", which leads to a failing test. When I debug the code in normal operation, I do get only "[]" when testing the code with Postman instead of the not working ""[]"" which I only get during the tests.

This is what my DTO looks like in Spring Boot

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;

public class PostLabelDTO {


    private final String templateId;

    private final String labels;

    @JsonCreator
    public PostLabelDTO(
            final @JsonProperty("templateId") String templateId,
            final @JsonProperty("labels") JsonNode labels
    ) {
        this.templateId = templateId;
        this.labels = labels.toString();
    }

    public String getId() {
        return templateId;
    }

    public String getData() {
        return labels;
    }
}

My test has to fake this object with the properties to pass to the method which is gonna get tested.

My test looks like this:

@Test
    public void getEmptyDocumentException() throws InvalidBarcodeException, EmptyStringException, InvalidBarcodeGeometryException, EmptyFieldException, TemplateNotFoundException, InvalidBarcodeStrategyException {

        //defining an ID for the templateId JsonProperty
        final String templateId = "fj2j931j2ijd1";

        //this is the "labels" JsonNode that gets sent in through the Post request
        //i checked 10 times how the value comes into the DTO and it was always "[]" (empty labels (document) object, for which I wrote this test for)

        final String jsonString = "[]";

        ObjectMapper mapper = new ObjectMapper();
        mapper.enable(JsonParser.Feature.ALLOW_MISSING_VALUES);

        JsonNode labels = mapper.valueToTree(jsonString);


        //when I do this, the "[]" which is normally passed into the PostLabelDTO, becomes ""[]"", so there are extra quotes added
        PostLabelDTO dto = new PostLabelDTO(templateId, labels);

        final Document document = new Document(dto, templateRepository);
        Exception resultingException = null;

        try {
            document.getPDF();
        } catch (Exception e) {
            e.printStackTrace();


            assertThat(resultingException).isExactlyInstanceOf(EmptyDocumentException.class);
        }

    }

So basically I tried to put the above Json into a new instance of PostLabelDTO as the labels JsonNode object for testing purposes, but it doesn't work.

This is the request with which it works through postman (it works as in, it throws the right exception)

{
    "templateId":"5b1140608134691d1804e74e",
    "labels":[]
}

So basically I tried to put the above Json into a new instance of PostLabelDTO as the labels JsonNode object for testing purposes, but it doesn't work.

This is a working request (which returns a PDF with labels with a label on each page)

{
    "templateId": "5b1140608134691d1804e74e",
    "labels": [{
        "data": {
            "Ivolgnr": "Volgnr",
            "Ilkw-nr": "Ilkw-nr",
            "bedrijf": "Hornbach",
            "wagenNr": "13513542626",
            "barcode": {
                "waarde": "9780471117094"
            },
            "leverdatumVan": "x",
            "leverdatumNaar": "x",
            "orderList": [{
                    "order": [{
                            "articlenumber": "29-840-4512"
                        },
                        {
                            "description": "Mooie grote plant"
                        },
                        {
                            "ordernumber": "3584479012860361"
                        },
                        {
                            "amount": "20"
                        },
                        {
                            "sellprice": "€5,00"
                        },
                        {
                            "deliverydate": "01-09-2018"
                        }
                    ]
                },
                {
                    "order": [{
                            "articlenumber": "29-840-4512"
                        },
                        {
                            "description": "Mooie grote plant"
                        },
                        {
                            "ordernumber": "3584479012860361"
                        },
                        {
                            "amount": "20"
                        },
                        {
                            "sellprice": "€5,00"
                        },
                        {
                            "deliverydate": "01-09-2018"
                        }
                    ]
                },
                {
                    "order": [{
                            "articlenumber": "29-840-4512"
                        },
                        {
                            "description": "Mooie grote plant"
                        },
                        {
                            "ordernumber": "3584479012860361"
                        },
                        {
                            "amount": "20"
                        },
                        {
                            "sellprice": "€5,00"
                        },
                        {
                            "deliverydate": "01-09-2018"
                        }
                    ]
                },
                {
                    "order": [{
                            "articlenumber": "29-840-4512"
                        },
                        {
                            "description": "Mooie grote plant"
                        },
                        {
                            "ordernumber": "3584479012860361"
                        },
                        {
                            "amount": "20"
                        },
                        {
                            "sellprice": "€5,00"
                        },
                        {
                            "deliverydate": "01-09-2018"
                        }
                    ]
                },
                {
                    "order": [{
                            "articlenumber": "29-840-4512"
                        },
                        {
                            "description": "Mooie grote plant"
                        },
                        {
                            "ordernumber": "3584479012860361"
                        },
                        {
                            "amount": "20"
                        },
                        {
                            "sellprice": "€5,00"
                        },
                        {
                            "deliverydate": "01-09-2018"
                        }
                    ]
                }

            ]
        }
    }, {
        "data": {
            "Ivolgnr": "22324rff",
            "Ilkw-nr": "246426246",
            "bedrijf": "bedrijfffff",
            "wagenNr": "wagennrrrrrrr",
            "barcode": {
                "waarde": "9780471117094"
            },
            "leverdatumVan": "x",
            "leverdatumNaar": "x",
            "orderList": [{
                "order": [{
                        "articlenumber": "a"
                    },
                    {
                        "description": "b"
                    },
                    {
                        "ordernumber": "c"
                    },
                    {
                        "amount": "d"
                    },
                    {
                        "sellprice": "e"
                    },
                    {
                        "deliverydate": "f"
                    }
                ]
            }]
        }
    }]
}

ATTENTION The schema of a label (called data for each label in this request) can always vary depending on which template is used to be filled. So there is no possibility to make a Label object containing all properties as these always vary (depends on the HTML of the Template that is to be filled with this request. My service does a "search&replace" based on the tag property-names.

I already tried this: How to parse a JSON string into JsonNode in Jackson?

But I can't seem to add an empty array to the JsonNode object as its supposed to.

Can someone please help me?

Regards,

Ali

user2520459
  • 29
  • 1
  • 1
  • 8

2 Answers2

1

So, basically what you have in the code is this: final String jsonString = "[]";

But, in your request from postman you are sending labels as type Array and not type String.

As there is not much info here, can you check with this body:

{
"templateId":"5b1140608134691d1804e74e",
"labels":"[]"
}

And share the output or even this(difference in types) might help you in understanding the unexpected behaviour you are facing where in its trying to convert the array to String type. In test class you should try to get JsonNode from arrayType String[] labels in test class


UPDATE: While using String [] instead of String for labels, you need to also give a pass type while getting JsonNode from String []. Refer to this link on how to do that.

abstractKarshit
  • 1,355
  • 2
  • 16
  • 34
  • This gives me `{ "timestamp": "2018-06-01T16:50:53.377+0000", "status": 500, "error": "Internal Server Error", "message": "A JSONArray text must start with '[' at 1 [character 2 line 1]", "path": "/labels/" }` – user2520459 Jun 01 '18 at 16:51
  • I already tried to cast it into a `JSONArray` instead of `JsonNode` upon arrival in the `PostLabelDTO`, but it seems it can't parse it and I get an error that its incorrect syntax – user2520459 Jun 01 '18 at 16:53
  • Ok, so the constructor always expects a JsonNode? And when you send the request from postman it gets mapped to PostLabelDto but not from your test class? Correct? – abstractKarshit Jun 01 '18 at 16:53
  • Yes, it doesn't go through the testclass, but the usual route (@JsonProperty etc etc) – user2520459 Jun 01 '18 at 16:54
  • I added an example (working, filled request) to my post so you can see it, maybe it'll help. – user2520459 Jun 01 '18 at 16:57
  • Can you check if your labels jsonNode is arrayNode by .isArray() method. It ideally should be an arrayNode. – abstractKarshit Jun 01 '18 at 17:09
  • Just convert string labels to String [] in test class to convert to JsonNode. This might help – abstractKarshit Jun 01 '18 at 17:19
  • I converted `private String jsonString = "[]"` to a `String[]` with `String labels[] = jsonString.split("") ;` but I get this error then `Error:(45, 65) java: incompatible types: java.lang.String[] cannot be converted to com.fasterxml.jackson.databind.JsonNode` – user2520459 Jun 01 '18 at 17:35
  • 1
    You might need to pass type while getting array or try something from here: https://stackoverflow.com/questions/16788213/jackson-how-to-transform-jsonnode-to-arraynode-without-casting/16793133 Fundamentally, you just need to get JsonNode from String array – abstractKarshit Jun 02 '18 at 05:10
  • This worked like a charm, thanks!!! Please update your answer so I can select it as best answer! – user2520459 Jun 02 '18 at 11:58
1

Try using labels as String[] in PostLabelDTO

public class PostLabelDTO {

    private final String templateId;

    private final String[] labels;

    public String[] getLabels() {
        return labels;
    }

    @JsonCreator
    public PostLabelDTO(final @JsonProperty("templateId") String templateId,
            final @JsonProperty("labels") String[] labels) {
        this.templateId = templateId;
        this.labels = labels;
    }

    public String getId() {
        return templateId;
    }

}

Then test this code like below:

String str[] = {};
PostLabelDTO postLabelDTO = new PostLabelDTO("fj2j931j2ijd1", str);

For your actual request with that big JSON, you should have PostLabelDTO like below

public class PostLabelDTO {

@JsonProperty("templateId")
private String templateId;
@JsonProperty("labels")
private List<Label> labels = null;
....
}

Try generating POJO from JSON using jsonschema2pojo link, it will generate correct JAVA classes and you can test the working of using this call using your actual JSON request body.

Amit K Bist
  • 6,760
  • 1
  • 11
  • 26
  • I need to get the string of the JSON to use in other functions. So ideally getLabels would return pure JSON instead of an array – user2520459 Jun 01 '18 at 17:18
  • I get this error `{ "timestamp": "2018-06-01T17:24:07.706+0000", "status": 400, "error": "Bad Request", "message": "JSON parse error: Cannot deserialize instance of java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: (PushbackInputStream); line: 3, column: 12] (through reference chain: han.oose.margriet.dto.PostLabelDTO[\"labels\"]->java.lang.Object[][0])", "path": "/labels/" }` – user2520459 Jun 01 '18 at 17:24
  • where you are getting this error, in your `getEmptyDocumentException()` method? – Amit K Bist Jun 01 '18 at 17:28
  • I have a method that throws that exception when there is an empty array in "labels" instead of filled as you can see with my 2 examples in my OP. – user2520459 Jun 01 '18 at 17:39
  • Hello, as for your comment on making a POJO for this. The layout of a label can be dynamic, so there can be more or less fields with an orderlist etc etc. – user2520459 Jun 01 '18 at 17:56
  • I thought you have maximum fields which can come in the label, and then create POJO with these fields, if all or less are coming then fine, but if some node is coming which is not in your POJO then it will not work. – Amit K Bist Jun 01 '18 at 17:58
  • No there is no maximum fields, its completely dynamic. So a label can have either 5 fields, or maybe 100, depending on the template the customer has made to fill (so just a html with `
    ` which gets filled by the property "price" from the JSON-request for example)
    – user2520459 Jun 01 '18 at 18:01