2

I have a class like:

public abstract class JsonMotivation {

    protected int motivationid;

    ... getters and setters

    public abstract String getMotivationType();
        public void setMotivationType(String motivationType) {
    }
} 

This motivationType datafield will keep a reference

Then I have some implementing class like:

@XmlRootElement
public class JsonAntibioticMotivation extends JsonMotivation {
    protected long smhid;
    protected int userid;

    @Override
    public String getMotivationType() {
        return "AB";
    }

    ... getters and setters
}

Finally I have some more classes that extend the JsonAntibioticMotivation class e.g.

@XmlRootElement
public class JsonSwitchAntibioticMotivation extends JsonAntibioticMotivation {
    @Override
    public String getMotivationType() {
        return "AB-S";
    }
    ... some additional dataparameters
}

One of the classes called JsonMedicationhistory references the abstract class JsonMotivation. On deserialization I get an error saying "Can not construct instance of be.uzgent.cosara.model.json.JsonMotivation, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information"

It seems logical that Jackson does not know which concrete class to use for deserialization. Could I somehow map the motivationType to a concrete class? I've tried writing a custom deserializer and annotated JsonMotivation with @JsonDeserialize(using=JsonMotivationDeserializer.class)

public class JsonMotivationDeserializer extends  JsonDeserializer<JsonMotivation> {

    @Override
    public JsonMotivation deserialize(JsonParser jp,
        DeserializationContext ctxt) throws IOException,
        JsonProcessingException {
        ObjectMapper mapper= new ObjectMapper();
        JsonNode node=jp.getCodec().readTree(jp);
        JsonNode motivationTypeNode=node.get("motivationType");
        if(motivationTypeNode!=null){
            String motivationType=motivationTypeNode.textValue();
            switch(motivationType){
                case "AB": return mapper.readValue(jp, JsonAntibioticMotivation.class);
                case "AB-N": return mapper.readValue(jp, JsonNewAntibioticMotivation.class);
                case "AB-S": return mapper.readValue(jp, JsonSwitchAntibioticMotivation.class);
                case "AB-E": return mapper.readValue(jp, JsonExtendAntibioticMotivation.class);
            }
        }
        return null;
    }
}

However, this did not seem to solve the problem. The ObjectMapper does not seem to know the original mappings. Is there a way to delegate the rest of the process to the original deserialization process once you know the concrete class?

gadeynebram
  • 725
  • 2
  • 6
  • 22

1 Answers1

1

It seemed like I only needed to anotate my JsonMotivation class with

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")

The custom deserializer could then be removed.

gadeynebram
  • 725
  • 2
  • 6
  • 22