8

I have a JSON schema, and a json string that matches the schema, except it might have a few extra fields. Jackson will throw an exception if those fields are there if I don't add objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);. Is there a way to obtain a collection of those extra fields to log them, even if I throw an exception?

Here's the relevant bit of the code:

public boolean validate(Message<String> json) {
    List<String> errorList = jsonSchema.validate(json.getPayload());
    ObjectMapper mapper = new ObjectMapper();
    try {
        Update update = mapper.readValue(json.getPayload(), Update.class);
    } catch (IOException e) {
        System.out.println("Broken");
    }
    if(!errorList.isEmpty()) {
        LOG.warn("Json message did not match schema: {}", errorList);
    }
    return true;
}
Tavo
  • 3,087
  • 5
  • 29
  • 44

2 Answers2

16

I don't think there's such an option out of the box.

You could however keep these unkwown fields with @JsonAnyGetter and @JsonAnySetter in a map (Hashmap,Treemap) as exemplified in this article and this one.

Add this to your Update class:

  private Map<String, String> other = new HashMap<String, String>();

  @JsonAnyGetter
  public Map<String, String> any() {
   return other;
  }

 @JsonAnySetter
  public void set(String name, String value) {
   other.put(name, value);
  }

And you can throw an exception yourself if the extra fields list is not empty. The method for checking that:

 public boolean hasUnknowProperties() {
   return !other.isEmpty();
  }
Laurentiu L.
  • 6,566
  • 1
  • 34
  • 60
  • The problem is that the Update class is auto-generated, so anything I add to it will be wiped out. Any other ideas? – Tavo Jun 17 '15 at 14:55
  • 3
    @Tavo Extend the Update class. – Laurentiu L. Jun 17 '15 at 14:57
  • I gone through your answer and tried but did not work perfectly for me. I want to know how to obtain the duplicate fields from `JSON` using the `@JsonAnySetter` when using with the `ObjectMapper.treeToValue` method. It would work perfectly when used with the `ObjectMapper.readValue` but when used with the `treeToValue` then `Jackson` stores only the last value of the duplicate key. It ignores the previous all values of the duplicated key. I would like to know how can I get all values of the `duplicate` key when using the `Jackson` with `ObjectMapper.treeToValue` method. – BATMAN_2008 May 10 '21 at 10:31
  • @BATMAN_2008 I recommend you ask a new question to get more eyes on it. Personally I doubt you can do that directly with `.treeToValue`, you expect it to merge values for the same key on the same level when traversing the tree, but that is a rather specific functionality (see `TreeTraversingParser`). Even with JSON, while the standard does not constrain keys to be unique, most implementations do not actually support duplicates. I recommend that in your new question to also take a step back and try to explain why you are trying to use treeToValue (i.e. what are you really trying to achieve) – Laurentiu L. May 11 '21 at 12:02
  • 1
    @LaurentiuL. Thanks a lot for the response. I have posted the questions if you get a chance please have a look and provide your suggestion: https://stackoverflow.com/questions/67413028/jackson-jsonanysetter-ignores-values-of-duplicate-key-when-used-with-jackson-ob – BATMAN_2008 May 11 '21 at 12:29
  • @LaurentiuL. both of the articles you linked are no longer available! :( – cptully Apr 07 '22 at 14:46
2

If you simply want to know what the first unknown property (name) is, I think the exception you get does have reference to that property name. You won't be able to get more information since processing stops at the first unknown property (or, if ignoring, that value is skipped).

Use of @JsonAnySetter which was suggested is a good option.

StaxMan
  • 113,358
  • 34
  • 211
  • 239