Вы можете реализовать пользовательский JsonDeserializer
для вашего общего типа, который также реализует ContextualDeserializer
.
Например, предположим, что мы имеем следующий простой тип оболочки, содержащий общую стоимость:
public static class Wrapper<T> {
public T value;
}
Теперь мы хотим десериализации JSON, который выглядит следующим образом:
{
"name": "Alice",
"age": 37
}
в экземпляр класс, который выглядит следующим образом:
public static class Person {
public Wrapper<String> name;
public Wrapper<Integer> age;
}
Внедрение ContextualDeserializer
позволяет нам создать конкретный десериализатор для каждого поля в классе Person
на основе параметров типового типа поля. Это позволяет десериализовать имя как строку, а возраст - как целое.
Полный десериализатор выглядит следующим образом:
public static class WrapperDeserializer extends JsonDeserializer<Wrapper<?>> implements ContextualDeserializer {
private JavaType valueType;
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
JavaType wrapperType = property.getType();
JavaType valueType = wrapperType.containedType(0);
WrapperDeserializer deserializer = new WrapperDeserializer();
deserializer.valueType = valueType;
return deserializer;
}
@Override
public Wrapper<?> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
Wrapper<?> wrapper = new Wrapper<>();
wrapper.value = ctxt.readValue(parser, valueType);
return wrapper;
}
}
Лучше смотреть на createContextual
здесь первый, так как это будет называться первым Джексон. Мы считываем тип поля из BeanProperty
(например, Wrapper<String>
), а затем извлекаем первый тип типичного типа (например, String
). Затем мы создаем новый десериализатор и сохраняем внутренний тип как valueType
.
После deserialize
вызывается этой вновь созданной десериализатор, можно просто попросить Джексона десериализовать значение в качестве внутреннего типа, а не весь тип обертки, и возвращает новый Wrapper
содержащий десериализованное значение.
Для того, чтобы зарегистрировать этот обычай десериализации, мы тогда необходимо создать модуль, содержащий его, и зарегистрировать этот модуль:
SimpleModule module = new SimpleModule()
.addDeserializer(Wrapper.class, new WrapperDeserializer());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
Если мы затем попытаться десериализации пример JSON из выше, мы можем видеть, что он работает, как ожидалось:
Person person = objectMapper.readValue(json, Person.class);
System.out.println(person.name.value); // prints Alice
System.out.println(person.age.value); // prints 37
Есть еще некоторые подробности о том, как контекстная deserializers работать в Jackson documentation.
Вы можете использовать отражение, чтобы выяснить, что * объявлен * тип 'foo' -' Foo '. Вот и все. Я не знаю о Джексоне, чтобы сказать, что это средство для вас здесь. ['Поле # getGenericType'] (http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Field.html#getGenericType--) –
Radiodef