Десериализация производных классов с Джексоном

У меня есть два автоматически сгенерированных класса следующим образом:

public class DataMonitoringClauseType extends ClauseType {
}

public class ClauseType {
}

Поскольку классы генерируются автоматически, я не могу определить дополнительные аннотации, такие как JsonSubType для них.

У меня есть третий объект со списком ClauseTypes следующим образом:

public class RootClass {
    List<ClauseType> clauses;
}

Учитывая сериализованный RootClassЕсть ли способ десериализации RootClass экземпляр такой, что у меня будет DataMonitoringClauseType экземпляры внутри clauses список?

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

ObjectMapper mapper = new ObjectMapper();
mapper.registerSubtypes(DataMonitoringClauseType.class);

Обратите внимание, что сериализованный контент передается в качестве входных данных на сервер. Поэтому у меня нет возможности включить информацию о типе в сериализованный контент.

2 ответа

Решение

Для Джексона вы можете определить собственный десериализатор для ClauseType по линии

class ClauseTypeDeserializer extends StdDeserializer<DataMonitoringClauseType> {

    @Override
    public DataMonitoringClauseType deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
        // get data, e.g.: data = jp.getCodec().readTree(jp).toString().getBytes();
        // construct result:
        return new DataMonitoringClauseType(data)
    }
}

Вы можете сделать его более общим, заявив о возвращении ClauseType и затем принятие решения, какой экземпляр возвращать на основе данных. В любом случае, зарегистрируйте его в ObjectMapper с помощью:

ObjectMapper mapper = new ObjectMapper()
  .registerModule(new SimpleModule()
    .addDeserializer(ClauseType.class, new ClauseTypeDeserializer()));

Если вы когда-либо интересовались Gson, решение очень похоже:

class ClauseTypeDeserializer implements JsonDeserializer<ClauseType> {

    @Override
    public ClauseType deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        // get data, e.g.: data = jpson.toString().getBytes();
        // construct result:
        return new DataMonitoringClauseType(data)
    }
}

И зарегистрируйте его в GsonBuilder:

Gson gson = new GsonBuilder()
  .registerTypeAdapter(ClauseType.class, new ClauseTypeDeserializer())
  .build();

Использование специального десериализатора не требуется. Нет необходимости в пользовательских десериализаторах или Gson. Джексон предлагает несколько способов.

Во-первых: то, что вы не можете напрямую изменять классы, не означает, что вы не можете использовать аннотации Джексона: это именно тот случай использования для "смешанных" аннотаций. См. https://dzone.com/articles/jackson-mix-in-annotations например, о том, как использовать дополнения, чтобы вы могли иметь эквивалент

@JsonDeserialize(as=DataMonitoringClauseType.class)
public class ClauseType { .... }

В качестве альтернативы вы также можете зарегистрировать тип реализации (ваша попытка регистрации подтипов будет работать для полиморфных подтипов, где используется идентификатор типа - но я не думаю, что это то, что вы хотите здесь). Что сделано с помощью Module интерфейс, метод "addAbstractTypeMapping ()"

https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/module/SimpleModule.html

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