2013-05-26 4 views
11

Я, похоже, не смог правильно зарегистрировать модуль модуля Jackson ObjectMapper.Как подключить Jackson ObjectMapper с Guice/Jersey

Я использую стек Guice + Jersey + Jackson (FasterXML).

Я следил за тем, как настроить ObjectMapper на основе различных вопросов здесь. В частности, у меня есть объявленный ContextResolver, помеченный как @ javax.ws.rs.ext.Provider и @ javax.inject.Singleton.

У меня есть GuiceServletContextListener вдоль линий:

@Override 
protected Injector getInjector() { 

    Injector injector = Guice.createInjector(new DBModule(dataSource), 
      new ServletModule() 
      { 
       @Override 
       protected void configureServlets() { 


        // Mapper 
        bind(JacksonOMP.class).asEagerSingleton(); 

        // ... 

        Map<String, String> initParams = new HashMap<String, String>(); 
        initParams.put("com.sun.jersey.config.feature.Trace", 
          "true"); 
        initParams.put("com.sun.jersey.api.json.POJOMappingFeature", "true"); 

        serve("/services/*").with(
          GuiceContainer.class, 
          initParams); 
       } 
      }); 

    return injector; 
} 

Mapper определено

import javax.inject.Singleton; 
import javax.ws.rs.Produces; 
import javax.ws.rs.ext.ContextResolver; 
import javax.ws.rs.ext.Provider; 

@Provider 
@Singleton 
@Produces 
public class JacksonOMP implements ContextResolver<ObjectMapper> { 

    @Override 
    public ObjectMapper getContext(Class<?> aClass) { 
    final ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(new Hibernate4Module()); 
    return mapper; 
    } 
} 

Однако - с одной этой конфигурации, getContext() никогда не вызывается, поэтому картографа никогда не зарегистрирован. Я застрял в типичном узоре - аннотации-таинственности, где практически невозможно отслеживать то, что я на самом деле должен делать. Пользователи Spring просто сообщают о регистрации компонента, и контейнер просто подбирает его.

This ответ на вопрос о переопределении моего собственного javax.ws.rs.core.Application осуществления. Тем не менее, это выглядит зашитыми в Джерси-Guice impementation из GuiceContainer быть DefaultResourceConfig():

@Override 
protected ResourceConfig getDefaultResourceConfig(Map<String, Object> props, 
     WebConfig webConfig) throws ServletException { 
    return new DefaultResourceConfig(); 
} 

Я должен подкласс GuiceContainer здесь? Или есть какая-то другая волшебная аннотация, которую я пропускаю?

Это кажется довольно распространенным явлением - я удивлен тем, насколько сложно это сделать с этой комбинацией.

ответ

22

Я застрял в типичной Guice - аннотаций-загадка, где это практически безвестно к тому, что я на самом деле должен делать. Пользователи Spring просто сообщают о регистрации компонента, а контейнер просто подбирает его.

Вы действительно должны прочитать excellent Guice documentation. Guice очень прост в использовании, он имеет очень небольшое количество базовых понятий. Ваша проблема заключается в том, что вы смешали инъекцию зависимостей Джерси JAX-RS и инъекцию зависимости Guice. Если вы используете GuiceContainer, тогда вы заявляете, что будете использовать Guice для всех вашего DI, поэтому вам нужно добавить привязки с Guice, а не с JAX-RS.

Например, вам не нужно ContextResolver, вы должны использовать простой Guice Provider вместо:

import com.google.inject.Provider; 

public class ObjectMapperProvider implements Provider<ObjectMapper> { 
    @Override 
    public ObjectMapper get() { 
     final ObjectMapper mapper = new ObjectMapper(); 
     mapper.registerModule(new Hibernate4Module()); 
     return mapper; 
    } 
} 

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

bind(ObjectMapper.class).toProvider(ObjectMapperProvider.class).in(Singleton.class); 

Это будет связывать ObjectMapper, но недостаточно использовать Джерси с Джексоном. Вам понадобится какой-то MessageBodyReader/MessageBodyWriter, например. JacksonJsonProvider.Вы будете нуждаться в другой поставщик для него:

public class JacksonJsonProviderProvider implements Provider<JacksonJsonProvider> { 
    private final ObjectMapper mapper; 

    @Inject 
    JacksonJsonProviderProvider(ObjectMapper mapper) { 
     this.mapper = mapper; 
    } 

    @Override 
    public JacksonJsonProvider get() { 
     return new JacksonJsonProvider(mapper); 
    } 
} 

Затем связать его:

bind(JacksonJsonProvider.class).toProvider(JacksonJsonProviderProvider.class).in(Singleton.class); 

Это все, что вам нужно сделать - не подклассы не требуется.

Однако есть место для оптимизации размера кода. Если бы я тебя, я хотел бы использовать @Provides -методов:

@Provides @Singleton 
ObjectMapper objectMapper() { 
    final ObjectMapper mapper = new ObjectMapper(); 
    mapper.registerModule(new Hibernate4Module()); 
    return mapper; 
} 

@Provides @Singleton 
JacksonJsonProvider jacksonJsonProvider(ObjectMapper mapper) { 
    return new JacksonJsonProvider(mapper); 
} 

Эти методы должны быть добавлены к одной из ваших модулей, например анонимно ServletModule. Тогда вам не понадобятся отдельные классы провайдеров.
BTW, вы должны использовать JerseyServletModule вместо простого ServletModule, он предоставляет множество полезных привязок для вас.

+0

Это очень полезно. Моя особая проблема заключалась в том, что у меня были * 2 * jacksons (как версия кодекса, так и версия quickxml), поэтому objectmappers были полностью проигнорированы, потому что они были неправильного типа. – user340535

+0

У меня была такая же проблема с конфликтами зависимостей (codehaus + quickxml): 'JsonIgnore' вообще не работал. В моем случае jackson codehaus (jackson-mapper-asl или core-asl) был связан с зависимостью пакета azure documentdb и был полностью удален (путем исключения pom), чтобы сохранить только самую последнюю версию (quickxml). Спасибо @ user340535 за ваш комментарий, который поможет мне исправить крюк JacksonJsonProvider! – boly38

+0

По какой-то причине версия с аннотациями не работает со мной в Guice 4 с использованием JerseyGuiceServletContextListener. Что может вызвать это? С нормальным связыванием и дополнительными классами он не работает без проблем. – Atais

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