Десериализуйте полезную нагрузку JSON, которая представляет строку или объект с помощью Джексона.

Я хочу десериализовать полезную нагрузку JSON, представляющую поле, которое может быть строкой (нерасширенной) или объектом (расширенной):

Пример полезной нагрузки unexpanded: отправляется только строковое значение, которое содержит идентификатор.

{
  "id" : "777424881071",
  "category" : "/category/12",
  "title" : "ACADEMY DINOSAUR",
  "description" : "A Epic Drama of ...",
  }

Пример полезной нагрузки expanded: отправляется соответствующий идентификатор:

{
  "id" : "777424881071",
  "category" : {
    "id" : "12",
    "name" : "Children"
  },
  "title" : "ACADEMY DINOSAUR",
  "description" : "A Epic Drama of ...",
  }

В java это может быть представлено таким типом:

public class ExpandableField<T> {
  private String id;
  private T expandedObject;

  public ExpandableField(String id, T expandedObject) {
    this.id = id;
    this.expandedObject = expandedObject;
  }
}

См. ExpandableField для полного примера из полосатого java-клиента.

Мне интересно, как я могу написать JsonDeserializer<ExpandableField<?>> для Джексона.

public class ExpandableFieldDeserializer extends JsonDeserializer<ExpandableField<?>> {

    @Override
    public ExpandableField<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonToken token = p.getCurrentToken();
        if (token == JsonToken.VALUE_STRING) {
            return new ExpandableField<>(p.getValueAsString(), null);
        }
        else if (token == JsonToken.START_OBJECT) {
            //TODO deserialize object and compute id
            return new ExpandableField<>(id, object);
        }
        return null;
    }
}

Мое текущее решение состоит в том, чтобы загрузить текущее дерево и жестко указать соответствующий класс с помощью небольшого метода: private Class<?> computeType(JsonNode node).

public class ExpandableFieldDeserializer extends JsonDeserializer<ExpandableField<?>> {

    @Override
    public ExpandableField<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        JsonToken token = p.getCurrentToken();
        if (token == JsonToken.VALUE_STRING) {
            return new ExpandableField<>(p.getValueAsString(), null);
        }
        else if (token == JsonToken.START_OBJECT) {
            ObjectCodec codec = p.getCodec();
            JsonNode node = codec.readTree(p);
            String id = null;
            if (node.has("id")) {
                id = node.asText();
            }
            Class<?> typeClass = computeType(node);
            Object object = codec.treeToValue(node, typeClass);
            return new ExpandableField<>(id, object);
        }
        return null;
    }

    private Class<?> computeType(JsonNode node) {
        //...
    }
}

Я бы предпочел что-то более динамичное.


Для сравнения, в библиотеке gson тип доступен в сигнатуре метода:

deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)

с ((ParameterizedType) typeOfT).getActualTypeArguments()[0] context может десериализовать объект с context.deserialize(json, t).

См. полный пример здесь: Десериализатор расширяемого поля


Как можно сделать что-то подобное с Джексоном?


person Jmini    schedule 23.04.2018    source источник
comment
Вы просите что-то похожее на утиную печать? Как здесь спросили stackoverflow.com/ вопросы/11842029/ ?   -  person jschnasse    schedule 23.04.2018
comment
Также обнаружил это: мы хотели, чтобы наш десериализатор автоматически создавал экземпляры правильных типов для нас ="nofollow noreferrer">tech.willhaben.at/   -  person jschnasse    schedule 23.04.2018