1

I am mapping my API JSON response to Java object using ObjectMapper (Jackson). Below is how my json looks like :

[
    {
        firstKey : "value1",
        secondKey : "value2",
        thirdKey : "value3"
    },
    {
        firstKey : "value4",
        secondKey : "value5",
        thirdKey : "value6"
    }
]

Required fields are : firstKey secondKey thirdKey

Some of my JSON responses might not have all these three required fields, for which I would like Jackson to throw exception while deserializing. How should I let Jackson know about the required fields ? Is there any annotation for it, except JsonProperty(required = true) since this does not works ?

Also, if a key has null value, it is accepted default value, so I cannot use @NotNull as well. For eg : [ { firstKey : null, secondKey : "value2", thirKey : "value3" } ] Above is valid JSON and should parsed without any exception during deserialization.

pirho
  • 11,565
  • 12
  • 43
  • 70
brij
  • 331
  • 1
  • 5
  • 17

1 Answers1

2

Validation functionality overall is not implemented in Jackson since it is considered to be out of scope, see for example Jackson - Required property?.

And some information about why the annotation @JsonProperty(required = true) does not work on field can be found here: Jackson @JsonProperty(required=true) doesn't throw an exception.

However there is a trick that might work for null & existing well-valued fields values but throw an exception if the field is missing completely. Create a constructor with annotation @JsonCreator (and do not create a default constructor!) where the same annotation @JsonProperty(value = "*field_name*", required = true) is used and it will throw in case of missing field, so like:

@Getter @Setter
public class KeyHolder {
    private String firstKey;
    private String secondKey;
    private String thirdKey;

    @JsonCreator
    public KeyHolder(
            @JsonProperty(value = "firstKey", required = true) String firstKey,
            @JsonProperty(value = "secondKey", required = true) String secondKey,
            @JsonProperty(value = "thirdKey", required = true) String thirdKey) {
        this.firstKey = firstKey;
        this.secondKey = secondKey;
        this.thirdKey = thirdKey;
    }

}

With these, doing:

new ObjectMapper().readValue("{ \"firstKey\": \"val1\", \"secondKey\": \"val2\" }"
        , KeyHolder.class);

should result into something like:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Missing required creator property 'thirdKey' (index 2)

Any required parameter needs also to be a constructor parameter. So if there is added field fourthKey the constructor needs also a fix so like adding:

@JsonProperty(value = "fourthKey", required = true) String fourthKey) {

and

this.fourthKey = fourthKey;
pirho
  • 11,565
  • 12
  • 43
  • 70
  • I just tried that and it seems to be not working as well. I added one more field in this class, lets say fourthKey, which is not present in my json response and no exception was thrown while deserializing. – brij Dec 24 '19 at 04:50
  • @brij and you added also the required constructor parameter fro fourthKey? – pirho Dec 24 '19 at 07:24
  • yes, for testing this I added an extra field in my model that is not present in the JSON keys and still there was no exception thrown during binding. – brij Dec 24 '19 at 08:58
  • @brij hard to say what is problem with your code/env, maybe it is some Jackson setting or perhaps you catch the exception somewhere so it is suppressed. Just edited the answer how I prove it working. It might also be your jackson version I guess this needs at least 2.6. – pirho Dec 24 '19 at 09:19
  • Is there a way to use this solution without having to specify value for each parameter in the constructor? It seems way easier than Gson custom deserialization, but kind of annoying :/ – Gal Mor Dec 03 '20 at 07:55
  • @brij looking again at your comment: did you add it as a constructor parameter also? Not only as class member? – pirho Dec 03 '20 at 10:02
  • @GalMor I am afraid not (not 100% sure though). In that case using Jackson there should be some kind of custom de-serializer involved also. – pirho Dec 03 '20 at 10:09