Как да получа препратка към Jackson Object Mapper в приложение jersey2 / hk2

Имам приложение jersey2, конфигурирано за поддръжка на JSON чрез Jackson, добавяйки

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>${jersey.version}</version>
</dependency>

в POM файла и

public MyApplication() {
    ...
    register(JacksonFeature.class)
    ...
}

в моето приложение. Всичко работи, ресурсите ми получават десериализирани POJO като аргументи

@POST @Consumes(MediaType.APPLICATION_JSON)
public void blah(MyPojo p) {
    ...
}

Сега един от тези ресурси се нуждае от препратка към ObjectMapper на Джаксън, за да извърши самостоятелно десериализация. Опитах се да направя нещо подобно

@Inject
public MyResource(@Context ObjectMapper mapper) {
    ...
}

or

@GET
public String foo(@Context ObjectMapper mapper) {
    ...
}

но и в двата случая препратката към mapper е нула. Как мога да инжектирам препратка към ObjectMapper в моите ресурси?


person agnul    schedule 15.05.2015    source източник


Отговори (2)


Първо, няма ObjectMapper по подразбиране, използван от доставчика на Jackson. Всъщност изобщо не използва ObjectMapper. Той използва други API на Jackson за обработка на (де)сериализацията.

Ако искате да използвате/инжектирате единичен ObjectMapper екземпляр, тогава трябва просто да създадете Factory за него

public class ObjectMapperFactory implements Factory<ObjectMapper> {

    final ObjectMapper mapper = new ObjectMapper();

    @Override
    public ObjectMapper provide() {
        return mapper;
    }

    @Override
    public void dispose(ObjectMapper t) {}   
}

След това го завържете

register(new AbstractBinder(){
    @Override
    public void configure() {
        bindFactory(ObjectMapperFactory.class)
            .to(ObjectMapper.class).in(Singleton.class);
    }
});

Трябва да се отбележи, че всяка конфигурация на ObjectMapper не е безопасна за нишки. Така че кажете, че сте се опитали да го конфигурирате от вашия ресурсен метод, тези операции не са безопасни за нишки.

Друго нещо, което трябва да се отбележи с доставчика на Jackson, е, че ако предоставим ContextResolver, като споменато от @Laurentiu L, тогава Доставчикът на Jackson ще премине към използване на нашия ObjectMapper. В който случай, ако искате да използвате същия ObjectMapper, тогава можете да го потърсите в Factory. Например

public class ObjectMapperFactory implements Factory<ObjectMapper> {

    private final Providers providers;
    final ObjectMapper mapper = new ObjectMapper();

    public ObjectMapperFactory(@Context Providers providers) {
        this.providers = providers;
    }

    @Override
    public ObjectMapper provide() {
        ContextResolver<ObjectMapper> resolver = providers.getContextResolver(
                ObjectMapper.class, MediaType.APPLICATION_JSON);
        if (resolver == null) { return mapper; }

        return resolver.getContext(null);
    }

    @Override
    public void dispose(ObjectMapper t) {}   
}

За да работи горното (използвайте един ObjectMapper), трябва да се уверите, че сте внедрили ContextResolver<ObjectMapper> и да анотирате ContextResolver със съответните типове носители @Produces и @Consumes.

person Paul Samsotha    schedule 15.05.2015
comment
според документацията на jackson ObjectMapper инстанциите са безопасни за нишки, стига да не се извършва преконфигуриране. Екземплярите на Mapper са напълно безопасни за нишки, при условие че ЦЯЛАТА конфигурация на екземпляра се извършва преди ВСЯКАКВИ извиквания за четене или запис. fasterxml.github.io/jackson- databind/javadoc/2.6/com/fasterxml/ - person Ricard Nàcher Roig; 14.06.2019
comment
@RicardNàcherRoig Не казах ли това? Едно нещо, което трябва да се отбележи е, че всяка конфигурация на ObjectMapper не е нишково безопасна. Ако не е формулирано правилно, това имах предвид. Не трябва да се опитвате да преконфигурирате картографа по време на изпълнение; Същият картограф може да се използва за друга заявка. - person Paul Samsotha; 14.06.2019
comment
Благодаря на @paul-samsotha за вашия отговор. Според мен не е формулиран правилно или поне смятам, че обяснението от документацията на Jackson API е много по-ясно. Загубих известно време, мислейки, че ObjectMapper никога не е бил безопасен за нишки. - person Ricard Nàcher Roig; 14.06.2019

Освен JacksonFeature, трябва да регистрирате ContextResolver за ObjectMapper.

Прост пример от Документацията в 9.1.4.2. Конфигурирайте и се регистрирайте

@Provider
public class MyObjectMapperProvider implements ContextResolver<ObjectMapper> {

    final ObjectMapper defaultObjectMapper;

    public MyObjectMapperProvider() {
        defaultObjectMapper = createDefaultMapper();
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return defaultObjectMapper;
    }

    private static ObjectMapper createDefaultMapper() {
        final ObjectMapper result = new ObjectMapper();
        result.configure(Feature.INDENT_OUTPUT, true);

        return result;
    }

    // ...
}

Пълен примерен код наличен в Github

Ще трябва също да го регистрирате

        .register(MyObjectMapperProvider.class)  
person Laurentiu L.    schedule 15.05.2015
comment
Това работи, но тъй като нямам нужда (все още?) от предоставен персонализиран ObjectMapper, надявах се да има начин да използвам създадения от Джърси, вместо да предоставям моя собствен. - person agnul; 15.05.2015
comment
Ако някой има проблем: абстрактните типове или трябва да бъдат съпоставени към конкретни типове с Dropwizard, въпреки че сте регистрирали модул с addAbstractTypeMapping, това решение коригира проблема като чар (просто регистрирайте своя модул в createDefaultMapper и регистрирайте този Provider с environment.jersey().register() в run() от вашите Application)! - person qwertzguy; 19.04.2017