ObjectMapper
имеет setInjectableValues, который позволяет зарегистрировать некоторые внешние компоненты, которые мы хотим использовать во время serialisation
/deserialisation
. Например, класс DeserializationContext
имеет findInjectableValue, который позволяет найти ранее зарегистрированный бин в контексте по имени. Ниже вы можете найти пример, который показывает общее представление о том, как это сделать. Во-первых, объявим инъекционный компонент, который мы хотим автоматически связать:
class InjectBean {
private int key = ThreadLocalRandom.current().nextInt();
@Override
public String toString() {
return "key => " + key;
}
}
POJO
, который мы хотим десериализовать из XML
, может выглядеть следующим образом:
class Pojo {
private String name;
private InjectBean dependency;
// getters, setters, toString
}
Теперь нам нужно реализовать пользовательский десериализатор, который будет вводить поле autowired:
class PojoBeanDeserializer extends BeanDeserializer {
public static final String DEPENDENCY_NAME = "injectBean";
public PojoBeanDeserializer(BeanDeserializerBase src) {
super(src);
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
Object deserialize = super.deserialize(p, ctxt);
InjectBean injectableValue = findInjectableValue(ctxt);
Pojo pojo = (Pojo) deserialize;
pojo.setDependency(injectableValue);
return deserialize;
}
private InjectBean findInjectableValue(DeserializationContext context) throws JsonMappingException {
return (InjectBean) context.findInjectableValue(DEPENDENCY_NAME, null, null);
}
}
Приведенный выше десериализатор можно использовать только для класса Pojo
. Если вам нужно сделать то же самое для многих классов, вы можете извлечь метод setDependency
в интерфейс и реализовать его в этом интерфейсе для каждого POJO
, с которым вам нужно обращаться таким же образом. В приведенном выше десериализаторе вместо приведения к Pojo
вы можете приводить к своему интерфейсу. Чтобы зарегистрировать наш пользовательский десериализатор, я буду использовать BeanDeserializerModifier
, но вы можете сделать это и другим способом. Например, если у вас уже есть собственный десериализатор и вы используете аннотацию @JsonDeserialize
, вам не нужно этого делать. Простое использование может выглядеть следующим образом:
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.InjectableValues;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
import com.fasterxml.jackson.databind.deser.BeanDeserializerBase;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ThreadLocalRandom;
public class XmlMapperApp {
public static void main(String[] args) throws Exception {
File xmlFile = new File("./resource/test.xml").getAbsoluteFile();
InjectBean injectBean = autowire();
InjectableValues.Std injectableValues = new InjectableValues.Std();
injectableValues.addValue(PojoBeanDeserializer.DEPENDENCY_NAME, injectBean);
SimpleModule injectModule = new SimpleModule();
injectModule.setDeserializerModifier(new InjectBeanDeserializerModifier());
XmlMapper xmlMapper = new XmlMapper();
xmlMapper.registerModule(injectModule);
xmlMapper.setInjectableValues(injectableValues);
Pojo bean = xmlMapper.readValue(xmlFile, Pojo.class);
System.out.println("After deserialization:");
System.out.println(bean);
}
private static InjectBean autowire() {
InjectBean bean = new InjectBean();
System.out.println("Injectable bean from context: " + bean);
return bean;
}
}
class InjectBeanDeserializerModifier extends BeanDeserializerModifier {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (beanDesc.getType().getRawClass() == Pojo.class) {
JsonDeserializer<?> jsonDeserializer = super.modifyDeserializer(config, beanDesc, deserializer);
return new PojoBeanDeserializer((BeanDeserializer) jsonDeserializer);
}
return super.modifyDeserializer(config, beanDesc, deserializer);
}
}
Для полезной нагрузки ниже XML
:
<Pojo>
<name>Tom</name>
</Pojo>
Отпечатки:
Injectable bean from context: key => 909636975
After deserialization:
Bean{name='Tom', dependency=key => 909636975}
Смотрите также:
person
Michał Ziober
schedule
07.05.2019