Egor Stepanov
Egor Stepanov

Reputation: 855

How to deserialize JSON with jackson when java class of value1 depends on value2

I have a JSON string:

{
  "entities": [
    {
      "type": "fio",
      "value": {
        "firstName": "first",
        "lastName": "last"
      }
    },

    {
      "type": "geo",
      "value": {
        "country": "the country",
        "city": "the city"
      }
    },

    {
      "type": "number",
      "value": 100
    },

    {
      "type": "number",
      "value": 3.14
    }
  ]
}

It's a list of some entities, that have params type and value. Depending of the type, param value has specific representation.

For example:

I created an absract class EntityValue with few implementations. I used jackson annotations:

@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME, 
  include = JsonTypeInfo.As.PROPERTY, 
  property = "type")
@JsonSubTypes({ 
  @Type(value = GeoEntityValue.class, name = "geo"), 
  @Type(value = FioEntityValue.class, name = "fio"),
  ... 
})
public class Entity {

    private final EntityType type;
    private final EntityValue value;

    ... constructor and getters ...
}

It works pretty well for a complex types like fio or geo, but I struggle with a number type. It serializes and deserializes like a complex object, not like the example mentioned at the beginning.

Can you please help me to manage with jackson annotations or reorganize class hierarchy to make serialization and deserialization works ?

Thanks!

Upvotes: 1

Views: 649

Answers (1)

Prabhakar D
Prabhakar D

Reputation: 1134

Here is a solution that works:

  @JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = As.PROPERTY,
    property = "type")
@JsonSubTypes(value = {
    @Type(value = GeoEntity.class, name = "geo"),
    @Type(value = FioEntity.class, name = "fio"),
    @Type(value = Number.class, name ="number")
})
public abstract class Entity {

  public void setType(String type) {
    this.type = type;
  }

  private String type;

  @Override
  public String toString(){
    return ToStringBuilder.reflectionToString(this);
  }

}

FioEntity class (similar way we can create GeoEntity )

    public class FioEntity extends Entity {

      public FioEntityValue getValue() {
        return value;
      }

      public void setValue(FioEntityValue value) {
        this.value = value;
      }

      private FioEntityValue value;


    public class FioEntityValue extends  EntityValue{

      private String firstName;

      private String lastName;


      public String getLastName() {
        return lastName;
      }

      public void setLastName(String lastName) {
        this.lastName = lastName;
      }

      public String getFirstName() {
        return firstName;
      }

      public void setFirstName(String firstName) {
        this.firstName = firstName;
      }
    }
   }

Number class:

public class Number extends Entity {

  private Double value;

  public Double getValue() {
    return value;
  }

  public void setValue(Double value) {
    this.value = value;
  }

}

Test class:

public class Test {

  public static void main(String[] args) throws IOException {


    ObjectMapper mapper = new ObjectMapper();
    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    String content = "{\n"
        + "  \"entities\": [\n"
        + "    {\n"
        + "      \"type\": \"fio\",\n"
        + "      \"value\": {\n"
        + "        \"firstName\": \"first\",\n"
        + "        \"lastName\": \"last\"\n"
        + "      }\n"
        + "    },\n"
        + "\n"
        + "    {\n"
        + "      \"type\": \"geo\",\n"
        + "      \"value\": {\n"
        + "        \"country\": \"the country\",\n"
        + "        \"city\": \"the city\"\n"
        + "      }\n"
        + "    },\n"
        + "\n"
        + "    {\n"
        + "      \"type\": \"number\",\n"
        + "      \"value\": 100\n"
        + "    },\n"
        + "\n"
        + "    {\n"
        + "      \"type\": \"number\",\n"
        + "      \"value\": 3.14\n"
        + "    }\n"
        + "  ]\n"
        + "}";

    Entities test = mapper.readValue(content, Entities.class);

    System.out.println(mapper.writeValueAsString(test));


  }

}

outPut:

 {"entities":[{"type":"fio","value":{"firstName":"first","lastName":"last"}},{"type":"geo","value":{"city":"the city","country":"the country"}},{"type":"number","value":100.0},{"type":"number","value":3.14}]}

Upvotes: 1

Related Questions