Search code examples
javaserializationjacksondeserializationjackson2

Java Jackson deserialize objects of the same name but different class types


I have POJOs that are used as the request and response object in a REST API like so (I know duplicate @JsonProperty isn't syntactically correct, see below):

public class Request {

    @JsonProperty("patient")
    PatientObjectA patientA;

    @JsonProperty("patient")
    PatientObjectB patientB;
}

public class PatientObjectA {
    @JsonProperty("identifier")
    Private Identifier identifier

    @JsonProperty("system")
    Private String system;

    @JsonProperty("value")
    Private String value;
}

public class PatientObjectA {
    @JsonProperty("identifier")
    Private List<Identifier> identifier

    @JsonProperty("system")
    Private String system;

    @JsonProperty("value")
    Private String value;
}

There are minor differences in cardinality in that I want to be able to consume i.e the "Patient" object will sometimes be (PatientObjectA in Request class):

"patient": {
  "identifier": {
    "type": {
      "coding": {
        "system": "NA",
        "code": "Patient"
      },
      "text": "Patient"
    },
    "system": "Patient",
    "value": "000000000"
  }
}

or this case (note the differences in cardinality on the identifier object, where in this case identifier can have one or more items) (PatientBObject in Request class):

    "patient": {
      "identifier": [{
         "type": {
          "coding": {
            "system": "NA",
            "code": "Patient"
          },
          "text": "Patient"
        },
        "system": "Patient",
        "value": "3018572032"
      }]
    }

I would like to achieve a functionality where requests are mapped to the correct objects. Is there a way (other than a custom deserializer) where I can map the requests to the appropriate object by type/cardinality? Any insight would be appreciated!


Solution

  • Jackson support this with the @JsonTypeInfo annotation.

    I recommend specifying the type info in a property (a json field) and use the full class name (as opposed to a short name) to provide a better guarantee of uniqueness:

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

    Output A looks like: "patient": { "jsonType": "com.company.PatientAObject" "identifier": { "type": { "coding": { "system": "NA", "code": "Patient" }, "text": "Patient" }, "system": "Patient", "value": "000000000" } } Output B looks like: "patient": { "jsonType": "com.company.PatientBObject" "identifier": { "type": { "coding": { "system": "NA", "code": "Patient" }, "text": "Patient" }, "system": "Patient", "value": "000000000" } }

    Note: Also, check out @JsonRootName, as it will give you the ability to create a 'rooted' json object without having to have that wrapper object you have.

    @JsonRootName("Patient") @JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.CLASS, property = "jsonType") public class PatientObjectA { ..

    .. and ..

    @JsonRootName("Patient") @JsonTypeInfo(include = JsonTypeInfo.As.PROPERTY, use = JsonTypeInfo.Id.CLASS, property = "jsonType") public class PatientObjectB { ..

    Related terms to assist with more research:

    • polymorphism in json
    • json equivalent of xml namespaces.