Десериализация производных классов с Джексоном
У меня есть два автоматически сгенерированных класса следующим образом:
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 ()"