Джексон десериализовал строку json с неизвестным именем свойства в общий тип

Я хотел бы десериализовать строку json, которая может иметь «неизвестное» свойство (но известного универсального свойства во время компиляции), и десериализовать это неизвестное свойство в предоставленный универсальный тип.

Строка JSON структурно может выглядеть следующим образом:

{
  "id":"abc",
  "human": {"name": "me", age: 99}
}
OR:
{
  "id":"abc",
  "cat": {"color": "orange"}
}
OR:
{
  "id":"abc",
  "bike": {"specs": {"speed":30}}
}

У меня есть следующие классы моделей:

@Value
@Builder
@Jacksonized
public class Data<T> {
  String id;
  T other; // <- how can I map "cat", "human", or "bike" into this generic
}

@V/B/J
public class Human {
  String name;
  Integer age;
}

@V/B/J
public class Cat {
  String color;
}

@V/B/J
public class Bike {
  Specs specs;
}

@V/B/J
public class Specs {
  Integer speed;
}

Требуемый универсальный вариант строки JSON будет известен во время компиляции, например:

Data<Human> humanData = objectMapper.readValue(jsonHumanString, Data.class);
Data<Cat> catData = objectMapper.readValue(jsonCatString, Data.class);
Data<Bike> bikeData = objectMapper.readValue(jsonBikeString, Data.class);

Однако я все еще получаю сообщение об ошибке: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "human". Как я могу принудительно сопоставить «велосипед», «кошку» и «человека» с «другим»?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
0
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Думаю, я нашел свой собственный ответ. Я могу использовать собственный десериализатор для всего класса Data, который разрешает дженерики.

@Value
@Builder
@JsonDeserialize(using = GenericDeserializer.class)
public class Data<T> {
    String id;
    T other;
}

Десериализатор:

public class GenericDeserializer extends StdDeserializer<Data<?>> {

    public GenericDeserializer() {
        this(null);
    }


    public GenericDeserializer(Class<Data<?>> vc) {
        super(vc);
    }

    @Override
    public Data<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
            throws IOException, JsonProcessingException {
        ObjectCodec codec = jsonParser.getCodec();
        JsonNode node = codec.readTree(jsonParser);
        if (node.has("bike")) {
            return Data.<Bike>builder()
                    .id(String.valueOf(node.get("id")))
                    .other(codec.treeToValue(node.get("bike"), Bike.class))
                    .build();
        } else if (node.has("human")) {
            return Data.<Human>builder()
                    .id(String.valueOf(node.get("id")))
                    .other(codec.treeToValue(node.get("human"), Human.class))
                    .build();
        } else if (node.has("cat")) {
            return Data.<Cat>builder()
                    .id(String.valueOf(node.get("id")))
                    .other(codec.treeToValue(node.get("cat"), Cat.class))
                    .build();
        }

    }
}

Другие вопросы по теме