Deserialising Jackson abstract and multiple concrete classes

Viewed 204

I am working in Java with Jackson.

I have an abstract class Base.class, which looks as follows:

@JsonDeserialize(as = Child1.class)
public abstract class Base {

    @JsonProperty("field1")
    private Boolean field1;

    @JsonProperty("field2")
    private Long field2;
//getters, setters
}

And a bunch of child classes that extend the abstract class, that look like this:

public class Child1 extends Base {
    
        @JsonProperty("field3")
        private Boolean field3;
    
        @JsonProperty("field4")
        private Long field4;
    //getters, setters
    }

When I deserialise the following JSON, it works perfectly well:

Base base = mapper.readValue(new File("src/test/resources/testerTemplate/example.json"), Base.class)

example.json :

{
  "field1":true,
  "field2":123456,
  "field3":false,
  "field4":123456,
}

The issue is that this limits this structure to one-to-one relationship between base and child classes - to deserialise into other child classes I would need to change the annotation every single time. I have tried other annotations but has not been able to work it out. How do I do this?

1 Answers

I have worked out a solution that allows the code to do what I need it to do, although I am not entirely happy with the outcome. Nonetheless, it works.

The solution is to extend the Base.class by an intermediate abstract class that will be deserialized instead of the Base.class, like so:

Base.class (contains the generic fields we want to include when deserialising child classes):

public abstract class Base {

    @JsonProperty("field1")
    private Boolean field1;

    @JsonProperty("field2")
    private Long field2;
//getters, setters
}

An "extension" class that we will use to deserialize a specific child:

@JsonDeserialize(as = Child1.class)
public abstract class BaseChild1 extends Base {}

And the Child1.class:

public class Child1 extends BaseChild1 {
    
        @JsonProperty("field3")
        private Boolean field3;
    
        @JsonProperty("field4")
        private Long field4;
    //getters, setters
    }

This means that for every child class, we would create an empty abstract class that extends from the Base.class.

We then deserialize as follows:

ObjectMapper mapper = new ObjectMapper();

BaseChild1 child1 = mapper.readValue(new File("src/test/resources/testerTemplate/example.json"), BaseChild1.class)

BaseChild2 child2 = mapper.readValue(new File("src/test/resources/testerTemplate/example.json"), BaseChild2.class)

...

It is not perfect, but it works.

Related