Как внедрить зависимость в десериализатор Jackson Custom - PullRequest
0 голосов
/ 20 февраля 2019

Я хочу включить пользовательский десериализатор Джексона для некоторых полей типа String.Десериализатор также должен быть внедрен с помощью зависимого компонента.SampleCode ниже:

public class CustomDeserializer extends StdDeserializer<String> {

    private SomeDependecy dependency;

    public StringDeserializer() {
        this(null);
    }

    public StringDeserializer(Class<?> vc) {
        super(vc);
    }

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return dependency.perform(p.getValueAsString());
    }
}

Я не могу зарегистрировать модуль, основанный на типе класса, так как он является универсальным (String.class, Complex Datatype (но не для каждого требуется десериализатор custome)).Есть ли способ достичь вышеупомянутого без использования статических методов?

PS: я провел поиск в сети, но не смог найти более чистого решения без использования статики.Все предложения где-то с использованием некоторого статического метода, чтобы получить контекст и бин.

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

Похоже, есть другой подход (спасибо одному из моих коллег), использующий injectableValues ​​для экземпляра objectMapper и затем извлекающий зависимость через DeserializationContext ctxt.Ниже приведен код.

Модуль GUI ObjectMapper.

public class MerchantConverterModule extends AbstractModule {

    @Override
    protected void configure() {

    }

    @Provides
    @Singleton
    public ObjectMapper objectMapper() {

        ObjectMapper objectMapper = new ObjectMapper();

        /**
         * Add dependency object to object mapper.
         */
        objectMapper.setInjectableValues(new InjectableValues
            .Std()
            .addValue("DependencyName", dependency));

        return objectMapper;
    }


}

Код вашего пользовательского десериализатора

public class CustomDeserializer extends StdDeserializer<String> {

    private SomeDependecy dependency;

    public StringDeserializer() {
        this(null);
    }

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        return getDependency(ctxt).perform(p.getValueAsString());
    }

    private SomeDependency getDependency(DeserializationContext ctxt) {
        SomeDependency dependency = (SomeDependency) ctxt
                .findInjectableValue("DependencyName", null, null);

        return dependency;
    }
}

findInjectableValue - это последний метод, поэтому вы можетеНужно настроить свой код модульного теста, чтобы макетировать финал.

ПРИМЕЧАНИЕ: Недостатком является то, что существует тесная связь между объектным картографом и десериализатором.

0 голосов
/ 21 февраля 2019

Взгляните на ContextualDeserializer интерфейс.Из документации:

Интерфейс надстройки, который JsonDeserializer может реализовать для получения обратного вызова, который можно использовать для создания контекстных (контекстно-зависимых) экземпляров десериализатора для использования для обработки свойств поддерживаемого типа.Это может быть полезно для десериализаторов, которые могут быть настроены с помощью аннотаций или иначе должны иметь различное поведение в зависимости от того, какое свойство десериализуется.

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

interface Dependency {

    String decrypt(String value);
}

class SomeDependency implements Dependency {

    public SomeDependency() {
        System.out.println("Create new SomeDependency!");
    }

    @Override
    public String decrypt(String value) {
        return value.replace('a', 'A');
    }
}

class DecryptModule extends AbstractModule {

    @Override
    protected void configure() {
        bind(Dependency.class).to(SomeDependency.class);
    }
}

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

class DecryptDeserializer extends StdDeserializer<String> implements ContextualDeserializer {

    private Dependency dependency;

    public DecryptDeserializer() {
        super(String.class);
    }

    @Override
    public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        return dependency.decrypt(p.getValueAsString());
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
        Injector injector = Guice.createInjector(new DecryptModule());
        DecryptDeserializer deserializer = new DecryptDeserializer();
        deserializer.dependency = injector.getInstance(Dependency.class);

        return deserializer;
    }
}

createContextual метод используется для создания нового экземпляра десериализатора.У вас есть много вариантов, как его создать.Вы даже можете смешать это решение с Static Injection .

...