Home > Software engineering >  Can a non-nested value be deserialized using a custom Jackson JsonDeserializer?
Can a non-nested value be deserialized using a custom Jackson JsonDeserializer?

Time:10-15

I'm working with a project that is using a custom Jackson JsonDeserializer to deserialize an object with a field containing a third-party object from JSON that cannot be deserialized directly. This deserializer is used by annotating the field with @JsonDeserialize(using = CustomTypeDeserializer.class).

public static class OuterType {
    @JsonDeserialize(using = CustomTypeDeserializer.class)
    private CustomType customType;

    public CustomType getCustomType() { return customType; }
    public void setCustomType(CustomType customType) { this.customType = customType; }
}

This works fine when the type to be deserialized is a property of another type, since there is a place to put the @JsonDeserialize annotation. One thing it does not work for is deserializing the type directly.

new ObjectMapper().readValue(json, CustomType.class); // Doesn't work.

It doesn't look like I can use the deserializer directly, as it does not appear to be written in a way that it can directly deserialize values outside of the context of an ObjectMapper.

Is there a way to deserialize a non-nested type using a custom deserializer?

CodePudding user response:

One approach would be to write a custom Module containing the deserializer to the module, and add the module to the ObjectMapper.

public static class CustomTypeModule extends SimpleModule {
    public CustomTypeModule() {
        addDeserializer(CustomType.class, new CustomTypeDeserializer());
    }
}
JsonMapper objectMapper = JsonMapper.builder().addModule(new CustomTypeModule()).build();
CustomType value = objectMapper.readValue(json, CustomType.class);

If you don't want to modify your global application ObjectMapper (making the module available to all requests), you can apply this to a copy of the ObjectMapper used just for this operation.

JsonMapper objectMapper = JsonMapper.builder().build();

// ...

JsonMapper customTypeMapper = objectMapper.rebuild().addModule(new CustomTypeModule()).build();
// OR
ObjectMapper customTypeMapper = objectMapper.copy().registerModule(new CustomTypeModule())

CustomType value = customTypeMapper.readValue(json, CustomType.class);

CodePudding user response:

If yours possible scenarios guarantee that a custom deserialer will be always applied over your type not considering if it is nested or not you could apply directly the JsonDeserialize annotation over your CustomType class as an alternative to your solution :

@JsonDeserialize(using = CustomTypeDeserializer.class)
public class CustomType {}

If in your json you want to extract the CustomType object you can use the readTree and treeToValue methods :

//customType object labelled with "customType"
JsonNode tree = mapper.readTree(src).get("customType");
CustomType custom = mapper.treeToValue(tree, CustomType.class);
  • Related