Read field from parent node in custom Jackson Deserializer
Asked Answered
D

2

10

Have a look at the following input JSON:

{
    "importantKey": "123xyz",
    "nested": {
        // more stuff goes here.
    }
}

Nested is represented by an interface that has several different implementations. The point is, in order to figure out which implementation should be used for deserialization, I need to check importantKey's value.

My current solution is to deserialize the whole thing at once:

@Override
public Foo deserialize(JsonParser jp, DeserializationContext dc) 
            throws IOException, JsonProcessingException {

    ObjectMapper objectMapper = (ObjectMapper) jp.getCodec();
    ObjectNode objectNode = objectMapper.readTree(jp);
    String importantKey = objectNode.findValue("importantKey").asText();

    JsonNode nestedNode = objectNode.findValue("nested");
    NestedInterface nested;
    nested = objectMapper.treeToValue(nestedNode, findNestedImplFor(importantKey));

    // construct containing Foo and so on ...
}

This works but for several different reasons (specific to my use case) it would be a lot cooler if there was a Deserializer just for nested that somehow could read or had access to fields from the outer object.

I'm running jackson 2.8.x in a dropwizard context.

Does someone have an idea? Thanks in advance!

Duane answered 22/10, 2016 at 13:21 Comment(3)
Hi - I have answered the pretty much same question before. Jackson supports this kind of behaviour out of the box, where the serialisation depends on a field in the json value. Have a look here: #38502074Mashburn
@Mashburn Nice hint, but I cannot use annotations for my use case. The model lib is serialization/deserialization agnosticDuane
I have the same requirement and after inspection of data available JsonParser and DeserializationContext I may conclude that there is no way to get access to parent json node...Petrochemical
M
2

You can access it through the DeserializationContext like so

Object parent = dc.getParser().getParsingContext().getCurrentValue();

Then cast it to the appropriate POJO type that has the 'importantKey' field.

Multicolored answered 2/4, 2019 at 18:39 Comment(0)
C
0

I am using jackson 2.13.5. The class I want to deserialize is like

public class ParentClass {
    private String name;
    private MyClass myClass;
}

I am using a custom StdDeserializer.

public class MyClassDeserializer extends StdDeserializer<Myclass> {

    // ...

    @Override
    public MyClass deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        Object parentValue = jsonParser.getParsingContext().getParent().getCurrentValue();
        if(parentValue instanceof ParentClass) {
            ParentClass parentClass = (ParentClass) parentValue;
            String name = parentClass.getName();
            // a custom method to determine the subtype by name
            Class<? extends PluginConfig> subtype = loadSubtype(name);
            ObjectCodec codec = jsonParser.getCodec();
            // Deserialize MyClass using the appropriate subtype
            return codec.treeToValue(codec.readTree(jsonParser), subtype);
        }
        return null;
    }
}

This works for me, but I am not sure if this approach is recommended.

Cuda answered 1/6, 2023 at 2:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.