Custom deserializer for TreeMap - cannot get full text by JsonParser

Viewed 273

I have a class defined as following:

class Rule {
    private final TreeMap<String, String> rule;
    public Rule(TreeMap<String, String> rule) {
        this.rule = rule;
    }
}

Another class contains a list of such object:

class BigClass {
    
    @JsonProperty("rules")
    @JsonDeserialize(contentUsing = Rule.Deserializer.class)
    private final List<Rule> rules;

    //...

}

... and as specified in the @JsonDeserialize annotation, I want the content of such list to be treated by a custom deserializer.

For that, I have extended the JsonDeserializer<Rule> as follows:

public static final class Deserializer extends JsonDeserializer<Rule> {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Rule deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String strRule = p.getText();
        TypeReference<TreeMap<String, String>> typeReference = new TypeReference<>() {
        };

        TreeMap<String, String> ruleMap = objectMapper.readValue(strRule, typeReference);
        return new Rule(ruleMap);
    }
}

When I try to parse a Json of type BigClass with the following structure:

{
    ...
    "rules": [
        {
            "A": "B",
            "C": "D",
            "E": "F" 
        }
    ]
}

... I am correctly called inside my own deserialize() method, but the problem is that the expression p.getText() only returns me { (the very first token), so the deserialization fails.

I have tried to put everything in the same line (no carriage return), but I have the same problem. It seems something obvious and simple but I can't find any example on the web nor in the Jackson documentation. Any suggestion or reference to share please?

1 Answers

Change your deserialize method as follows: You read the whole JsonNode in the deserialization step, and construct your own TreeMap based on the key-values that you find in the node. (you may have to add a constructor to the Rule class)

@Override
  public Rule deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
    JsonNode node = p.getCodec().readTree(p);
    TreeMap<String, String> ruleMap = new TreeMap<>();
    node.fields().forEachRemaining(e -> ruleMap.put(e.getKey(), e.getValue().textValue()));

    return new Rule(ruleMap);
  }
Related