2015-05-15 1 views
7

У меня есть приложение jersey2, сконфигурированный для поддержки JSON через Джексон, добавивКак получить ссылку на Mapper объектов Джексона в приложении jersey2/hk2

<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) { 
    ... 
} 

Теперь один из thoese ресурсов необходима ссылка на Джексон ObjectMapper сделать некоторые десериализации самостоятельно. Я пытался сделать что-то вроде

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

или

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

, но в обоих случаях ссылка на mapper является нулевым. Как я могу ввести ссылку на ObjectMapper в свои ресурсы?

ответ

5

Сначала не по умолчанию ObjectMapper используетсяДжексон провайдер. Он вообще не использует ObjectMapper. Он использует другие API-интерфейсы Jackson для обработки сериализации (de).

Если вы хотите использовать/вводить один 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 составляет небезопасный поток. Поэтому скажите, что вы пытались настроить его из вашего метода ресурсов, эти операции не являются потокобезопасными.

Другая вещь, чтобы отметить с поставщиком Джексона, является то, что если мы обеспечиваем ContextResolver, как mentioned by @Laurentiu L, то поставщик Джексон переключится на использование нашего 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 типов носителей.

3

Помимо JacksonFeature вам необходимо зарегистрировать ContextResolver для ObjectMapper.

Простой пример от Documentation по адресу 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; 
    } 

    // ... 
} 

Полный пример кода available on Github

Вам также необходимо зарегистрировать его

 .register(MyObjectMapperProvider.class) 
+0

Это работает, но поскольку у меня нет необходимости (пока?) Пользовательского предоставленного 'ObjectMapper', я надеялся, что вы воспользуетесь созданным вами Джерси вместо того, чтобы предоставлять свои собственные. – agnul

+0

Если у кого-то «проблема: абстрактные типы либо должны быть сопоставлены конкретным типам» с Dropwizard, даже если вы зарегистрировали модуль с 'addAbstractTypeMapping', это решение устранило проблему как очарование (просто зарегистрируйте свой модуль в' createDefaultMapper' и зарегистрируйте этот «поставщик» с 'environment.jersey(). register()' в 'run()' вашего 'приложения')! – qwertzguy

Смежные вопросы