Как десериализовать JSON с Джексоном, когда java-класс value1 зависит от value2 - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть строка JSON:

{
  "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
    }
  ]
}

Это список некоторых сущностей, которые имеют параметры type и value .В зависимости от типа , параметр значение имеет конкретное представление.

Например:

  • если тип равен fio , то значение является сложным объектом, объединяющим 2 поля: firstName и lastName .
  • , если type is geo , тогда value является сложным объектом, связывающимполя: страна , город , ...
  • если тип равен число ,затем значение - это простое число (длинное или двойное)

Я создал класс absract * EntityValue с несколькими реализациями.Я использовал аннотации Джексона:

@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 ...
}

Работает довольно хорошо для сложных типов, таких как fio или geo , но я борюсь с число типа.Он сериализует и десериализует как сложный объект, а не как пример, упомянутый в начале.

Не могли бы вы помочь мне справиться с аннотациями Джексона или реорганизовать иерархию классов, чтобы сериализация и десериализация работали?* Спасибо!

1 Ответ

0 голосов
/ 08 февраля 2019

Вот решение, которое работает:

  @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 (аналогично тому, как мы можем создать 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;
      }
    }
   }

Класс номера:

public class Number extends Entity {

  private Double value;

  public Double getValue() {
    return value;
  }

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

}

Тестовый класс:

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));


  }

}

Выход:

 {"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}]}
...